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