Remove useless comparison
[pidgin-git.git] / libpurple / server.c
blob27a796ffef30966561f64656004a164c18b44d2b
1 /*
2 * purple
4 * Purple 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.
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
24 /* This file is the fullcrap */
26 #include "internal.h"
27 #include "blist.h"
28 #include "conversation.h"
29 #include "debug.h"
30 #include "log.h"
31 #include "notify.h"
32 #include "prefs.h"
33 #include "privacy.h"
34 #include "prpl.h"
35 #include "request.h"
36 #include "signals.h"
37 #include "server.h"
38 #include "status.h"
39 #include "util.h"
41 #define SECS_BEFORE_RESENDING_AUTORESPONSE 600
42 #define SEX_BEFORE_RESENDING_AUTORESPONSE "Only after you're married"
44 unsigned int
45 serv_send_typing(PurpleConnection *gc, const char *name, PurpleTypingState state)
47 PurplePlugin *prpl;
48 PurplePluginProtocolInfo *prpl_info;
50 if (gc) {
51 prpl = purple_connection_get_prpl(gc);
52 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
54 if (prpl_info->send_typing)
55 return prpl_info->send_typing(gc, name, state);
58 return 0;
61 static GSList *last_auto_responses = NULL;
62 struct last_auto_response {
63 PurpleConnection *gc;
64 char name[80];
65 time_t sent;
68 static gboolean
69 expire_last_auto_responses(gpointer data)
71 GSList *tmp, *cur;
72 struct last_auto_response *lar;
74 tmp = last_auto_responses;
76 while (tmp) {
77 cur = tmp;
78 tmp = tmp->next;
79 lar = (struct last_auto_response *)cur->data;
81 if ((time(NULL) - lar->sent) > SECS_BEFORE_RESENDING_AUTORESPONSE) {
82 last_auto_responses = g_slist_remove(last_auto_responses, lar);
83 g_free(lar);
87 return FALSE; /* do not run again */
90 static struct last_auto_response *
91 get_last_auto_response(PurpleConnection *gc, const char *name)
93 GSList *tmp;
94 struct last_auto_response *lar;
96 /* because we're modifying or creating a lar, schedule the
97 * function to expire them as the pref dictates */
98 purple_timeout_add_seconds((SECS_BEFORE_RESENDING_AUTORESPONSE + 1), expire_last_auto_responses, NULL);
100 tmp = last_auto_responses;
102 while (tmp) {
103 lar = (struct last_auto_response *)tmp->data;
105 if (gc == lar->gc && !strncmp(name, lar->name, sizeof(lar->name)))
106 return lar;
108 tmp = tmp->next;
111 lar = (struct last_auto_response *)g_new0(struct last_auto_response, 1);
112 g_snprintf(lar->name, sizeof(lar->name), "%s", name);
113 lar->gc = gc;
114 lar->sent = 0;
115 last_auto_responses = g_slist_prepend(last_auto_responses, lar);
117 return lar;
120 int serv_send_im(PurpleConnection *gc, const char *name, const char *message,
121 PurpleMessageFlags flags)
123 PurpleConversation *conv = NULL;
124 PurpleAccount *account = NULL;
125 PurplePresence *presence = NULL;
126 PurplePlugin *prpl = NULL;
127 PurplePluginProtocolInfo *prpl_info = NULL;
128 int val = -EINVAL;
129 const gchar *auto_reply_pref = NULL;
131 g_return_val_if_fail(gc != NULL, val);
133 prpl = purple_connection_get_prpl(gc);
135 g_return_val_if_fail(prpl != NULL, val);
137 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
139 account = purple_connection_get_account(gc);
140 presence = purple_account_get_presence(account);
142 conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, name, account);
144 if (prpl_info->send_im)
145 val = prpl_info->send_im(gc, name, message, flags);
148 * XXX - If "only auto-reply when away & idle" is set, then shouldn't
149 * this only reset lar->sent if we're away AND idle?
151 auto_reply_pref = purple_prefs_get_string("/purple/away/auto_reply");
152 if((gc->flags & PURPLE_CONNECTION_AUTO_RESP) &&
153 !purple_presence_is_available(presence) &&
154 !purple_strequal(auto_reply_pref, "never")) {
156 struct last_auto_response *lar;
157 lar = get_last_auto_response(gc, name);
158 lar->sent = time(NULL);
161 if(conv && purple_conv_im_get_send_typed_timeout(PURPLE_CONV_IM(conv)))
162 purple_conv_im_stop_send_typed_timeout(PURPLE_CONV_IM(conv));
164 return val;
167 void serv_get_info(PurpleConnection *gc, const char *name)
169 PurplePlugin *prpl;
170 PurplePluginProtocolInfo *prpl_info;
172 if (gc) {
173 prpl = purple_connection_get_prpl(gc);
174 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
176 if (prpl_info->get_info)
177 prpl_info->get_info(gc, name);
181 void serv_set_info(PurpleConnection *gc, const char *info)
183 PurplePlugin *prpl;
184 PurplePluginProtocolInfo *prpl_info;
185 PurpleAccount *account;
187 if (gc) {
188 prpl = purple_connection_get_prpl(gc);
189 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
191 if (prpl_info->set_info) {
192 account = purple_connection_get_account(gc);
194 if (purple_signal_emit_return_1(purple_accounts_get_handle(),
195 "account-setting-info", account, info))
196 return;
198 prpl_info->set_info(gc, info);
200 purple_signal_emit(purple_accounts_get_handle(),
201 "account-set-info", account, info);
207 * Set buddy's alias on server roster/list
209 void serv_alias_buddy(PurpleBuddy *b)
211 PurpleAccount *account;
212 PurpleConnection *gc;
213 PurplePlugin *prpl;
214 PurplePluginProtocolInfo *prpl_info;
216 if (b) {
217 account = purple_buddy_get_account(b);
219 if (account) {
220 gc = purple_account_get_connection(account);
222 if (gc) {
223 prpl = purple_connection_get_prpl(gc);
224 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
226 if (prpl_info->alias_buddy)
227 prpl_info->alias_buddy(gc,
228 purple_buddy_get_name(b),
229 purple_buddy_get_local_buddy_alias(b));
235 void
236 serv_got_alias(PurpleConnection *gc, const char *who, const char *alias)
238 PurpleAccount *account;
239 GSList *buddies;
240 PurpleBuddy *b;
241 PurpleConversation *conv;
243 account = purple_connection_get_account(gc);
244 buddies = purple_find_buddies(account, who);
246 while (buddies != NULL)
248 const char *server_alias;
250 b = buddies->data;
251 buddies = g_slist_delete_link(buddies, buddies);
253 server_alias = purple_buddy_get_server_alias(b);
255 if (purple_strequal(server_alias, alias))
256 continue;
258 purple_blist_server_alias_buddy(b, alias);
260 conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, purple_buddy_get_name(b), account);
261 if (conv != NULL && alias != NULL && !purple_strequal(alias, who))
263 char *escaped = g_markup_escape_text(who, -1);
264 char *escaped2 = g_markup_escape_text(alias, -1);
265 char *tmp = g_strdup_printf(_("%s is now known as %s.\n"),
266 escaped, escaped2);
268 purple_conversation_write(conv, NULL, tmp,
269 PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LINKIFY,
270 time(NULL));
272 g_free(tmp);
273 g_free(escaped2);
274 g_free(escaped);
279 void
280 purple_serv_got_private_alias(PurpleConnection *gc, const char *who, const char *alias)
282 PurpleAccount *account = NULL;
283 GSList *buddies = NULL;
284 PurpleBuddy *b = NULL;
286 account = purple_connection_get_account(gc);
287 buddies = purple_find_buddies(account, who);
289 while(buddies != NULL) {
290 const char *balias;
291 b = buddies->data;
293 buddies = g_slist_delete_link(buddies, buddies);
295 balias = purple_buddy_get_local_buddy_alias(b);
296 if (purple_strequal(balias, alias))
297 continue;
299 purple_blist_alias_buddy(b, alias);
304 PurpleAttentionType *purple_get_attention_type_from_code(PurpleAccount *account, guint type_code)
306 PurplePlugin *prpl;
307 PurpleAttentionType* attn;
308 GList *(*get_attention_types)(PurpleAccount *);
310 g_return_val_if_fail(account != NULL, NULL);
312 prpl = purple_find_prpl(purple_account_get_protocol_id(account));
314 /* Lookup the attention type in the protocol's attention_types list, if any. */
315 get_attention_types = PURPLE_PLUGIN_PROTOCOL_INFO(prpl)->get_attention_types;
316 if (get_attention_types) {
317 GList *attention_types;
319 attention_types = get_attention_types(account);
320 attn = (PurpleAttentionType *)g_list_nth_data(attention_types, type_code);
321 } else {
322 attn = NULL;
325 return attn;
328 void
329 serv_send_attention(PurpleConnection *gc, const char *who, guint type_code)
331 purple_prpl_send_attention(gc, who, type_code);
334 void
335 serv_got_attention(PurpleConnection *gc, const char *who, guint type_code)
337 purple_prpl_got_attention(gc, who, type_code);
342 * Move a buddy from one group to another on server.
344 * Note: For now we'll not deal with changing gc's at the same time, but
345 * it should be possible. Probably needs to be done, someday. Although,
346 * the UI for that would be difficult, because groups are Purple-wide.
348 void serv_move_buddy(PurpleBuddy *b, PurpleGroup *og, PurpleGroup *ng)
350 PurpleAccount *account;
351 PurpleConnection *gc;
352 PurplePlugin *prpl;
353 PurplePluginProtocolInfo *prpl_info;
355 g_return_if_fail(b != NULL);
356 g_return_if_fail(og != NULL);
357 g_return_if_fail(ng != NULL);
359 account = purple_buddy_get_account(b);
360 gc = purple_account_get_connection(account);
362 if (gc) {
363 prpl = purple_connection_get_prpl(gc);
364 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
366 if (prpl_info->group_buddy)
367 prpl_info->group_buddy(gc, purple_buddy_get_name(b),
368 purple_group_get_name(og),
369 purple_group_get_name(ng));
373 void serv_add_permit(PurpleConnection *gc, const char *name)
375 PurplePlugin *prpl;
376 PurplePluginProtocolInfo *prpl_info;
378 if (gc) {
379 prpl = purple_connection_get_prpl(gc);
380 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
382 if (prpl_info->add_permit)
383 prpl_info->add_permit(gc, name);
387 void serv_add_deny(PurpleConnection *gc, const char *name)
389 PurplePlugin *prpl;
390 PurplePluginProtocolInfo *prpl_info;
392 if (gc) {
393 prpl = purple_connection_get_prpl(gc);
394 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
396 if (prpl_info->add_deny)
397 prpl_info->add_deny(gc, name);
401 void serv_rem_permit(PurpleConnection *gc, const char *name)
403 PurplePlugin *prpl;
404 PurplePluginProtocolInfo *prpl_info;
406 if (gc) {
407 prpl = purple_connection_get_prpl(gc);
408 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
410 if (prpl_info->rem_permit)
411 prpl_info->rem_permit(gc, name);
415 void serv_rem_deny(PurpleConnection *gc, const char *name)
417 PurplePlugin *prpl;
418 PurplePluginProtocolInfo *prpl_info;
420 if (gc) {
421 prpl = purple_connection_get_prpl(gc);
422 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
424 if (prpl_info->rem_deny)
425 prpl_info->rem_deny(gc, name);
429 void serv_set_permit_deny(PurpleConnection *gc)
431 PurplePlugin *prpl;
432 PurplePluginProtocolInfo *prpl_info;
434 if (gc) {
435 prpl = purple_connection_get_prpl(gc);
436 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
439 * this is called when either you import a buddy list, and make lots
440 * of changes that way, or when the user toggles the permit/deny mode
441 * in the prefs. In either case you should probably be resetting and
442 * resending the permit/deny info when you get this.
444 if (prpl_info->set_permit_deny)
445 prpl_info->set_permit_deny(gc);
449 void serv_join_chat(PurpleConnection *gc, GHashTable *data)
451 PurplePlugin *prpl;
452 PurplePluginProtocolInfo *prpl_info;
454 if (gc) {
455 prpl = purple_connection_get_prpl(gc);
456 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
458 if (prpl_info->join_chat)
459 prpl_info->join_chat(gc, data);
464 void serv_reject_chat(PurpleConnection *gc, GHashTable *data)
466 PurplePlugin *prpl;
467 PurplePluginProtocolInfo *prpl_info;
469 if (gc) {
470 prpl = purple_connection_get_prpl(gc);
471 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
473 if (prpl_info->reject_chat)
474 prpl_info->reject_chat(gc, data);
478 void serv_chat_invite(PurpleConnection *gc, int id, const char *message, const char *name)
480 PurplePlugin *prpl = NULL;
481 PurplePluginProtocolInfo *prpl_info = NULL;
482 PurpleConversation *conv;
483 char *buffy = message && *message ? g_strdup(message) : NULL;
485 conv = purple_find_chat(gc, id);
487 if(conv == NULL)
488 return;
490 if(gc)
491 prpl = purple_connection_get_prpl(gc);
493 if(prpl)
494 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
496 purple_signal_emit(purple_conversations_get_handle(), "chat-inviting-user",
497 conv, name, &buffy);
499 if (prpl_info && prpl_info->chat_invite)
500 prpl_info->chat_invite(gc, id, buffy, name);
502 purple_signal_emit(purple_conversations_get_handle(), "chat-invited-user",
503 conv, name, buffy);
505 g_free(buffy);
508 /* Ya know, nothing uses this except purple_conversation_destroy(),
509 * I think I'll just merge it into that later...
510 * Then again, something might want to use this, from outside prpl-land
511 * to leave a chat without destroying the conversation.
513 void serv_chat_leave(PurpleConnection *gc, int id)
515 PurplePlugin *prpl;
516 PurplePluginProtocolInfo *prpl_info;
518 prpl = purple_connection_get_prpl(gc);
519 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
521 if (prpl_info->chat_leave)
522 prpl_info->chat_leave(gc, id);
525 void serv_chat_whisper(PurpleConnection *gc, int id, const char *who, const char *message)
527 PurplePlugin *prpl;
528 PurplePluginProtocolInfo *prpl_info;
530 if (gc) {
531 prpl = purple_connection_get_prpl(gc);
532 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
534 if (prpl_info->chat_whisper)
535 prpl_info->chat_whisper(gc, id, who, message);
539 int serv_chat_send(PurpleConnection *gc, int id, const char *message, PurpleMessageFlags flags)
541 PurplePlugin *prpl;
542 PurplePluginProtocolInfo *prpl_info;
544 prpl = purple_connection_get_prpl(gc);
545 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
547 if (prpl_info->chat_send)
548 return prpl_info->chat_send(gc, id, message, flags);
550 return -EINVAL;
554 * woo. i'm actually going to comment this function. isn't that fun. make
555 * sure to follow along, kids
557 void serv_got_im(PurpleConnection *gc, const char *who, const char *msg,
558 PurpleMessageFlags flags, time_t mtime)
560 PurpleAccount *account;
561 PurpleConversation *conv;
562 char *message, *name;
563 char *angel, *buffy;
564 int plugin_return;
566 g_return_if_fail(msg != NULL);
568 account = purple_connection_get_account(gc);
570 if (mtime < 0) {
571 purple_debug_error("server",
572 "serv_got_im ignoring negative timestamp\n");
573 /* TODO: Would be more appropriate to use a value that indicates
574 that the timestamp is unknown, and surface that in the UI. */
575 mtime = time(NULL);
579 * XXX: Should we be setting this here, or relying on prpls to set it?
581 flags |= PURPLE_MESSAGE_RECV;
583 if (!purple_privacy_check(account, who)) {
584 purple_signal_emit(purple_conversations_get_handle(), "blocked-im-msg",
585 account, who, msg, flags, (unsigned int)mtime);
586 return;
590 * We should update the conversation window buttons and menu,
591 * if it exists.
593 conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, who, gc->account);
596 * Make copies of the message and the sender in case plugins want
597 * to free these strings and replace them with a modifed version.
599 buffy = g_strdup(msg);
600 angel = g_strdup(who);
602 plugin_return = GPOINTER_TO_INT(
603 purple_signal_emit_return_1(purple_conversations_get_handle(),
604 "receiving-im-msg", gc->account,
605 &angel, &buffy, conv, &flags));
607 if (!buffy || !angel || plugin_return) {
608 g_free(buffy);
609 g_free(angel);
610 return;
613 name = angel;
614 message = buffy;
616 purple_signal_emit(purple_conversations_get_handle(), "received-im-msg", gc->account,
617 name, message, conv, flags);
619 /* search for conversation again in case it was created by received-im-msg handler */
620 if (conv == NULL)
621 conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, name, gc->account);
623 if (conv == NULL)
624 conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, name);
626 purple_conv_im_write(PURPLE_CONV_IM(conv), name, message, flags, mtime);
627 g_free(message);
630 * Don't autorespond if:
632 * - it's not supported on this connection
633 * - we are available
634 * - or it's disabled
635 * - or we're not idle and the 'only auto respond if idle' pref
636 * is set
638 if (gc->flags & PURPLE_CONNECTION_AUTO_RESP)
640 PurplePresence *presence;
641 PurpleStatus *status;
642 PurpleStatusType *status_type;
643 PurpleStatusPrimitive primitive;
644 const gchar *auto_reply_pref;
645 const char *away_msg = NULL;
646 gboolean mobile = FALSE;
648 auto_reply_pref = purple_prefs_get_string("/purple/away/auto_reply");
650 presence = purple_account_get_presence(account);
651 status = purple_presence_get_active_status(presence);
652 status_type = purple_status_get_type(status);
653 primitive = purple_status_type_get_primitive(status_type);
654 mobile = purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_MOBILE);
655 if ((primitive == PURPLE_STATUS_AVAILABLE) ||
656 (primitive == PURPLE_STATUS_INVISIBLE) ||
657 mobile ||
658 purple_strequal(auto_reply_pref, "never") ||
659 (!purple_presence_is_idle(presence) && purple_strequal(auto_reply_pref, "awayidle")))
661 g_free(name);
662 return;
665 away_msg = purple_value_get_string(
666 purple_status_get_attr_value(status, "message"));
668 if ((away_msg != NULL) && (*away_msg != '\0')) {
669 struct last_auto_response *lar;
670 time_t now = time(NULL);
673 * This used to be based on the conversation window. But um, if
674 * you went away, and someone sent you a message and got your
675 * auto-response, and then you closed the window, and then they
676 * sent you another one, they'd get the auto-response back too
677 * soon. Besides that, we need to keep track of this even if we've
678 * got a queue. So the rest of this block is just the auto-response,
679 * if necessary.
681 lar = get_last_auto_response(gc, name);
682 if ((now - lar->sent) >= SECS_BEFORE_RESENDING_AUTORESPONSE)
685 * We don't want to send an autoresponse in response to the other user's
686 * autoresponse. We do, however, not want to then send one in response to the
687 * _next_ message, so we still set lar->sent to now.
689 lar->sent = now;
691 if (!(flags & PURPLE_MESSAGE_AUTO_RESP))
693 serv_send_im(gc, name, away_msg, PURPLE_MESSAGE_AUTO_RESP);
695 purple_conv_im_write(PURPLE_CONV_IM(conv), NULL, away_msg,
696 PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_AUTO_RESP,
697 mtime);
703 g_free(name);
706 void serv_got_typing(PurpleConnection *gc, const char *name, int timeout,
707 PurpleTypingState state) {
708 PurpleConversation *conv;
709 PurpleConvIm *im = NULL;
711 conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, name, gc->account);
712 if (conv != NULL) {
713 im = PURPLE_CONV_IM(conv);
715 purple_conv_im_set_typing_state(im, state);
716 } else {
717 switch (state)
719 case PURPLE_TYPING:
720 purple_signal_emit(purple_conversations_get_handle(),
721 "buddy-typing", gc->account, name);
722 break;
723 case PURPLE_TYPED:
724 purple_signal_emit(purple_conversations_get_handle(),
725 "buddy-typed", gc->account, name);
726 break;
727 case PURPLE_NOT_TYPING:
728 purple_signal_emit(purple_conversations_get_handle(),
729 "buddy-typing-stopped", gc->account, name);
730 break;
734 if (conv != NULL && timeout > 0)
735 purple_conv_im_start_typing_timeout(im, timeout);
738 void serv_got_typing_stopped(PurpleConnection *gc, const char *name) {
740 PurpleConversation *conv;
741 PurpleConvIm *im;
743 conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, name, gc->account);
744 if (conv != NULL)
746 im = PURPLE_CONV_IM(conv);
748 if (im->typing_state == PURPLE_NOT_TYPING)
749 return;
751 purple_conv_im_stop_typing_timeout(im);
752 purple_conv_im_set_typing_state(im, PURPLE_NOT_TYPING);
754 else
756 purple_signal_emit(purple_conversations_get_handle(),
757 "buddy-typing-stopped", gc->account, name);
761 struct chat_invite_data {
762 PurpleConnection *gc;
763 GHashTable *components;
766 static void chat_invite_data_free(struct chat_invite_data *cid)
768 if (cid->components)
769 g_hash_table_destroy(cid->components);
770 g_free(cid);
774 static void chat_invite_reject(struct chat_invite_data *cid)
776 serv_reject_chat(cid->gc, cid->components);
777 chat_invite_data_free(cid);
781 static void chat_invite_accept(struct chat_invite_data *cid)
783 serv_join_chat(cid->gc, cid->components);
784 chat_invite_data_free(cid);
789 void serv_got_chat_invite(PurpleConnection *gc, const char *name,
790 const char *who, const char *message, GHashTable *data)
792 PurpleAccount *account;
793 char buf2[BUF_LONG];
794 struct chat_invite_data *cid;
795 int plugin_return;
797 g_return_if_fail(name != NULL);
798 g_return_if_fail(who != NULL);
800 account = purple_connection_get_account(gc);
801 if (!purple_privacy_check(account, who)) {
802 purple_signal_emit(purple_conversations_get_handle(), "chat-invite-blocked",
803 account, who, name, message, data);
804 return;
807 cid = g_new0(struct chat_invite_data, 1);
809 plugin_return = GPOINTER_TO_INT(purple_signal_emit_return_1(
810 purple_conversations_get_handle(),
811 "chat-invited", account, who, name, message, data));
813 cid->gc = gc;
814 cid->components = data;
816 if (plugin_return == 0)
818 if (message != NULL)
820 g_snprintf(buf2, sizeof(buf2),
821 _("%s has invited %s to the chat room %s:\n%s"),
822 who, purple_account_get_username(account), name, message);
824 else
825 g_snprintf(buf2, sizeof(buf2),
826 _("%s has invited %s to the chat room %s\n"),
827 who, purple_account_get_username(account), name);
830 purple_request_accept_cancel(gc, NULL, _("Accept chat invitation?"), buf2,
831 PURPLE_DEFAULT_ACTION_NONE, account, who, NULL,
832 cid, G_CALLBACK(chat_invite_accept),
833 G_CALLBACK(chat_invite_reject));
835 else if (plugin_return > 0)
836 chat_invite_accept(cid);
837 else
838 chat_invite_reject(cid);
841 PurpleConversation *serv_got_joined_chat(PurpleConnection *gc,
842 int id, const char *name)
844 PurpleConversation *conv;
845 PurpleConvChat *chat;
846 PurpleAccount *account;
848 account = purple_connection_get_account(gc);
850 g_return_val_if_fail(account != NULL, NULL);
851 g_return_val_if_fail(name != NULL, NULL);
853 conv = purple_conversation_new(PURPLE_CONV_TYPE_CHAT, account, name);
854 g_return_val_if_fail(conv != NULL, NULL);
856 chat = PURPLE_CONV_CHAT(conv);
858 if (!g_slist_find(gc->buddy_chats, conv))
859 gc->buddy_chats = g_slist_append(gc->buddy_chats, conv);
861 purple_conv_chat_set_id(chat, id);
863 purple_signal_emit(purple_conversations_get_handle(), "chat-joined", conv);
865 return conv;
868 void serv_got_chat_left(PurpleConnection *g, int id)
870 GSList *bcs;
871 PurpleConversation *conv = NULL;
872 PurpleConvChat *chat = NULL;
874 for (bcs = g->buddy_chats; bcs != NULL; bcs = bcs->next) {
875 conv = (PurpleConversation *)bcs->data;
877 chat = PURPLE_CONV_CHAT(conv);
879 if (purple_conv_chat_get_id(chat) == id)
880 break;
882 conv = NULL;
885 if (!conv)
886 return;
888 purple_debug(PURPLE_DEBUG_INFO, "server", "Leaving room: %s\n",
889 purple_conversation_get_name(conv));
891 g->buddy_chats = g_slist_remove(g->buddy_chats, conv);
893 purple_conv_chat_left(PURPLE_CONV_CHAT(conv));
895 purple_signal_emit(purple_conversations_get_handle(), "chat-left", conv);
898 void purple_serv_got_join_chat_failed(PurpleConnection *gc, GHashTable *data)
900 purple_signal_emit(purple_conversations_get_handle(), "chat-join-failed",
901 gc, data);
904 void serv_got_chat_in(PurpleConnection *g, int id, const char *who,
905 PurpleMessageFlags flags, const char *message, time_t mtime)
907 GSList *bcs;
908 PurpleConversation *conv = NULL;
909 PurpleConvChat *chat = NULL;
910 char *buffy, *angel;
911 int plugin_return;
913 g_return_if_fail(who != NULL);
914 g_return_if_fail(message != NULL);
916 if (mtime < 0) {
917 purple_debug_error("server",
918 "serv_got_chat_in ignoring negative timestamp\n");
919 /* TODO: Would be more appropriate to use a value that indicates
920 that the timestamp is unknown, and surface that in the UI. */
921 mtime = time(NULL);
924 for (bcs = g->buddy_chats; bcs != NULL; bcs = bcs->next) {
925 conv = (PurpleConversation *)bcs->data;
927 chat = PURPLE_CONV_CHAT(conv);
929 if (purple_conv_chat_get_id(chat) == id)
930 break;
932 conv = NULL;
935 if (!conv)
936 return;
938 /* Did I send the message? */
939 if (purple_strequal(purple_conv_chat_get_nick(chat),
940 purple_normalize(purple_conversation_get_account(conv), who))) {
941 flags |= PURPLE_MESSAGE_SEND;
942 flags &= ~PURPLE_MESSAGE_RECV; /* Just in case some prpl sets it! */
943 } else {
944 flags |= PURPLE_MESSAGE_RECV;
948 * Make copies of the message and the sender in case plugins want
949 * to free these strings and replace them with a modifed version.
951 buffy = g_strdup(message);
952 angel = g_strdup(who);
954 plugin_return = GPOINTER_TO_INT(
955 purple_signal_emit_return_1(purple_conversations_get_handle(),
956 "receiving-chat-msg", g->account,
957 &angel, &buffy, conv, &flags));
959 if (!buffy || !angel || plugin_return) {
960 g_free(buffy);
961 g_free(angel);
962 return;
965 who = angel;
966 message = buffy;
968 purple_signal_emit(purple_conversations_get_handle(), "received-chat-msg", g->account,
969 who, message, conv, flags);
971 purple_conv_chat_write(chat, who, message, flags, mtime);
973 g_free(angel);
974 g_free(buffy);
977 void serv_send_file(PurpleConnection *gc, const char *who, const char *file)
979 PurplePlugin *prpl;
980 PurplePluginProtocolInfo *prpl_info;
982 if (gc) {
983 prpl = purple_connection_get_prpl(gc);
984 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
986 if (prpl_info->send_file &&
987 (!prpl_info->can_receive_file
988 || prpl_info->can_receive_file(gc, who)))
989 prpl_info->send_file(gc, who, file);