Mercurial > pidgin
annotate libgaim/server.c @ 14637:c811cfc944d1
[gaim-migrate @ 17383]
Fixed two issues which stem from changes when the Yahoo protocol upgrades were done; I'm fairly sure this properly fixes issue worked-around in [17080].
Yahoo buddies on the Ignore list were being added to the last group sent from the server. On Yahoo, an Ignored contact can never be on your contact list. These contacts should be noted locally as on the Deny list and, accordingly, not added to the contact list.
I added some comments about the keys and their order sent here based on my observations; they seem to generalize across a couple test cases I ran. See the comments themselves for details.
This fixes Adium Trac ticket #5470.
committer: Tailor Script <tailor@pidgin.im>
author | Evan Schoenberg <evan.s@dreskin.net> |
---|---|
date | Wed, 27 Sep 2006 04:44:30 +0000 |
parents | f23506e8f812 |
children | 0a9c44ce9a4a |
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 | |
14607 | 176 if (prpl_info && prpl_info->set_info) { |
14192 | 177 |
178 account = gaim_connection_get_account(gc); | |
179 | |
180 if (gaim_signal_emit_return_1(gaim_accounts_get_handle(), | |
181 "account-setting-info", account, info)) | |
182 return; | |
183 | |
184 prpl_info->set_info(gc, info); | |
185 | |
186 gaim_signal_emit(gaim_accounts_get_handle(), | |
187 "account-set-info", account, info); | |
188 } | |
189 } | |
190 | |
191 /* | |
192 * Set buddy's alias on server roster/list | |
193 */ | |
194 void serv_alias_buddy(GaimBuddy *b) | |
195 { | |
196 GaimPluginProtocolInfo *prpl_info = NULL; | |
197 | |
198 if (b != NULL && b->account->gc->prpl != NULL) | |
199 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(b->account->gc->prpl); | |
200 | |
201 if (b && prpl_info && prpl_info->alias_buddy) { | |
202 prpl_info->alias_buddy(b->account->gc, b->name, b->alias); | |
203 } | |
204 } | |
205 | |
206 void | |
207 serv_got_alias(GaimConnection *gc, const char *who, const char *alias) | |
208 { | |
209 GaimAccount *account = gaim_connection_get_account(gc); | |
210 GSList *buds, *buddies = gaim_find_buddies(account, who); | |
211 GaimBuddy *b; | |
212 GaimConversation *conv; | |
213 | |
214 for (buds = buddies; buds; buds = buds->next) | |
215 { | |
216 b = buds->data; | |
14496
aee74d84816c
[gaim-migrate @ 17215]
Richard Laager <rlaager@wiktel.com>
parents:
14484
diff
changeset
|
217 if ((b->server_alias == NULL && alias == NULL) || |
aee74d84816c
[gaim-migrate @ 17215]
Richard Laager <rlaager@wiktel.com>
parents:
14484
diff
changeset
|
218 (b->server_alias && alias && !strcmp(b->server_alias, alias))) |
aee74d84816c
[gaim-migrate @ 17215]
Richard Laager <rlaager@wiktel.com>
parents:
14484
diff
changeset
|
219 { |
14484
1f81919515ae
[gaim-migrate @ 17203]
Richard Laager <rlaager@wiktel.com>
parents:
14192
diff
changeset
|
220 continue; |
14496
aee74d84816c
[gaim-migrate @ 17215]
Richard Laager <rlaager@wiktel.com>
parents:
14484
diff
changeset
|
221 } |
14192 | 222 gaim_blist_server_alias_buddy(b, alias); |
223 | |
224 conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, b->name, account); | |
225 | |
14496
aee74d84816c
[gaim-migrate @ 17215]
Richard Laager <rlaager@wiktel.com>
parents:
14484
diff
changeset
|
226 if (conv != NULL && alias != NULL) |
14192 | 227 { |
228 char *tmp = g_strdup_printf(_("%s is now known as %s.\n"), | |
229 who, alias); | |
230 | |
231 gaim_conversation_write(conv, NULL, tmp, GAIM_MESSAGE_SYSTEM, | |
232 time(NULL)); | |
233 | |
234 g_free(tmp); | |
235 } | |
236 } | |
237 g_slist_free(buddies); | |
238 } | |
239 | |
240 /* | |
241 * Move a buddy from one group to another on server. | |
242 * | |
243 * Note: For now we'll not deal with changing gc's at the same time, but | |
244 * it should be possible. Probably needs to be done, someday. Although, | |
245 * the UI for that would be difficult, because groups are Gaim-wide. | |
246 */ | |
247 void serv_move_buddy(GaimBuddy *b, GaimGroup *og, GaimGroup *ng) | |
248 { | |
249 GaimPluginProtocolInfo *prpl_info = NULL; | |
250 | |
251 g_return_if_fail(b != NULL); | |
252 g_return_if_fail(og != NULL); | |
253 g_return_if_fail(ng != NULL); | |
254 | |
255 if (b->account->gc != NULL && b->account->gc->prpl != NULL) | |
256 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(b->account->gc->prpl); | |
257 | |
258 if (b->account->gc && og && ng) { | |
259 if (prpl_info && prpl_info->group_buddy) { | |
260 prpl_info->group_buddy(b->account->gc, b->name, og->name, ng->name); | |
261 } | |
262 } | |
263 } | |
264 | |
265 void serv_add_permit(GaimConnection *g, const char *name) | |
266 { | |
267 GaimPluginProtocolInfo *prpl_info = NULL; | |
268 | |
269 if (g != NULL && g->prpl != NULL) | |
270 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); | |
271 | |
14607 | 272 if (prpl_info && prpl_info->add_permit) |
14192 | 273 prpl_info->add_permit(g, name); |
274 } | |
275 | |
276 void serv_add_deny(GaimConnection *g, const char *name) | |
277 { | |
278 GaimPluginProtocolInfo *prpl_info = NULL; | |
279 | |
280 if (g != NULL && g->prpl != NULL) | |
281 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); | |
282 | |
14607 | 283 if (prpl_info && prpl_info->add_deny) |
14192 | 284 prpl_info->add_deny(g, name); |
285 } | |
286 | |
287 void serv_rem_permit(GaimConnection *g, const char *name) | |
288 { | |
289 GaimPluginProtocolInfo *prpl_info = NULL; | |
290 | |
291 if (g != NULL && g->prpl != NULL) | |
292 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); | |
293 | |
14607 | 294 if (prpl_info && prpl_info->rem_permit) |
14192 | 295 prpl_info->rem_permit(g, name); |
296 } | |
297 | |
298 void serv_rem_deny(GaimConnection *g, const char *name) | |
299 { | |
300 GaimPluginProtocolInfo *prpl_info = NULL; | |
301 | |
302 if (g != NULL && g->prpl != NULL) | |
303 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); | |
304 | |
14607 | 305 if (prpl_info && prpl_info->rem_deny) |
14192 | 306 prpl_info->rem_deny(g, name); |
307 } | |
308 | |
309 void serv_set_permit_deny(GaimConnection *g) | |
310 { | |
311 GaimPluginProtocolInfo *prpl_info = NULL; | |
312 | |
313 if (g != NULL && g->prpl != NULL) | |
314 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); | |
315 | |
316 /* | |
317 * this is called when either you import a buddy list, and make lots | |
318 * of changes that way, or when the user toggles the permit/deny mode | |
319 * in the prefs. In either case you should probably be resetting and | |
320 * resending the permit/deny info when you get this. | |
321 */ | |
14607 | 322 if (prpl_info && prpl_info->set_permit_deny) |
14192 | 323 prpl_info->set_permit_deny(g); |
324 } | |
325 | |
326 void serv_join_chat(GaimConnection *g, GHashTable *data) | |
327 { | |
328 GaimPluginProtocolInfo *prpl_info = NULL; | |
329 | |
330 if (g != NULL && g->prpl != NULL) | |
331 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); | |
332 | |
14607 | 333 if (prpl_info && prpl_info->join_chat) |
14192 | 334 prpl_info->join_chat(g, data); |
335 } | |
336 | |
337 | |
338 void serv_reject_chat(GaimConnection *g, GHashTable *data) | |
339 { | |
340 GaimPluginProtocolInfo *prpl_info = NULL; | |
341 | |
342 if (g != NULL && g->prpl != NULL) | |
343 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); | |
344 | |
14607 | 345 if (prpl_info && prpl_info->reject_chat) |
14192 | 346 prpl_info->reject_chat(g, data); |
347 } | |
348 | |
349 void serv_chat_invite(GaimConnection *g, int id, const char *message, const char *name) | |
350 { | |
351 GaimPluginProtocolInfo *prpl_info = NULL; | |
352 GaimConversation *conv; | |
353 char *buffy = message && *message ? g_strdup(message) : NULL; | |
354 | |
355 conv = gaim_find_chat(g, id); | |
356 | |
357 if (conv == NULL) | |
358 return; | |
359 | |
360 if (g != NULL && g->prpl != NULL) | |
361 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); | |
362 | |
363 gaim_signal_emit(gaim_conversations_get_handle(), "chat-inviting-user", | |
364 conv, name, &buffy); | |
365 | |
14607 | 366 if (prpl_info && prpl_info->chat_invite) |
14192 | 367 prpl_info->chat_invite(g, id, buffy, name); |
368 | |
369 gaim_signal_emit(gaim_conversations_get_handle(), "chat-invited-user", | |
370 conv, name, buffy); | |
371 | |
372 g_free(buffy); | |
373 } | |
374 | |
375 /* Ya know, nothing uses this except gaim_conversation_destroy(), | |
376 * I think I'll just merge it into that later... | |
377 * Then again, something might want to use this, from outside prpl-land | |
378 * to leave a chat without destroying the conversation. | |
379 */ | |
380 | |
381 void serv_chat_leave(GaimConnection *g, int id) | |
382 { | |
383 GaimPluginProtocolInfo *prpl_info = NULL; | |
384 | |
385 if (g->prpl != NULL) | |
386 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); | |
387 | |
388 if (prpl_info && prpl_info->chat_leave) | |
389 prpl_info->chat_leave(g, id); | |
390 } | |
391 | |
392 void serv_chat_whisper(GaimConnection *g, int id, const char *who, const char *message) | |
393 { | |
394 GaimPluginProtocolInfo *prpl_info = NULL; | |
395 | |
396 if (g != NULL && g->prpl != NULL) | |
397 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); | |
398 | |
399 if (prpl_info && prpl_info->chat_whisper) | |
400 prpl_info->chat_whisper(g, id, who, message); | |
401 } | |
402 | |
403 int serv_chat_send(GaimConnection *gc, int id, const char *message, GaimMessageFlags flags) | |
404 { | |
405 int val = -EINVAL; | |
406 GaimPluginProtocolInfo *prpl_info = NULL; | |
407 | |
408 if (gc->prpl != NULL) | |
409 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); | |
410 | |
411 if (prpl_info && prpl_info->chat_send) | |
412 val = prpl_info->chat_send(gc, id, message, flags); | |
413 | |
414 return val; | |
415 } | |
416 | |
417 void serv_set_buddyicon(GaimConnection *gc, const char *filename) | |
418 { | |
419 GaimPluginProtocolInfo *prpl_info = NULL; | |
420 | |
421 if (gc->prpl != NULL) | |
422 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); | |
423 | |
424 if (prpl_info && prpl_info->set_buddy_icon) | |
425 prpl_info->set_buddy_icon(gc, filename); | |
426 | |
427 } | |
428 | |
429 /* | |
430 * woo. i'm actually going to comment this function. isn't that fun. make | |
431 * sure to follow along, kids | |
432 */ | |
433 void serv_got_im(GaimConnection *gc, const char *who, const char *msg, | |
434 GaimMessageFlags flags, time_t mtime) | |
435 { | |
436 GaimAccount *account; | |
437 GaimConversation *cnv; | |
438 char *message, *name; | |
439 char *angel, *buffy; | |
440 int plugin_return; | |
441 | |
442 g_return_if_fail(msg != NULL); | |
443 | |
444 account = gaim_connection_get_account(gc); | |
445 | |
446 if (GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl)->set_permit_deny == NULL) { | |
447 /* protocol does not support privacy, handle it ourselves */ | |
448 if (!gaim_privacy_check(account, who)) | |
449 return; | |
450 } | |
451 | |
452 /* | |
453 * We should update the conversation window buttons and menu, | |
454 * if it exists. | |
455 */ | |
456 cnv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, who, gc->account); | |
457 | |
458 /* | |
459 * Plugin stuff. we pass a char ** but we don't want to pass what's | |
460 * been given us by the prpls. So we create temp holders and pass | |
461 * those instead. It's basically just to avoid segfaults. | |
462 */ | |
463 buffy = g_malloc(MAX(strlen(msg) + 1, BUF_LONG)); | |
464 strcpy(buffy, msg); | |
465 angel = g_strdup(who); | |
466 | |
467 plugin_return = GPOINTER_TO_INT( | |
468 gaim_signal_emit_return_1(gaim_conversations_get_handle(), | |
469 "receiving-im-msg", gc->account, | |
470 &angel, &buffy, cnv, &flags)); | |
471 | |
472 if (!buffy || !angel || plugin_return) { | |
473 g_free(buffy); | |
474 g_free(angel); | |
475 return; | |
476 } | |
477 | |
478 name = angel; | |
479 message = buffy; | |
480 | |
481 gaim_signal_emit(gaim_conversations_get_handle(), "received-im-msg", gc->account, | |
482 name, message, cnv, flags); | |
483 | |
484 /* search for conversation again in case it was created by received-im-msg handler */ | |
485 if (cnv == NULL) | |
486 cnv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, name, gc->account); | |
487 | |
488 /* Make sure URLs are clickable */ | |
489 buffy = gaim_markup_linkify(message); | |
490 g_free(message); | |
491 message = buffy; | |
492 | |
493 /* | |
494 * XXX: Should we be setting this here, or relying on prpls to set it? | |
495 */ | |
496 flags |= GAIM_MESSAGE_RECV; | |
497 | |
498 if (cnv == NULL) | |
499 cnv = gaim_conversation_new(GAIM_CONV_TYPE_IM, account, name); | |
500 | |
501 gaim_conv_im_write(GAIM_CONV_IM(cnv), NULL, message, flags, mtime); | |
502 g_free(message); | |
503 | |
504 /* | |
505 * Don't autorespond if: | |
506 * | |
507 * - it's not supported on this connection | |
508 * - we are available | |
509 * - or it's disabled | |
510 * - or we're not idle and the 'only auto respond if idle' pref | |
511 * is set | |
512 */ | |
513 if (gc->flags & GAIM_CONNECTION_AUTO_RESP) | |
514 { | |
515 GaimPresence *presence; | |
516 GaimStatus *status; | |
517 GaimStatusType *status_type; | |
518 GaimStatusPrimitive primitive; | |
519 const gchar *auto_reply_pref; | |
520 const char *away_msg = NULL; | |
521 | |
522 auto_reply_pref = gaim_prefs_get_string("/core/away/auto_reply"); | |
523 | |
524 presence = gaim_account_get_presence(account); | |
525 status = gaim_presence_get_active_status(presence); | |
526 status_type = gaim_status_get_type(status); | |
527 primitive = gaim_status_type_get_primitive(status_type); | |
528 if ((primitive == GAIM_STATUS_AVAILABLE) || | |
529 (primitive == GAIM_STATUS_INVISIBLE) || | |
530 (primitive == GAIM_STATUS_MOBILE) || | |
531 !strcmp(auto_reply_pref, "never") || | |
532 (!gaim_presence_is_idle(presence) && !strcmp(auto_reply_pref, "awayidle"))) | |
533 { | |
534 g_free(name); | |
535 return; | |
536 } | |
537 | |
538 away_msg = gaim_value_get_string( | |
539 gaim_status_get_attr_value(status, "message")); | |
540 | |
541 if ((away_msg != NULL) && (*away_msg != '\0')) { | |
542 struct last_auto_response *lar; | |
543 time_t now = time(NULL); | |
544 | |
545 /* | |
546 * This used to be based on the conversation window. But um, if | |
547 * you went away, and someone sent you a message and got your | |
548 * auto-response, and then you closed the window, and then they | |
549 * sent you another one, they'd get the auto-response back too | |
550 * soon. Besides that, we need to keep track of this even if we've | |
551 * got a queue. So the rest of this block is just the auto-response, | |
552 * if necessary. | |
553 */ | |
554 lar = get_last_auto_response(gc, name); | |
555 if ((now - lar->sent) >= SECS_BEFORE_RESENDING_AUTORESPONSE) | |
556 { | |
557 /* | |
558 * We don't want to send an autoresponse in response to the other user's | |
559 * autoresponse. We do, however, not want to then send one in response to the | |
560 * _next_ message, so we still set lar->sent to now. | |
561 */ | |
562 lar->sent = now; | |
563 | |
564 if (!(flags & GAIM_MESSAGE_AUTO_RESP)) | |
565 { | |
566 serv_send_im(gc, name, away_msg, GAIM_MESSAGE_AUTO_RESP); | |
567 | |
568 gaim_conv_im_write(GAIM_CONV_IM(cnv), NULL, away_msg, | |
569 GAIM_MESSAGE_SEND | GAIM_MESSAGE_AUTO_RESP, | |
570 mtime); | |
571 } | |
572 } | |
573 } | |
574 } | |
575 | |
576 g_free(name); | |
577 } | |
578 | |
579 void serv_got_typing(GaimConnection *gc, const char *name, int timeout, | |
580 GaimTypingState state) { | |
581 GaimConversation *conv; | |
582 GaimConvIm *im = NULL; | |
583 | |
584 conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, name, gc->account); | |
585 if (conv != NULL) { | |
586 im = GAIM_CONV_IM(conv); | |
587 | |
588 gaim_conv_im_set_typing_state(im, state); | |
589 gaim_conv_im_update_typing(im); | |
590 } else { | |
591 if (state == GAIM_TYPING) | |
592 { | |
593 gaim_signal_emit(gaim_conversations_get_handle(), | |
594 "buddy-typing", gc->account, name); | |
595 } | |
596 else | |
597 { | |
598 gaim_signal_emit(gaim_conversations_get_handle(), | |
599 "buddy-typed", gc->account, name); | |
600 } | |
601 } | |
602 | |
603 if (conv != NULL && timeout > 0) | |
604 gaim_conv_im_start_typing_timeout(im, timeout); | |
605 } | |
606 | |
607 void serv_got_typing_stopped(GaimConnection *gc, const char *name) { | |
608 | |
609 GaimConversation *conv; | |
610 GaimConvIm *im; | |
611 | |
612 conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, name, gc->account); | |
613 if (conv != NULL) | |
614 { | |
615 im = GAIM_CONV_IM(conv); | |
616 | |
617 if (im->typing_state == GAIM_NOT_TYPING) | |
618 return; | |
619 | |
620 gaim_conv_im_stop_typing_timeout(im); | |
621 gaim_conv_im_set_typing_state(im, GAIM_NOT_TYPING); | |
622 gaim_conv_im_update_typing(im); | |
623 } | |
624 else | |
625 { | |
626 gaim_signal_emit(gaim_conversations_get_handle(), | |
627 "buddy-typing-stopped", gc->account, name); | |
628 } | |
629 } | |
630 | |
631 struct chat_invite_data { | |
632 GaimConnection *gc; | |
633 GHashTable *components; | |
634 }; | |
635 | |
636 static void chat_invite_data_free(struct chat_invite_data *cid) | |
637 { | |
638 if (cid->components) | |
639 g_hash_table_destroy(cid->components); | |
640 g_free(cid); | |
641 } | |
642 | |
643 | |
644 static void chat_invite_reject(struct chat_invite_data *cid) | |
645 { | |
646 serv_reject_chat(cid->gc, cid->components); | |
647 chat_invite_data_free(cid); | |
648 } | |
649 | |
650 | |
651 static void chat_invite_accept(struct chat_invite_data *cid) | |
652 { | |
653 serv_join_chat(cid->gc, cid->components); | |
654 chat_invite_data_free(cid); | |
655 } | |
656 | |
657 | |
658 | |
659 void serv_got_chat_invite(GaimConnection *gc, const char *name, | |
660 const char *who, const char *message, GHashTable *data) | |
661 { | |
662 GaimAccount *account; | |
663 char buf2[BUF_LONG]; | |
664 struct chat_invite_data *cid = g_new0(struct chat_invite_data, 1); | |
665 int plugin_return; | |
666 | |
667 account = gaim_connection_get_account(gc); | |
668 if (GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl)->set_permit_deny == NULL) { | |
669 /* protocol does not support privacy, handle it ourselves */ | |
670 if (!gaim_privacy_check(account, who)) | |
671 return; | |
672 } | |
673 | |
674 plugin_return = GPOINTER_TO_INT(gaim_signal_emit_return_1( | |
675 gaim_conversations_get_handle(), | |
676 "chat-invited", account, who, name, message, data)); | |
677 | |
678 cid->gc = gc; | |
679 cid->components = data; | |
680 | |
681 if (plugin_return == 0) | |
682 { | |
683 if (message != NULL) | |
684 { | |
685 g_snprintf(buf2, sizeof(buf2), | |
686 _("%s has invited %s to the chat room %s:\n%s"), | |
687 who, gaim_account_get_username(account), name, message); | |
688 } | |
689 else | |
690 g_snprintf(buf2, sizeof(buf2), | |
691 _("%s has invited %s to the chat room %s\n"), | |
692 who, gaim_account_get_username(account), name); | |
693 | |
694 | |
695 gaim_request_accept_cancel(gc, NULL, _("Accept chat invitation?"), buf2, | |
696 GAIM_DEFAULT_ACTION_NONE, cid, | |
697 G_CALLBACK(chat_invite_accept), | |
698 G_CALLBACK(chat_invite_reject)); | |
699 } | |
700 else if (plugin_return > 0) | |
701 chat_invite_accept(cid); | |
702 else | |
703 chat_invite_reject(cid); | |
704 } | |
705 | |
706 GaimConversation *serv_got_joined_chat(GaimConnection *gc, | |
707 int id, const char *name) | |
708 { | |
709 GaimConversation *conv; | |
710 GaimConvChat *chat; | |
711 GaimAccount *account; | |
712 | |
713 account = gaim_connection_get_account(gc); | |
714 | |
715 conv = gaim_conversation_new(GAIM_CONV_TYPE_CHAT, account, name); | |
716 chat = GAIM_CONV_CHAT(conv); | |
717 | |
718 if (!g_slist_find(gc->buddy_chats, conv)) | |
719 gc->buddy_chats = g_slist_append(gc->buddy_chats, conv); | |
720 | |
721 gaim_conv_chat_set_id(chat, id); | |
722 | |
723 gaim_signal_emit(gaim_conversations_get_handle(), "chat-joined", conv); | |
724 | |
725 return conv; | |
726 } | |
727 | |
728 void serv_got_chat_left(GaimConnection *g, int id) | |
729 { | |
730 GSList *bcs; | |
731 GaimConversation *conv = NULL; | |
732 GaimConvChat *chat = NULL; | |
733 | |
734 for (bcs = g->buddy_chats; bcs != NULL; bcs = bcs->next) { | |
735 conv = (GaimConversation *)bcs->data; | |
736 | |
737 chat = GAIM_CONV_CHAT(conv); | |
738 | |
739 if (gaim_conv_chat_get_id(chat) == id) | |
740 break; | |
741 | |
742 conv = NULL; | |
743 } | |
744 | |
745 if (!conv) | |
746 return; | |
747 | |
748 gaim_debug(GAIM_DEBUG_INFO, "server", "Leaving room: %s\n", | |
749 gaim_conversation_get_name(conv)); | |
750 | |
751 g->buddy_chats = g_slist_remove(g->buddy_chats, conv); | |
752 | |
753 gaim_conv_chat_left(GAIM_CONV_CHAT(conv)); | |
754 | |
755 gaim_signal_emit(gaim_conversations_get_handle(), "chat-left", conv); | |
756 } | |
757 | |
758 void serv_got_chat_in(GaimConnection *g, int id, const char *who, | |
759 GaimMessageFlags flags, const char *message, time_t mtime) | |
760 { | |
761 GSList *bcs; | |
762 GaimConversation *conv = NULL; | |
763 GaimConvChat *chat = NULL; | |
764 char *buf; | |
765 char *buffy, *angel; | |
766 int plugin_return; | |
767 | |
768 g_return_if_fail(who != NULL); | |
769 g_return_if_fail(message != NULL); | |
770 | |
771 for (bcs = g->buddy_chats; bcs != NULL; bcs = bcs->next) { | |
772 conv = (GaimConversation *)bcs->data; | |
773 | |
774 chat = GAIM_CONV_CHAT(conv); | |
775 | |
776 if (gaim_conv_chat_get_id(chat) == id) | |
777 break; | |
778 | |
779 conv = NULL; | |
780 } | |
781 | |
782 if (!conv) | |
783 return; | |
784 | |
785 /* | |
786 * Plugin stuff. We pass a char ** but we don't want to pass what's | |
787 * been given us by the prpls. so we create temp holders and pass those | |
788 * instead. It's basically just to avoid segfaults. Of course, if the | |
789 * data is binary, plugins don't see it. Bitch all you want; i really | |
790 * don't want you to be dealing with it. | |
791 */ | |
792 | |
793 buffy = g_malloc(MAX(strlen(message) + 1, BUF_LONG)); | |
794 strcpy(buffy, message); | |
795 angel = g_strdup(who); | |
796 | |
797 plugin_return = GPOINTER_TO_INT( | |
798 gaim_signal_emit_return_1(gaim_conversations_get_handle(), | |
799 "receiving-chat-msg", g->account, | |
800 &angel, &buffy, conv, &flags)); | |
801 | |
802 if (!buffy || !angel || plugin_return) { | |
803 g_free(buffy); | |
804 g_free(angel); | |
805 return; | |
806 } | |
807 who = angel; | |
808 message = buffy; | |
809 | |
810 gaim_signal_emit(gaim_conversations_get_handle(), "received-chat-msg", g->account, | |
811 who, message, conv, flags); | |
812 | |
813 /* Make sure URLs are clickable */ | |
814 buf = gaim_markup_linkify(message); | |
815 | |
816 gaim_conv_chat_write(chat, who, buf, flags, mtime); | |
817 | |
818 g_free(angel); | |
819 g_free(buf); | |
820 g_free(buffy); | |
821 } | |
822 | |
823 void serv_send_file(GaimConnection *gc, const char *who, const char *file) | |
824 { | |
825 GaimPluginProtocolInfo *prpl_info = NULL; | |
826 | |
827 if (gc != NULL && gc->prpl != NULL) | |
828 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); | |
829 | |
830 if (prpl_info && prpl_info->send_file) { | |
831 if (!prpl_info->can_receive_file || prpl_info->can_receive_file(gc, who)) { | |
832 prpl_info->send_file(gc, who, file); | |
833 } | |
834 } | |
835 } |