Mercurial > pidgin
annotate libgaim/server.c @ 14484:1f81919515ae
[gaim-migrate @ 17203]
Part of SF Patch #1554627 from Richard Nelson (wabz)
"The msn protocol currently calls serv_got_alias on all
buddy status changes (as they are NLN commands),
resulting in lots of unnecessary blist.xml write schedules.
serv_got_alias already checks if the alias has actually
changed before printing to the conv. The first hunk in
this patch checks it a bit earlier."
The second hunk checks in the MSN prpl, which also avoids
an extra call to msn_user_set_friendly_name().
committer: Tailor Script <tailor@pidgin.im>
author | Richard Laager <rlaager@wiktel.com> |
---|---|
date | Sat, 09 Sep 2006 20:27:48 +0000 |
parents | 60b1bc8dbf37 |
children | aee74d84816c |
rev | line source |
---|---|
14192 | 1 /* |
2 * gaim | |
3 * | |
4 * Gaim is the legal property of its developers, whose names are too numerous | |
5 * to list here. Please refer to the COPYRIGHT file distributed with this | |
6 * source distribution. | |
7 * | |
8 * This program is free software; you can redistribute it and/or modify | |
9 * it under the terms of the GNU General Public License as published by | |
10 * the Free Software Foundation; either version 2 of the License, or | |
11 * (at your option) any later version. | |
12 * | |
13 * This program is distributed in the hope that it will be useful, | |
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 * GNU General Public License for more details. | |
17 * | |
18 * You should have received a copy of the GNU General Public License | |
19 * along with this program; if not, write to the Free Software | |
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 * | |
22 */ | |
23 #include "internal.h" | |
24 #include "blist.h" | |
25 #include "conversation.h" | |
26 #include "debug.h" | |
27 #include "log.h" | |
28 #include "notify.h" | |
29 #include "prefs.h" | |
30 #include "privacy.h" | |
31 #include "prpl.h" | |
32 #include "request.h" | |
33 #include "signals.h" | |
34 #include "server.h" | |
35 #include "status.h" | |
36 #include "util.h" | |
37 | |
38 #define SECS_BEFORE_RESENDING_AUTORESPONSE 600 | |
39 #define SEX_BEFORE_RESENDING_AUTORESPONSE "Only after you're married" | |
40 | |
41 unsigned int | |
42 serv_send_typing(GaimConnection *gc, const char *name, GaimTypingState state) | |
43 { | |
44 GaimPluginProtocolInfo *prpl_info = NULL; | |
45 | |
46 if (gc != NULL && gc->prpl != NULL) | |
47 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); | |
48 | |
49 if (prpl_info && prpl_info->send_typing) | |
50 return prpl_info->send_typing(gc, name, state); | |
51 | |
52 return 0; | |
53 } | |
54 | |
55 static GSList *last_auto_responses = NULL; | |
56 struct last_auto_response { | |
57 GaimConnection *gc; | |
58 char name[80]; | |
59 time_t sent; | |
60 }; | |
61 | |
62 static gboolean | |
63 expire_last_auto_responses(gpointer data) | |
64 { | |
65 GSList *tmp, *cur; | |
66 struct last_auto_response *lar; | |
67 | |
68 tmp = last_auto_responses; | |
69 | |
70 while (tmp) { | |
71 cur = tmp; | |
72 tmp = tmp->next; | |
73 lar = (struct last_auto_response *)cur->data; | |
74 | |
75 if ((time(NULL) - lar->sent) > SECS_BEFORE_RESENDING_AUTORESPONSE) { | |
76 last_auto_responses = g_slist_remove(last_auto_responses, lar); | |
77 g_free(lar); | |
78 } | |
79 } | |
80 | |
81 return FALSE; /* do not run again */ | |
82 } | |
83 | |
84 static struct last_auto_response * | |
85 get_last_auto_response(GaimConnection *gc, const char *name) | |
86 { | |
87 GSList *tmp; | |
88 struct last_auto_response *lar; | |
89 | |
90 /* because we're modifying or creating a lar, schedule the | |
91 * function to expire them as the pref dictates */ | |
92 gaim_timeout_add((SECS_BEFORE_RESENDING_AUTORESPONSE + 1) * 1000, expire_last_auto_responses, NULL); | |
93 | |
94 tmp = last_auto_responses; | |
95 | |
96 while (tmp) { | |
97 lar = (struct last_auto_response *)tmp->data; | |
98 | |
99 if (gc == lar->gc && !strncmp(name, lar->name, sizeof(lar->name))) | |
100 return lar; | |
101 | |
102 tmp = tmp->next; | |
103 } | |
104 | |
105 lar = (struct last_auto_response *)g_new0(struct last_auto_response, 1); | |
106 g_snprintf(lar->name, sizeof(lar->name), "%s", name); | |
107 lar->gc = gc; | |
108 lar->sent = 0; | |
109 last_auto_responses = g_slist_prepend(last_auto_responses, lar); | |
110 | |
111 return lar; | |
112 } | |
113 | |
114 int serv_send_im(GaimConnection *gc, const char *name, const char *message, | |
115 GaimMessageFlags flags) | |
116 { | |
117 GaimConversation *conv; | |
118 GaimAccount *account; | |
119 GaimPresence *presence; | |
120 GaimPluginProtocolInfo *prpl_info; | |
121 int val = -EINVAL; | |
122 const gchar *auto_reply_pref; | |
123 | |
124 g_return_val_if_fail(gc != NULL, val); | |
125 g_return_val_if_fail(gc->prpl != NULL, val); | |
126 | |
127 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); | |
128 | |
129 account = gaim_connection_get_account(gc); | |
130 presence = gaim_account_get_presence(account); | |
131 | |
132 conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, name, gc->account); | |
133 | |
134 if (prpl_info && prpl_info->send_im) | |
135 val = prpl_info->send_im(gc, name, message, flags); | |
136 | |
137 /* | |
138 * XXX - If "only auto-reply when away & idle" is set, then shouldn't | |
139 * this only reset lar->sent if we're away AND idle? | |
140 */ | |
141 auto_reply_pref = gaim_prefs_get_string("/core/away/auto_reply"); | |
142 if ((gc->flags & GAIM_CONNECTION_AUTO_RESP) && | |
143 !gaim_presence_is_available(presence) && | |
144 strcmp(auto_reply_pref, "never")) { | |
145 | |
146 struct last_auto_response *lar; | |
147 lar = get_last_auto_response(gc, name); | |
148 lar->sent = time(NULL); | |
149 } | |
150 | |
151 if (conv && gaim_conv_im_get_send_typed_timeout(GAIM_CONV_IM(conv))) | |
152 gaim_conv_im_stop_send_typed_timeout(GAIM_CONV_IM(conv)); | |
153 | |
154 return val; | |
155 } | |
156 | |
157 void serv_get_info(GaimConnection *gc, const char *name) | |
158 { | |
159 GaimPluginProtocolInfo *prpl_info = NULL; | |
160 | |
161 if (gc != NULL && gc->prpl != NULL) | |
162 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); | |
163 | |
164 if (gc && prpl_info && prpl_info->get_info) | |
165 prpl_info->get_info(gc, name); | |
166 } | |
167 | |
168 void serv_set_info(GaimConnection *gc, const char *info) | |
169 { | |
170 GaimPluginProtocolInfo *prpl_info = NULL; | |
171 GaimAccount *account; | |
172 | |
173 if (gc != NULL && gc->prpl != NULL) | |
174 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); | |
175 | |
176 if (prpl_info && g_list_find(gaim_connections_get_all(), gc) && | |
177 prpl_info->set_info) { | |
178 | |
179 account = gaim_connection_get_account(gc); | |
180 | |
181 if (gaim_signal_emit_return_1(gaim_accounts_get_handle(), | |
182 "account-setting-info", account, info)) | |
183 return; | |
184 | |
185 prpl_info->set_info(gc, info); | |
186 | |
187 gaim_signal_emit(gaim_accounts_get_handle(), | |
188 "account-set-info", account, info); | |
189 } | |
190 } | |
191 | |
192 /* | |
193 * Set buddy's alias on server roster/list | |
194 */ | |
195 void serv_alias_buddy(GaimBuddy *b) | |
196 { | |
197 GaimPluginProtocolInfo *prpl_info = NULL; | |
198 | |
199 if (b != NULL && b->account->gc->prpl != NULL) | |
200 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(b->account->gc->prpl); | |
201 | |
202 if (b && prpl_info && prpl_info->alias_buddy) { | |
203 prpl_info->alias_buddy(b->account->gc, b->name, b->alias); | |
204 } | |
205 } | |
206 | |
207 void | |
208 serv_got_alias(GaimConnection *gc, const char *who, const char *alias) | |
209 { | |
210 GaimAccount *account = gaim_connection_get_account(gc); | |
211 GSList *buds, *buddies = gaim_find_buddies(account, who); | |
212 GaimBuddy *b; | |
213 GaimConversation *conv; | |
214 | |
215 for (buds = buddies; buds; buds = buds->next) | |
216 { | |
217 b = buds->data; | |
14484
1f81919515ae
[gaim-migrate @ 17203]
Richard Laager <rlaager@wiktel.com>
parents:
14192
diff
changeset
|
218 if (b->server_alias && !strcmp(b->server_alias, alias)) |
1f81919515ae
[gaim-migrate @ 17203]
Richard Laager <rlaager@wiktel.com>
parents:
14192
diff
changeset
|
219 continue; |
14192 | 220 gaim_blist_server_alias_buddy(b, alias); |
221 | |
222 conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, b->name, account); | |
223 | |
14484
1f81919515ae
[gaim-migrate @ 17203]
Richard Laager <rlaager@wiktel.com>
parents:
14192
diff
changeset
|
224 if (conv != NULL) |
14192 | 225 { |
226 char *tmp = g_strdup_printf(_("%s is now known as %s.\n"), | |
227 who, alias); | |
228 | |
229 gaim_conversation_write(conv, NULL, tmp, GAIM_MESSAGE_SYSTEM, | |
230 time(NULL)); | |
231 | |
232 g_free(tmp); | |
233 } | |
234 } | |
235 g_slist_free(buddies); | |
236 } | |
237 | |
238 /* | |
239 * Move a buddy from one group to another on server. | |
240 * | |
241 * Note: For now we'll not deal with changing gc's at the same time, but | |
242 * it should be possible. Probably needs to be done, someday. Although, | |
243 * the UI for that would be difficult, because groups are Gaim-wide. | |
244 */ | |
245 void serv_move_buddy(GaimBuddy *b, GaimGroup *og, GaimGroup *ng) | |
246 { | |
247 GaimPluginProtocolInfo *prpl_info = NULL; | |
248 | |
249 g_return_if_fail(b != NULL); | |
250 g_return_if_fail(og != NULL); | |
251 g_return_if_fail(ng != NULL); | |
252 | |
253 if (b->account->gc != NULL && b->account->gc->prpl != NULL) | |
254 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(b->account->gc->prpl); | |
255 | |
256 if (b->account->gc && og && ng) { | |
257 if (prpl_info && prpl_info->group_buddy) { | |
258 prpl_info->group_buddy(b->account->gc, b->name, og->name, ng->name); | |
259 } | |
260 } | |
261 } | |
262 | |
263 void serv_add_permit(GaimConnection *g, const char *name) | |
264 { | |
265 GaimPluginProtocolInfo *prpl_info = NULL; | |
266 | |
267 if (g != NULL && g->prpl != NULL) | |
268 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); | |
269 | |
270 if (prpl_info && g_list_find(gaim_connections_get_all(), g) && prpl_info->add_permit) | |
271 prpl_info->add_permit(g, name); | |
272 } | |
273 | |
274 void serv_add_deny(GaimConnection *g, const char *name) | |
275 { | |
276 GaimPluginProtocolInfo *prpl_info = NULL; | |
277 | |
278 if (g != NULL && g->prpl != NULL) | |
279 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); | |
280 | |
281 if (prpl_info && g_list_find(gaim_connections_get_all(), g) && prpl_info->add_deny) | |
282 prpl_info->add_deny(g, name); | |
283 } | |
284 | |
285 void serv_rem_permit(GaimConnection *g, const char *name) | |
286 { | |
287 GaimPluginProtocolInfo *prpl_info = NULL; | |
288 | |
289 if (g != NULL && g->prpl != NULL) | |
290 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); | |
291 | |
292 if (prpl_info && g_list_find(gaim_connections_get_all(), g) && prpl_info->rem_permit) | |
293 prpl_info->rem_permit(g, name); | |
294 } | |
295 | |
296 void serv_rem_deny(GaimConnection *g, const char *name) | |
297 { | |
298 GaimPluginProtocolInfo *prpl_info = NULL; | |
299 | |
300 if (g != NULL && g->prpl != NULL) | |
301 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); | |
302 | |
303 if (prpl_info && g_list_find(gaim_connections_get_all(), g) && prpl_info->rem_deny) | |
304 prpl_info->rem_deny(g, name); | |
305 } | |
306 | |
307 void serv_set_permit_deny(GaimConnection *g) | |
308 { | |
309 GaimPluginProtocolInfo *prpl_info = NULL; | |
310 | |
311 if (g != NULL && g->prpl != NULL) | |
312 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); | |
313 | |
314 /* | |
315 * this is called when either you import a buddy list, and make lots | |
316 * of changes that way, or when the user toggles the permit/deny mode | |
317 * in the prefs. In either case you should probably be resetting and | |
318 * resending the permit/deny info when you get this. | |
319 */ | |
320 if (prpl_info && g_list_find(gaim_connections_get_all(), g) && prpl_info->set_permit_deny) | |
321 prpl_info->set_permit_deny(g); | |
322 } | |
323 | |
324 void serv_join_chat(GaimConnection *g, GHashTable *data) | |
325 { | |
326 GaimPluginProtocolInfo *prpl_info = NULL; | |
327 | |
328 if (g != NULL && g->prpl != NULL) | |
329 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); | |
330 | |
331 if (prpl_info && g_list_find(gaim_connections_get_all(), g) && prpl_info->join_chat) | |
332 prpl_info->join_chat(g, data); | |
333 } | |
334 | |
335 | |
336 void serv_reject_chat(GaimConnection *g, GHashTable *data) | |
337 { | |
338 GaimPluginProtocolInfo *prpl_info = NULL; | |
339 | |
340 if (g != NULL && g->prpl != NULL) | |
341 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); | |
342 | |
343 if (prpl_info && g_list_find(gaim_connections_get_all(), g) && prpl_info->reject_chat) | |
344 prpl_info->reject_chat(g, data); | |
345 } | |
346 | |
347 void serv_chat_invite(GaimConnection *g, int id, const char *message, const char *name) | |
348 { | |
349 GaimPluginProtocolInfo *prpl_info = NULL; | |
350 GaimConversation *conv; | |
351 char *buffy = message && *message ? g_strdup(message) : NULL; | |
352 | |
353 conv = gaim_find_chat(g, id); | |
354 | |
355 if (conv == NULL) | |
356 return; | |
357 | |
358 if (g != NULL && g->prpl != NULL) | |
359 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); | |
360 | |
361 gaim_signal_emit(gaim_conversations_get_handle(), "chat-inviting-user", | |
362 conv, name, &buffy); | |
363 | |
364 if (prpl_info && g_list_find(gaim_connections_get_all(), g) && prpl_info->chat_invite) | |
365 prpl_info->chat_invite(g, id, buffy, name); | |
366 | |
367 gaim_signal_emit(gaim_conversations_get_handle(), "chat-invited-user", | |
368 conv, name, buffy); | |
369 | |
370 g_free(buffy); | |
371 } | |
372 | |
373 /* Ya know, nothing uses this except gaim_conversation_destroy(), | |
374 * I think I'll just merge it into that later... | |
375 * Then again, something might want to use this, from outside prpl-land | |
376 * to leave a chat without destroying the conversation. | |
377 */ | |
378 | |
379 void serv_chat_leave(GaimConnection *g, int id) | |
380 { | |
381 GaimPluginProtocolInfo *prpl_info = NULL; | |
382 | |
383 if (!g_list_find(gaim_connections_get_all(), g)) | |
384 return; | |
385 | |
386 if (g->prpl != NULL) | |
387 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); | |
388 | |
389 if (prpl_info && prpl_info->chat_leave) | |
390 prpl_info->chat_leave(g, id); | |
391 } | |
392 | |
393 void serv_chat_whisper(GaimConnection *g, int id, const char *who, const char *message) | |
394 { | |
395 GaimPluginProtocolInfo *prpl_info = NULL; | |
396 | |
397 if (g != NULL && g->prpl != NULL) | |
398 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); | |
399 | |
400 if (prpl_info && prpl_info->chat_whisper) | |
401 prpl_info->chat_whisper(g, id, who, message); | |
402 } | |
403 | |
404 int serv_chat_send(GaimConnection *gc, int id, const char *message, GaimMessageFlags flags) | |
405 { | |
406 int val = -EINVAL; | |
407 GaimPluginProtocolInfo *prpl_info = NULL; | |
408 | |
409 if (gc->prpl != NULL) | |
410 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); | |
411 | |
412 if (prpl_info && prpl_info->chat_send) | |
413 val = prpl_info->chat_send(gc, id, message, flags); | |
414 | |
415 return val; | |
416 } | |
417 | |
418 void serv_set_buddyicon(GaimConnection *gc, const char *filename) | |
419 { | |
420 GaimPluginProtocolInfo *prpl_info = NULL; | |
421 | |
422 if (gc->prpl != NULL) | |
423 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); | |
424 | |
425 if (prpl_info && prpl_info->set_buddy_icon) | |
426 prpl_info->set_buddy_icon(gc, filename); | |
427 | |
428 } | |
429 | |
430 /* | |
431 * woo. i'm actually going to comment this function. isn't that fun. make | |
432 * sure to follow along, kids | |
433 */ | |
434 void serv_got_im(GaimConnection *gc, const char *who, const char *msg, | |
435 GaimMessageFlags flags, time_t mtime) | |
436 { | |
437 GaimAccount *account; | |
438 GaimConversation *cnv; | |
439 char *message, *name; | |
440 char *angel, *buffy; | |
441 int plugin_return; | |
442 | |
443 g_return_if_fail(msg != NULL); | |
444 | |
445 account = gaim_connection_get_account(gc); | |
446 | |
447 if (GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl)->set_permit_deny == NULL) { | |
448 /* protocol does not support privacy, handle it ourselves */ | |
449 if (!gaim_privacy_check(account, who)) | |
450 return; | |
451 } | |
452 | |
453 /* | |
454 * We should update the conversation window buttons and menu, | |
455 * if it exists. | |
456 */ | |
457 cnv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, who, gc->account); | |
458 | |
459 /* | |
460 * Plugin stuff. we pass a char ** but we don't want to pass what's | |
461 * been given us by the prpls. So we create temp holders and pass | |
462 * those instead. It's basically just to avoid segfaults. | |
463 */ | |
464 buffy = g_malloc(MAX(strlen(msg) + 1, BUF_LONG)); | |
465 strcpy(buffy, msg); | |
466 angel = g_strdup(who); | |
467 | |
468 plugin_return = GPOINTER_TO_INT( | |
469 gaim_signal_emit_return_1(gaim_conversations_get_handle(), | |
470 "receiving-im-msg", gc->account, | |
471 &angel, &buffy, cnv, &flags)); | |
472 | |
473 if (!buffy || !angel || plugin_return) { | |
474 g_free(buffy); | |
475 g_free(angel); | |
476 return; | |
477 } | |
478 | |
479 name = angel; | |
480 message = buffy; | |
481 | |
482 gaim_signal_emit(gaim_conversations_get_handle(), "received-im-msg", gc->account, | |
483 name, message, cnv, flags); | |
484 | |
485 /* search for conversation again in case it was created by received-im-msg handler */ | |
486 if (cnv == NULL) | |
487 cnv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, name, gc->account); | |
488 | |
489 /* Make sure URLs are clickable */ | |
490 buffy = gaim_markup_linkify(message); | |
491 g_free(message); | |
492 message = buffy; | |
493 | |
494 /* | |
495 * XXX: Should we be setting this here, or relying on prpls to set it? | |
496 */ | |
497 flags |= GAIM_MESSAGE_RECV; | |
498 | |
499 if (cnv == NULL) | |
500 cnv = gaim_conversation_new(GAIM_CONV_TYPE_IM, account, name); | |
501 | |
502 gaim_conv_im_write(GAIM_CONV_IM(cnv), NULL, message, flags, mtime); | |
503 g_free(message); | |
504 | |
505 /* | |
506 * Don't autorespond if: | |
507 * | |
508 * - it's not supported on this connection | |
509 * - we are available | |
510 * - or it's disabled | |
511 * - or we're not idle and the 'only auto respond if idle' pref | |
512 * is set | |
513 */ | |
514 if (gc->flags & GAIM_CONNECTION_AUTO_RESP) | |
515 { | |
516 GaimPresence *presence; | |
517 GaimStatus *status; | |
518 GaimStatusType *status_type; | |
519 GaimStatusPrimitive primitive; | |
520 const gchar *auto_reply_pref; | |
521 const char *away_msg = NULL; | |
522 | |
523 auto_reply_pref = gaim_prefs_get_string("/core/away/auto_reply"); | |
524 | |
525 presence = gaim_account_get_presence(account); | |
526 status = gaim_presence_get_active_status(presence); | |
527 status_type = gaim_status_get_type(status); | |
528 primitive = gaim_status_type_get_primitive(status_type); | |
529 if ((primitive == GAIM_STATUS_AVAILABLE) || | |
530 (primitive == GAIM_STATUS_INVISIBLE) || | |
531 (primitive == GAIM_STATUS_MOBILE) || | |
532 !strcmp(auto_reply_pref, "never") || | |
533 (!gaim_presence_is_idle(presence) && !strcmp(auto_reply_pref, "awayidle"))) | |
534 { | |
535 g_free(name); | |
536 return; | |
537 } | |
538 | |
539 away_msg = gaim_value_get_string( | |
540 gaim_status_get_attr_value(status, "message")); | |
541 | |
542 if ((away_msg != NULL) && (*away_msg != '\0')) { | |
543 struct last_auto_response *lar; | |
544 time_t now = time(NULL); | |
545 | |
546 /* | |
547 * This used to be based on the conversation window. But um, if | |
548 * you went away, and someone sent you a message and got your | |
549 * auto-response, and then you closed the window, and then they | |
550 * sent you another one, they'd get the auto-response back too | |
551 * soon. Besides that, we need to keep track of this even if we've | |
552 * got a queue. So the rest of this block is just the auto-response, | |
553 * if necessary. | |
554 */ | |
555 lar = get_last_auto_response(gc, name); | |
556 if ((now - lar->sent) >= SECS_BEFORE_RESENDING_AUTORESPONSE) | |
557 { | |
558 /* | |
559 * We don't want to send an autoresponse in response to the other user's | |
560 * autoresponse. We do, however, not want to then send one in response to the | |
561 * _next_ message, so we still set lar->sent to now. | |
562 */ | |
563 lar->sent = now; | |
564 | |
565 if (!(flags & GAIM_MESSAGE_AUTO_RESP)) | |
566 { | |
567 serv_send_im(gc, name, away_msg, GAIM_MESSAGE_AUTO_RESP); | |
568 | |
569 gaim_conv_im_write(GAIM_CONV_IM(cnv), NULL, away_msg, | |
570 GAIM_MESSAGE_SEND | GAIM_MESSAGE_AUTO_RESP, | |
571 mtime); | |
572 } | |
573 } | |
574 } | |
575 } | |
576 | |
577 g_free(name); | |
578 } | |
579 | |
580 void serv_got_typing(GaimConnection *gc, const char *name, int timeout, | |
581 GaimTypingState state) { | |
582 GaimConversation *conv; | |
583 GaimConvIm *im = NULL; | |
584 | |
585 conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, name, gc->account); | |
586 if (conv != NULL) { | |
587 im = GAIM_CONV_IM(conv); | |
588 | |
589 gaim_conv_im_set_typing_state(im, state); | |
590 gaim_conv_im_update_typing(im); | |
591 } else { | |
592 if (state == GAIM_TYPING) | |
593 { | |
594 gaim_signal_emit(gaim_conversations_get_handle(), | |
595 "buddy-typing", gc->account, name); | |
596 } | |
597 else | |
598 { | |
599 gaim_signal_emit(gaim_conversations_get_handle(), | |
600 "buddy-typed", gc->account, name); | |
601 } | |
602 } | |
603 | |
604 if (conv != NULL && timeout > 0) | |
605 gaim_conv_im_start_typing_timeout(im, timeout); | |
606 } | |
607 | |
608 void serv_got_typing_stopped(GaimConnection *gc, const char *name) { | |
609 | |
610 GaimConversation *conv; | |
611 GaimConvIm *im; | |
612 | |
613 conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, name, gc->account); | |
614 if (conv != NULL) | |
615 { | |
616 im = GAIM_CONV_IM(conv); | |
617 | |
618 if (im->typing_state == GAIM_NOT_TYPING) | |
619 return; | |
620 | |
621 gaim_conv_im_stop_typing_timeout(im); | |
622 gaim_conv_im_set_typing_state(im, GAIM_NOT_TYPING); | |
623 gaim_conv_im_update_typing(im); | |
624 } | |
625 else | |
626 { | |
627 gaim_signal_emit(gaim_conversations_get_handle(), | |
628 "buddy-typing-stopped", gc->account, name); | |
629 } | |
630 } | |
631 | |
632 struct chat_invite_data { | |
633 GaimConnection *gc; | |
634 GHashTable *components; | |
635 }; | |
636 | |
637 static void chat_invite_data_free(struct chat_invite_data *cid) | |
638 { | |
639 if (cid->components) | |
640 g_hash_table_destroy(cid->components); | |
641 g_free(cid); | |
642 } | |
643 | |
644 | |
645 static void chat_invite_reject(struct chat_invite_data *cid) | |
646 { | |
647 serv_reject_chat(cid->gc, cid->components); | |
648 chat_invite_data_free(cid); | |
649 } | |
650 | |
651 | |
652 static void chat_invite_accept(struct chat_invite_data *cid) | |
653 { | |
654 serv_join_chat(cid->gc, cid->components); | |
655 chat_invite_data_free(cid); | |
656 } | |
657 | |
658 | |
659 | |
660 void serv_got_chat_invite(GaimConnection *gc, const char *name, | |
661 const char *who, const char *message, GHashTable *data) | |
662 { | |
663 GaimAccount *account; | |
664 char buf2[BUF_LONG]; | |
665 struct chat_invite_data *cid = g_new0(struct chat_invite_data, 1); | |
666 int plugin_return; | |
667 | |
668 account = gaim_connection_get_account(gc); | |
669 if (GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl)->set_permit_deny == NULL) { | |
670 /* protocol does not support privacy, handle it ourselves */ | |
671 if (!gaim_privacy_check(account, who)) | |
672 return; | |
673 } | |
674 | |
675 plugin_return = GPOINTER_TO_INT(gaim_signal_emit_return_1( | |
676 gaim_conversations_get_handle(), | |
677 "chat-invited", account, who, name, message, data)); | |
678 | |
679 cid->gc = gc; | |
680 cid->components = data; | |
681 | |
682 if (plugin_return == 0) | |
683 { | |
684 if (message != NULL) | |
685 { | |
686 g_snprintf(buf2, sizeof(buf2), | |
687 _("%s has invited %s to the chat room %s:\n%s"), | |
688 who, gaim_account_get_username(account), name, message); | |
689 } | |
690 else | |
691 g_snprintf(buf2, sizeof(buf2), | |
692 _("%s has invited %s to the chat room %s\n"), | |
693 who, gaim_account_get_username(account), name); | |
694 | |
695 | |
696 gaim_request_accept_cancel(gc, NULL, _("Accept chat invitation?"), buf2, | |
697 GAIM_DEFAULT_ACTION_NONE, cid, | |
698 G_CALLBACK(chat_invite_accept), | |
699 G_CALLBACK(chat_invite_reject)); | |
700 } | |
701 else if (plugin_return > 0) | |
702 chat_invite_accept(cid); | |
703 else | |
704 chat_invite_reject(cid); | |
705 } | |
706 | |
707 GaimConversation *serv_got_joined_chat(GaimConnection *gc, | |
708 int id, const char *name) | |
709 { | |
710 GaimConversation *conv; | |
711 GaimConvChat *chat; | |
712 GaimAccount *account; | |
713 | |
714 account = gaim_connection_get_account(gc); | |
715 | |
716 conv = gaim_conversation_new(GAIM_CONV_TYPE_CHAT, account, name); | |
717 chat = GAIM_CONV_CHAT(conv); | |
718 | |
719 if (!g_slist_find(gc->buddy_chats, conv)) | |
720 gc->buddy_chats = g_slist_append(gc->buddy_chats, conv); | |
721 | |
722 gaim_conv_chat_set_id(chat, id); | |
723 | |
724 gaim_signal_emit(gaim_conversations_get_handle(), "chat-joined", conv); | |
725 | |
726 return conv; | |
727 } | |
728 | |
729 void serv_got_chat_left(GaimConnection *g, int id) | |
730 { | |
731 GSList *bcs; | |
732 GaimConversation *conv = NULL; | |
733 GaimConvChat *chat = NULL; | |
734 | |
735 for (bcs = g->buddy_chats; bcs != NULL; bcs = bcs->next) { | |
736 conv = (GaimConversation *)bcs->data; | |
737 | |
738 chat = GAIM_CONV_CHAT(conv); | |
739 | |
740 if (gaim_conv_chat_get_id(chat) == id) | |
741 break; | |
742 | |
743 conv = NULL; | |
744 } | |
745 | |
746 if (!conv) | |
747 return; | |
748 | |
749 gaim_debug(GAIM_DEBUG_INFO, "server", "Leaving room: %s\n", | |
750 gaim_conversation_get_name(conv)); | |
751 | |
752 g->buddy_chats = g_slist_remove(g->buddy_chats, conv); | |
753 | |
754 gaim_conv_chat_left(GAIM_CONV_CHAT(conv)); | |
755 | |
756 gaim_signal_emit(gaim_conversations_get_handle(), "chat-left", conv); | |
757 } | |
758 | |
759 void serv_got_chat_in(GaimConnection *g, int id, const char *who, | |
760 GaimMessageFlags flags, const char *message, time_t mtime) | |
761 { | |
762 GSList *bcs; | |
763 GaimConversation *conv = NULL; | |
764 GaimConvChat *chat = NULL; | |
765 char *buf; | |
766 char *buffy, *angel; | |
767 int plugin_return; | |
768 | |
769 g_return_if_fail(who != NULL); | |
770 g_return_if_fail(message != NULL); | |
771 | |
772 for (bcs = g->buddy_chats; bcs != NULL; bcs = bcs->next) { | |
773 conv = (GaimConversation *)bcs->data; | |
774 | |
775 chat = GAIM_CONV_CHAT(conv); | |
776 | |
777 if (gaim_conv_chat_get_id(chat) == id) | |
778 break; | |
779 | |
780 conv = NULL; | |
781 } | |
782 | |
783 if (!conv) | |
784 return; | |
785 | |
786 /* | |
787 * Plugin stuff. We pass a char ** but we don't want to pass what's | |
788 * been given us by the prpls. so we create temp holders and pass those | |
789 * instead. It's basically just to avoid segfaults. Of course, if the | |
790 * data is binary, plugins don't see it. Bitch all you want; i really | |
791 * don't want you to be dealing with it. | |
792 */ | |
793 | |
794 buffy = g_malloc(MAX(strlen(message) + 1, BUF_LONG)); | |
795 strcpy(buffy, message); | |
796 angel = g_strdup(who); | |
797 | |
798 plugin_return = GPOINTER_TO_INT( | |
799 gaim_signal_emit_return_1(gaim_conversations_get_handle(), | |
800 "receiving-chat-msg", g->account, | |
801 &angel, &buffy, conv, &flags)); | |
802 | |
803 if (!buffy || !angel || plugin_return) { | |
804 g_free(buffy); | |
805 g_free(angel); | |
806 return; | |
807 } | |
808 who = angel; | |
809 message = buffy; | |
810 | |
811 gaim_signal_emit(gaim_conversations_get_handle(), "received-chat-msg", g->account, | |
812 who, message, conv, flags); | |
813 | |
814 /* Make sure URLs are clickable */ | |
815 buf = gaim_markup_linkify(message); | |
816 | |
817 gaim_conv_chat_write(chat, who, buf, flags, mtime); | |
818 | |
819 g_free(angel); | |
820 g_free(buf); | |
821 g_free(buffy); | |
822 } | |
823 | |
824 void serv_send_file(GaimConnection *gc, const char *who, const char *file) | |
825 { | |
826 GaimPluginProtocolInfo *prpl_info = NULL; | |
827 | |
828 if (gc != NULL && gc->prpl != NULL) | |
829 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); | |
830 | |
831 if (prpl_info && prpl_info->send_file) { | |
832 if (!prpl_info->can_receive_file || prpl_info->can_receive_file(gc, who)) { | |
833 prpl_info->send_file(gc, who, file); | |
834 } | |
835 } | |
836 } |