4 * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include <sys/types.h>
34 #include "gtkimhtml.h"
42 void serv_login(struct gaim_account
*account
)
44 GaimPlugin
*p
= gaim_find_prpl(account
->protocol
);
45 GaimPluginProtocolInfo
*prpl_info
= NULL
;
47 if (account
->gc
!= NULL
|| p
== NULL
)
50 prpl_info
= GAIM_PLUGIN_PROTOCOL_INFO(p
);
52 if (prpl_info
->login
) {
53 if (!strlen(account
->password
) && !(prpl_info
->options
& OPT_PROTO_NO_PASSWORD
) &&
54 !(prpl_info
->options
& OPT_PROTO_PASSWORD_OPTIONAL
)) {
55 gaim_notify_error(NULL
, NULL
,
56 _("Please enter your password"), NULL
);
60 gaim_debug(GAIM_DEBUG_INFO
, "server",
61 PACKAGE
" " VERSION
" logging in %s using %s\n",
62 account
->username
, p
->info
->name
);
63 account
->connecting
= TRUE
;
65 gaim_debug(GAIM_DEBUG_MISC
, "server",
66 "connection count: %d\n", connecting_count
);
67 gaim_event_broadcast(event_connecting
, account
);
68 prpl_info
->login(account
);
72 static gboolean
send_keepalive(gpointer d
)
74 struct gaim_connection
*gc
= d
;
75 GaimPluginProtocolInfo
*prpl_info
= NULL
;
77 if (gc
!= NULL
&& gc
->prpl
!= NULL
)
78 prpl_info
= GAIM_PLUGIN_PROTOCOL_INFO(gc
->prpl
);
80 if (prpl_info
&& prpl_info
->keepalive
)
81 prpl_info
->keepalive(gc
);
86 static void update_keepalive(struct gaim_connection
*gc
, gboolean on
)
88 if (on
&& !gc
->keepalive
) {
89 gaim_debug(GAIM_DEBUG_INFO
, "server", "allowing NOP\n");
90 gc
->keepalive
= g_timeout_add(60000, send_keepalive
, gc
);
91 } else if (!on
&& gc
->keepalive
> 0) {
92 gaim_debug(GAIM_DEBUG_INFO
, "server", "removing NOP\n");
93 g_source_remove(gc
->keepalive
);
98 void serv_close(struct gaim_connection
*gc
)
101 GaimPluginProtocolInfo
*prpl_info
= NULL
;
103 while (gc
->buddy_chats
) {
104 struct gaim_conversation
*b
= gc
->buddy_chats
->data
;
106 gc
->buddy_chats
= g_slist_remove(gc
->buddy_chats
, b
);
108 /* TODO: Nuke the UI-specific code here. */
109 if (GAIM_IS_GTK_CONVERSATION(b
))
110 gaim_gtkconv_update_buttons_by_protocol(b
);
113 if (gc
->idle_timer
> 0)
114 g_source_remove(gc
->idle_timer
);
117 update_keepalive(gc
, FALSE
);
119 if (gc
->prpl
!= NULL
) {
120 prpl_info
= GAIM_PLUGIN_PROTOCOL_INFO(gc
->prpl
);
122 if (prpl_info
->close
)
123 prpl_info
->close(gc
);
128 destroy_gaim_conn(gc
);
131 void serv_touch_idle(struct gaim_connection
*gc
)
133 /* Are we idle? If so, not anymore */
134 if (gc
->is_idle
> 0) {
136 serv_set_idle(gc
, 0);
139 if (gc
->is_auto_away
)
143 void serv_finish_login(struct gaim_connection
*gc
)
145 GaimPluginProtocolInfo
*prpl_info
= NULL
;
147 if (gc
!= NULL
&& gc
->prpl
!= NULL
)
148 prpl_info
= GAIM_PLUGIN_PROTOCOL_INFO(gc
->prpl
);
150 if (strlen(gc
->account
->user_info
)) {
151 /* g_malloc(strlen(gc->user->user_info) * 4);
152 strncpy_withhtml(buf, gc->user->user_info, strlen(gc->user->user_info) * 4); */
153 serv_set_info(gc
, gc
->account
->user_info
);
157 if (gc
->idle_timer
> 0)
158 g_source_remove(gc
->idle_timer
);
160 gc
->idle_timer
= g_timeout_add(20000, check_idle
, gc
);
163 if (prpl_info
->options
& OPT_PROTO_CORRECT_TIME
)
164 serv_add_buddy(gc
, gc
->username
);
166 update_keepalive(gc
, TRUE
);
169 /* This should return the elapsed time in seconds in which Gaim will not send
170 * typing notifications.
171 * if it returns zero, it will not send any more typing notifications
172 * typing is a flag - TRUE for typing, FALSE for stopped typing */
173 int serv_send_typing(struct gaim_connection
*g
, char *name
, int typing
) {
174 GaimPluginProtocolInfo
*prpl_info
= NULL
;
176 if (g
!= NULL
&& g
->prpl
!= NULL
)
177 prpl_info
= GAIM_PLUGIN_PROTOCOL_INFO(g
->prpl
);
179 if (g
&& prpl_info
&& prpl_info
->send_typing
)
180 return prpl_info
->send_typing(g
, name
, typing
);
185 struct queued_away_response
{
190 struct queued_away_response
*find_queued_away_response_by_name(char *name
);
192 int serv_send_im(struct gaim_connection
*gc
, char *name
, char *message
,
195 struct gaim_conversation
*c
;
197 GaimPluginProtocolInfo
*prpl_info
= NULL
;
199 if (gc
!= NULL
&& gc
->prpl
!= NULL
)
200 prpl_info
= GAIM_PLUGIN_PROTOCOL_INFO(gc
->prpl
);
202 c
= gaim_find_conversation(name
);
204 if (prpl_info
&& prpl_info
->send_im
)
205 val
= prpl_info
->send_im(gc
, name
, message
, len
, flags
);
207 if (!(flags
& IM_FLAG_AWAY
))
210 if (gc
->away
&& away_options
& OPT_AWAY_DELAY_IN_USE
&&
211 !(away_options
& OPT_AWAY_NO_AUTO_RESP
)) {
213 struct queued_away_response
*qar
;
215 qar
= find_queued_away_response_by_name(name
);
217 qar
= (struct queued_away_response
*)g_new0(struct queued_away_response
, 1);
218 g_snprintf(qar
->name
, sizeof(qar
->name
), "%s", name
);
220 away_time_queue
= g_slist_append(away_time_queue
, qar
);
225 if (c
&& gaim_im_get_type_again_timeout(GAIM_IM(c
)))
226 gaim_im_stop_type_again_timeout(GAIM_IM(c
));
231 void serv_get_info(struct gaim_connection
*g
, char *name
)
233 GaimPluginProtocolInfo
*prpl_info
= NULL
;
235 if (g
!= NULL
&& g
->prpl
!= NULL
)
236 prpl_info
= GAIM_PLUGIN_PROTOCOL_INFO(g
->prpl
);
238 if (g
&& prpl_info
&& prpl_info
->get_info
)
239 prpl_info
->get_info(g
, name
);
242 void serv_get_away(struct gaim_connection
*g
, const char *name
)
244 GaimPluginProtocolInfo
*prpl_info
= NULL
;
246 if (g
!= NULL
&& g
->prpl
!= NULL
)
247 prpl_info
= GAIM_PLUGIN_PROTOCOL_INFO(g
->prpl
);
249 if (g
&& prpl_info
&& prpl_info
->get_away
)
250 prpl_info
->get_away(g
, name
);
253 void serv_get_dir(struct gaim_connection
*g
, char *name
)
255 GaimPluginProtocolInfo
*prpl_info
= NULL
;
257 if (g
!= NULL
&& g
->prpl
!= NULL
)
258 prpl_info
= GAIM_PLUGIN_PROTOCOL_INFO(g
->prpl
);
260 if (prpl_info
&& g_slist_find(connections
, g
) && prpl_info
->get_dir
)
261 prpl_info
->get_dir(g
, name
);
264 void serv_set_dir(struct gaim_connection
*g
, const char *first
,
265 const char *middle
, const char *last
, const char *maiden
,
266 const char *city
, const char *state
, const char *country
,
269 GaimPluginProtocolInfo
*prpl_info
= NULL
;
271 if (g
!= NULL
&& g
->prpl
!= NULL
)
272 prpl_info
= GAIM_PLUGIN_PROTOCOL_INFO(g
->prpl
);
274 if (prpl_info
&& g_slist_find(connections
, g
) && prpl_info
->set_dir
)
275 prpl_info
->set_dir(g
, first
, middle
, last
, maiden
, city
, state
,
279 void serv_dir_search(struct gaim_connection
*g
, const char *first
,
280 const char *middle
, const char *last
, const char *maiden
,
281 const char *city
, const char *state
, const char *country
,
284 GaimPluginProtocolInfo
*prpl_info
= NULL
;
286 if (g
!= NULL
&& g
->prpl
!= NULL
)
287 prpl_info
= GAIM_PLUGIN_PROTOCOL_INFO(g
->prpl
);
289 if (prpl_info
&& g_slist_find(connections
, g
) && prpl_info
->dir_search
)
290 prpl_info
->dir_search(g
, first
, middle
, last
, maiden
, city
, state
,
295 void serv_set_away(struct gaim_connection
*gc
, char *state
, char *message
)
297 GaimPluginProtocolInfo
*prpl_info
= NULL
;
299 if (gc
->away_state
== NULL
&& state
== NULL
&&
300 gc
->away
== NULL
&& message
== NULL
) {
305 if ((gc
->away_state
!= NULL
&& state
!= NULL
&&
306 !strcmp(gc
->away_state
, state
) &&
307 !strcmp(gc
->away_state
, GAIM_AWAY_CUSTOM
)) &&
308 (gc
->away
!= NULL
&& message
!= NULL
&& !strcmp(gc
->away
, message
))) {
313 if (gc
!= NULL
&& gc
->prpl
!= NULL
)
314 prpl_info
= GAIM_PLUGIN_PROTOCOL_INFO(gc
->prpl
);
316 if (prpl_info
&& prpl_info
->set_away
) {
319 if (gc
->away_state
) {
320 g_free(gc
->away_state
);
321 gc
->away_state
= NULL
;
325 buf
= g_malloc(strlen(message
) * 4 + 1);
326 if (gc
->flags
& OPT_CONN_HTML
)
327 strncpy_withhtml(buf
, message
, strlen(message
) * 4 + 1);
329 strncpy_nohtml(buf
, message
, strlen(message
) + 1);
332 prpl_info
->set_away(gc
, state
, buf
);
334 if (gc
->away
&& state
) {
335 gc
->away_state
= g_strdup(state
);
338 gaim_event_broadcast(event_away
, gc
, state
, buf
);
344 system_log(log_away
, gc
, NULL
, OPT_LOG_BUDDY_AWAY
| OPT_LOG_MY_SIGNON
);
347 void serv_set_away_all(char *message
)
350 struct gaim_connection
*g
;
352 for (c
= connections
; c
!= NULL
; c
= c
->next
) {
353 g
= (struct gaim_connection
*)c
->data
;
355 serv_set_away(g
, GAIM_AWAY_CUSTOM
, message
);
359 void serv_set_info(struct gaim_connection
*g
, char *info
)
361 GaimPluginProtocolInfo
*prpl_info
= NULL
;
363 if (g
!= NULL
&& g
->prpl
!= NULL
)
364 prpl_info
= GAIM_PLUGIN_PROTOCOL_INFO(g
->prpl
);
366 if (prpl_info
&& g_slist_find(connections
, g
) && prpl_info
->set_info
) {
367 if (gaim_event_broadcast(event_set_info
, g
, info
))
370 prpl_info
->set_info(g
, info
);
374 void serv_change_passwd(struct gaim_connection
*g
, const char *orig
, const char *new)
376 GaimPluginProtocolInfo
*prpl_info
= NULL
;
378 if (g
!= NULL
&& g
->prpl
!= NULL
)
379 prpl_info
= GAIM_PLUGIN_PROTOCOL_INFO(g
->prpl
);
381 if (prpl_info
&& g_slist_find(connections
, g
) && prpl_info
->change_passwd
)
382 prpl_info
->change_passwd(g
, orig
, new);
385 void serv_add_buddy(struct gaim_connection
*g
, const char *name
)
387 GaimPluginProtocolInfo
*prpl_info
= NULL
;
389 if (g
!= NULL
&& g
->prpl
!= NULL
)
390 prpl_info
= GAIM_PLUGIN_PROTOCOL_INFO(g
->prpl
);
392 if (prpl_info
&& g_slist_find(connections
, g
) && prpl_info
->add_buddy
)
393 prpl_info
->add_buddy(g
, name
);
396 void serv_add_buddies(struct gaim_connection
*g
, GList
*buddies
)
398 GaimPluginProtocolInfo
*prpl_info
= NULL
;
400 if (g
!= NULL
&& g
->prpl
!= NULL
)
401 prpl_info
= GAIM_PLUGIN_PROTOCOL_INFO(g
->prpl
);
403 if (prpl_info
&& g_slist_find(connections
, g
)) {
404 if (prpl_info
->add_buddies
)
405 prpl_info
->add_buddies(g
, buddies
);
406 else if (prpl_info
->add_buddy
) {
408 prpl_info
->add_buddy(g
, buddies
->data
);
409 buddies
= buddies
->next
;
416 void serv_remove_buddy(struct gaim_connection
*g
, char *name
, char *group
)
418 GaimPluginProtocolInfo
*prpl_info
= NULL
;
420 if (g
!= NULL
&& g
->prpl
!= NULL
)
421 prpl_info
= GAIM_PLUGIN_PROTOCOL_INFO(g
->prpl
);
423 if (prpl_info
&& g_slist_find(connections
, g
) && prpl_info
->remove_buddy
)
424 prpl_info
->remove_buddy(g
, name
, group
);
427 void serv_remove_buddies(struct gaim_connection
*gc
, GList
*g
, char *group
)
429 GaimPluginProtocolInfo
*prpl_info
= NULL
;
431 if (!g_slist_find(connections
, gc
))
435 return; /* how the hell did that happen? */
437 if (gc
!= NULL
&& gc
->prpl
!= NULL
)
438 prpl_info
= GAIM_PLUGIN_PROTOCOL_INFO(gc
->prpl
);
440 if (prpl_info
->remove_buddies
)
441 prpl_info
->remove_buddies(gc
, g
, group
);
444 serv_remove_buddy(gc
, g
->data
, group
);
451 * Set buddy's alias on server roster/list
453 void serv_alias_buddy(struct buddy
*b
)
455 GaimPluginProtocolInfo
*prpl_info
= NULL
;
457 if (b
!= NULL
&& b
->account
->gc
->prpl
!= NULL
)
458 prpl_info
= GAIM_PLUGIN_PROTOCOL_INFO(b
->account
->gc
->prpl
);
460 if (b
&& prpl_info
&& prpl_info
->alias_buddy
) {
461 prpl_info
->alias_buddy(b
->account
->gc
, b
->name
, b
->alias
);
465 void serv_got_alias(struct gaim_connection
*gc
, char *who
, char *alias
) {
466 struct buddy
*b
= gaim_find_buddy(gc
->account
, who
);
471 g_free(b
->server_alias
);
474 b
->server_alias
= g_strdup(alias
);
476 b
->server_alias
= NULL
;
478 gaim_blist_update_buddy_status(b
, b
->uc
);
482 * Move a buddy from one group to another on server.
484 * Note: For now we'll not deal with changing gc's at the same time, but
485 * it should be possible. Probably needs to be done, someday.
487 void serv_move_buddy(struct buddy
*b
, struct group
*og
, struct group
*ng
)
489 GaimPluginProtocolInfo
*prpl_info
= NULL
;
491 if (b
->account
->gc
!= NULL
&& b
->account
->gc
->prpl
!= NULL
)
492 prpl_info
= GAIM_PLUGIN_PROTOCOL_INFO(b
->account
->gc
->prpl
);
494 if (b
&& b
->account
->gc
&& og
&& ng
) {
495 if (prpl_info
&& prpl_info
->group_buddy
) {
496 prpl_info
->group_buddy(b
->account
->gc
, b
->name
, og
->name
, ng
->name
);
502 * Rename a group on server roster/list.
504 void serv_rename_group(struct gaim_connection
*g
, struct group
*old_group
,
505 const char *new_name
)
507 GaimPluginProtocolInfo
*prpl_info
= NULL
;
509 if (g
!= NULL
&& g
->prpl
!= NULL
)
510 prpl_info
= GAIM_PLUGIN_PROTOCOL_INFO(g
->prpl
);
512 if (prpl_info
&& old_group
&& new_name
) {
513 GList
*tobemoved
= NULL
;
514 GaimBlistNode
*b
= ((GaimBlistNode
*)old_group
)->child
;
517 if(GAIM_BLIST_NODE_IS_BUDDY(b
)) {
518 struct buddy
*bd
= (struct buddy
*)b
;
519 if (bd
->account
== g
->account
)
520 tobemoved
= g_list_append(tobemoved
, bd
->name
);
525 if (prpl_info
->rename_group
) {
526 /* prpl's might need to check if the group already
527 * exists or not, and handle that differently */
528 prpl_info
->rename_group(g
, old_group
->name
, new_name
, tobemoved
);
530 serv_remove_buddies(g
, tobemoved
, old_group
->name
);
531 serv_add_buddies(g
, tobemoved
);
534 g_list_free(tobemoved
);
538 void serv_add_permit(struct gaim_connection
*g
, const char *name
)
540 GaimPluginProtocolInfo
*prpl_info
= NULL
;
542 if (g
!= NULL
&& g
->prpl
!= NULL
)
543 prpl_info
= GAIM_PLUGIN_PROTOCOL_INFO(g
->prpl
);
545 if (prpl_info
&& g_slist_find(connections
, g
) && prpl_info
->add_permit
)
546 prpl_info
->add_permit(g
, name
);
549 void serv_add_deny(struct gaim_connection
*g
, const char *name
)
551 GaimPluginProtocolInfo
*prpl_info
= NULL
;
553 if (g
!= NULL
&& g
->prpl
!= NULL
)
554 prpl_info
= GAIM_PLUGIN_PROTOCOL_INFO(g
->prpl
);
556 if (prpl_info
&& g_slist_find(connections
, g
) && prpl_info
->add_deny
)
557 prpl_info
->add_deny(g
, name
);
560 void serv_rem_permit(struct gaim_connection
*g
, const char *name
)
562 GaimPluginProtocolInfo
*prpl_info
= NULL
;
564 if (g
!= NULL
&& g
->prpl
!= NULL
)
565 prpl_info
= GAIM_PLUGIN_PROTOCOL_INFO(g
->prpl
);
567 if (prpl_info
&& g_slist_find(connections
, g
) && prpl_info
->rem_permit
)
568 prpl_info
->rem_permit(g
, name
);
571 void serv_rem_deny(struct gaim_connection
*g
, const char *name
)
573 GaimPluginProtocolInfo
*prpl_info
= NULL
;
575 if (g
!= NULL
&& g
->prpl
!= NULL
)
576 prpl_info
= GAIM_PLUGIN_PROTOCOL_INFO(g
->prpl
);
578 if (prpl_info
&& g_slist_find(connections
, g
) && prpl_info
->rem_deny
)
579 prpl_info
->rem_deny(g
, name
);
582 void serv_set_permit_deny(struct gaim_connection
*g
)
584 GaimPluginProtocolInfo
*prpl_info
= NULL
;
586 if (g
!= NULL
&& g
->prpl
!= NULL
)
587 prpl_info
= GAIM_PLUGIN_PROTOCOL_INFO(g
->prpl
);
590 * this is called when either you import a buddy list, and make lots
591 * of changes that way, or when the user toggles the permit/deny mode
592 * in the prefs. In either case you should probably be resetting and
593 * resending the permit/deny info when you get this.
595 if (prpl_info
&& g_slist_find(connections
, g
) && prpl_info
->set_permit_deny
)
596 prpl_info
->set_permit_deny(g
);
600 void serv_set_idle(struct gaim_connection
*g
, int time
)
602 GaimPluginProtocolInfo
*prpl_info
= NULL
;
604 if (g
!= NULL
&& g
->prpl
!= NULL
)
605 prpl_info
= GAIM_PLUGIN_PROTOCOL_INFO(g
->prpl
);
607 if (prpl_info
&& g_slist_find(connections
, g
) && prpl_info
->set_idle
)
608 prpl_info
->set_idle(g
, time
);
611 void serv_warn(struct gaim_connection
*g
, char *name
, int anon
)
613 GaimPluginProtocolInfo
*prpl_info
= NULL
;
615 if (g
!= NULL
&& g
->prpl
!= NULL
)
616 prpl_info
= GAIM_PLUGIN_PROTOCOL_INFO(g
->prpl
);
618 if (prpl_info
&& g_slist_find(connections
, g
) && prpl_info
->warn
)
619 prpl_info
->warn(g
, name
, anon
);
622 void serv_join_chat(struct gaim_connection
*g
, GHashTable
*data
)
624 GaimPluginProtocolInfo
*prpl_info
= NULL
;
626 if (g
!= NULL
&& g
->prpl
!= NULL
)
627 prpl_info
= GAIM_PLUGIN_PROTOCOL_INFO(g
->prpl
);
629 if (prpl_info
&& g_slist_find(connections
, g
) && prpl_info
->join_chat
)
630 prpl_info
->join_chat(g
, data
);
633 void serv_chat_invite(struct gaim_connection
*g
, int id
, const char *message
, const char *name
)
635 GaimPluginProtocolInfo
*prpl_info
= NULL
;
636 char *buffy
= message
&& *message
? g_strdup(message
) : NULL
;
638 if (g
!= NULL
&& g
->prpl
!= NULL
)
639 prpl_info
= GAIM_PLUGIN_PROTOCOL_INFO(g
->prpl
);
641 gaim_event_broadcast(event_chat_send_invite
, g
, (void *)id
, name
, &buffy
);
643 if (prpl_info
&& g_slist_find(connections
, g
) && prpl_info
->chat_invite
)
644 prpl_info
->chat_invite(g
, id
, buffy
, name
);
650 void serv_chat_leave(struct gaim_connection
*g
, int id
)
652 GaimPluginProtocolInfo
*prpl_info
= NULL
;
654 if (!g_slist_find(connections
, g
))
658 prpl_info
= GAIM_PLUGIN_PROTOCOL_INFO(g
->prpl
);
660 if (prpl_info
&& prpl_info
->chat_leave
)
661 prpl_info
->chat_leave(g
, id
);
664 void serv_chat_whisper(struct gaim_connection
*g
, int id
, char *who
, char *message
)
666 GaimPluginProtocolInfo
*prpl_info
= NULL
;
668 if (g
!= NULL
&& g
->prpl
!= NULL
)
669 prpl_info
= GAIM_PLUGIN_PROTOCOL_INFO(g
->prpl
);
671 if (prpl_info
&& prpl_info
->chat_whisper
)
672 prpl_info
->chat_whisper(g
, id
, who
, message
);
675 int serv_chat_send(struct gaim_connection
*g
, int id
, char *message
)
678 GaimPluginProtocolInfo
*prpl_info
= NULL
;
681 prpl_info
= GAIM_PLUGIN_PROTOCOL_INFO(g
->prpl
);
683 if (prpl_info
&& prpl_info
->chat_send
)
684 val
= prpl_info
->chat_send(g
, id
, message
);
691 int find_queue_row_by_name(char *name
)
698 valid
= gtk_tree_model_get_iter_first(GTK_TREE_MODEL(awayqueuestore
), &iter
);
700 gtk_tree_model_get(GTK_TREE_MODEL(awayqueuestore
), &iter
, 0, &temp
, -1);
701 if(!strcmp(name
, temp
))
706 valid
= gtk_tree_model_iter_next(GTK_TREE_MODEL(awayqueuestore
), &iter
);
712 int find_queue_total_by_name(char *name
)
717 templist
= message_queue
;
720 struct queued_message
*qm
= (struct queued_message
*)templist
->data
;
721 if ((qm
->flags
& WFLAG_RECV
) && !strcmp(name
, qm
->name
))
724 templist
= templist
->next
;
730 struct queued_away_response
*find_queued_away_response_by_name(char *name
)
733 struct queued_away_response
*qar
;
735 templist
= away_time_queue
;
738 qar
= (struct queued_away_response
*)templist
->data
;
740 if (!strcmp(name
, qar
->name
))
743 templist
= templist
->next
;
750 * woo. i'm actually going to comment this function. isn't that fun. make
751 * sure to follow along, kids
753 void serv_got_im(struct gaim_connection
*gc
, const char *who
, const char *msg
,
754 guint32 flags
, time_t mtime
, gint len
)
761 struct gaim_conversation
*cnv
;
763 char *message
, *name
;
766 * Pay no attention to the man behind the curtain.
768 * The reason i feel okay with this is because it's useful to some
769 * plugins. Gaim doesn't ever use it itself. Besides, it's not entirely
770 * accurate; it's possible to have false negatives with most protocols.
771 * Also with some it's easy to have false positives as well. So if you're
772 * a plugin author, don't rely on this, still do your own checks. But uh.
776 if (flags
& IM_FLAG_GAIMUSER
)
777 gaim_debug(GAIM_DEBUG_MISC
, "server", "%s is a gaim user.\n", who
);
780 * We should update the conversation window buttons and menu,
783 cnv
= gaim_find_conversation_with_account(who
, gc
->account
);
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
788 * those instead. It's basically just to avoid segfaults. Of course,
789 * if the data is binary, plugins don't see it. Bitch all you want;
790 * I really don't want you to be dealing with it.
793 buffy
= g_malloc(MAX(strlen(msg
) + 1, BUF_LONG
));
795 angel
= g_strdup(who
);
796 plugin_return
= gaim_event_broadcast(event_im_recv
, gc
, &angel
, &buffy
, &flags
);
798 if (!buffy
|| !angel
|| plugin_return
) {
808 name
= g_strdup(who
);
809 message
= g_memdup(msg
, len
);
813 * If you can't figure this out, stop reading right now.
814 * "We're not worthy! We're not worthy!"
816 if ((len
< 0) && (convo_options
& OPT_CONVO_SEND_LINKS
)) {
817 buffy
= linkify_text(message
);
823 * Um. When we call gaim_conversation_write with the message we received,
824 * it's nice to pass whether or not it was an auto-response. So if it
825 * was an auto-response, we set the appropriate flag. This is just so
826 * prpls don't have to know about WFLAG_* (though some do anyway)
828 if (flags
& IM_FLAG_AWAY
)
832 * Alright. Two cases for how to handle this. Either we're away or
833 * we're not. If we're not, then it's easy. If we are, then there
834 * are three or four different ways of handling it and different
835 * things we have to do for each.
840 struct buddy
*b
= gaim_find_buddy(gc
->account
, name
);
841 char *alias
= b
? gaim_get_buddy_alias(b
) : name
;
843 struct queued_away_response
*qar
;
848 * Either we're going to queue it or not. Because of the way
849 * awayness currently works, this is fucked up. It's possible
850 * for an account to be away without the imaway dialog being
851 * shown. In fact, it's possible for *all* the accounts to be
852 * away without the imaway dialog being shown. So in order for
853 * this to be queued properly, we have to make sure that the
854 * imaway dialog actually exists, first.
856 if (!cnv
&& awayqueue
&& (away_options
& OPT_AWAY_QUEUE
)) {
858 * Alright, so we're going to queue it. Neat, eh? :)
859 * So first we create something to store the message, and add
860 * it to our queue. Then we update the away dialog to indicate
861 * that we've queued something.
863 struct queued_message
*qm
;
867 qm
= g_new0(struct queued_message
, 1);
868 g_snprintf(qm
->name
, sizeof(qm
->name
), "%s", name
);
869 qm
->message
= g_memdup(message
, len
== -1 ? strlen(message
) + 1 : len
);
870 qm
->account
= gc
->account
;
872 qm
->flags
= WFLAG_RECV
| away
;
874 message_queue
= g_slist_append(message_queue
, qm
);
876 row
= find_queue_row_by_name(qm
->name
);
881 qtotal
= find_queue_total_by_name(qm
->name
);
882 g_snprintf(number
, 32, _("(%d messages)"), qtotal
);
883 g_snprintf(path
, 10, "%d", row
);
884 gtk_tree_model_get_iter_from_string(
885 GTK_TREE_MODEL(awayqueuestore
), &iter
, path
);
886 gtk_list_store_set(awayqueuestore
, &iter
,
889 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(awayqueuestore
),
891 gtk_list_store_append(awayqueuestore
, &iter
);
892 gtk_list_store_set(awayqueuestore
, &iter
,
899 * Make sure the conversation
900 * exists and is updated (partly handled above already), play
901 * the receive sound (sound.c will take care of not playing
902 * while away), and then write it to the convo window.
905 cnv
= gaim_conversation_new(GAIM_CONV_IM
, gc
->account
, name
);
907 gaim_im_write(GAIM_IM(cnv
), NULL
, message
, len
,
908 away
| WFLAG_RECV
, mtime
);
912 * Regardless of whether we queue it or not, we should send an
913 * auto-response. That is, of course, unless the horse.... no wait.
914 * Don't autorespond if:
916 * - it's not supported on this connection
918 * - or the away message is empty
919 * - or we're not idle and the 'only auto respond if idle' pref
922 if (!(gc
->flags
& OPT_CONN_AUTO_RESP
) ||
923 (away_options
& OPT_AWAY_NO_AUTO_RESP
) || !strlen(gc
->away
) ||
924 ((away_options
& OPT_AWAY_IDLE_RESP
) && !gc
->is_idle
)) {
932 * This used to be based on the conversation window. But um, if
933 * you went away, and someone sent you a message and got your
934 * auto-response, and then you closed the window, and then the
935 * sent you another one, they'd get the auto-response back too
936 * soon. Besides that, we need to keep track of this even if we've
937 * got a queue. So the rest of this block is just the auto-response,
940 qar
= find_queued_away_response_by_name(name
);
942 qar
= (struct queued_away_response
*)g_new0(struct queued_away_response
, 1);
943 g_snprintf(qar
->name
, sizeof(qar
->name
), "%s", name
);
945 away_time_queue
= g_slist_append(away_time_queue
, qar
);
947 if ((t
- qar
->sent_away
) < away_resend
) {
954 /* apply default fonts and colors */
955 tmpmsg
= stylize(gc
->away
, MSG_LEN
);
956 serv_send_im(gc
, name
, away_subs(tmpmsg
, alias
), -1, IM_FLAG_AWAY
);
957 if (!cnv
&& awayqueue
&& (away_options
& OPT_AWAY_QUEUE
)) {
958 struct queued_message
*qm
;
959 qm
= g_new0(struct queued_message
, 1);
960 g_snprintf(qm
->name
, sizeof(qm
->name
), "%s", name
);
961 qm
->message
= g_strdup(away_subs(tmpmsg
, alias
));
962 qm
->account
= gc
->account
;
964 qm
->flags
= WFLAG_SEND
| WFLAG_AUTO
;
966 message_queue
= g_slist_append(message_queue
, qm
);
967 } else if (cnv
!= NULL
)
968 gaim_im_write(GAIM_IM(cnv
), NULL
, away_subs(tmpmsg
, alias
),
969 len
, WFLAG_SEND
| WFLAG_AUTO
, mtime
);
974 * We're not away. This is easy. If the convo window doesn't
975 * exist, create and update it (if it does exist it was updated
976 * earlier), then play a sound indicating we've received it and
977 * then display it. Easy.
979 if (away_options
& OPT_AWAY_QUEUE_UNREAD
&&
980 !gaim_find_conversation(name
) && docklet_count
) {
983 * We're gonna queue it up and wait for the user to ask for
984 * it... probably by clicking the docklet or windows tray icon.
986 struct queued_message
*qm
;
987 qm
= g_new0(struct queued_message
, 1);
988 g_snprintf(qm
->name
, sizeof(qm
->name
), "%s", name
);
989 qm
->message
= g_strdup(message
);
990 qm
->account
= gc
->account
;
992 qm
->flags
= away
| WFLAG_RECV
;
994 unread_message_queue
= g_slist_append(unread_message_queue
, qm
);
997 cnv
= gaim_conversation_new(GAIM_CONV_IM
, gc
->account
, name
);
999 /* CONV XXX gaim_conversation_set_name(cnv, name); */
1001 gaim_im_write(GAIM_IM(cnv
), NULL
, message
, len
,
1002 away
| WFLAG_RECV
, mtime
);
1003 gaim_window_flash(gaim_conversation_get_window(cnv
));
1007 gaim_event_broadcast(event_im_displayed_rcvd
, gc
, name
, message
, flags
, mtime
);
1014 void serv_got_update(struct gaim_connection
*gc
, char *name
, int loggedin
,
1015 int evil
, time_t signon
, time_t idle
, int type
)
1017 struct buddy
*b
= gaim_find_buddy(gc
->account
, name
);
1019 if (signon
&& (GAIM_PLUGIN_PROTOCOL_INFO(gc
->prpl
)->options
&
1020 OPT_PROTO_CORRECT_TIME
)) {
1022 char *tmp
= g_strdup(normalize(name
));
1023 if (!gaim_utf8_strcasecmp(tmp
, normalize(gc
->username
))) {
1025 gc
->login_time_official
= signon
;
1026 /*update_idle_times();*/
1032 gaim_debug(GAIM_DEBUG_ERROR
, "server",
1033 "No such buddy: %s\n", name
);
1037 /* This code will 'align' the name from the TOC */
1038 /* server with what's in our record. We want to */
1039 /* store things how THEY want it... */
1040 if (strcmp(name
, b
->name
)) {
1041 gaim_blist_rename_buddy(b
, name
);
1045 if (!b
->idle
&& idle
) {
1046 gaim_pounce_execute(gc
->account
, b
->name
, GAIM_POUNCE_IDLE
);
1047 gaim_event_broadcast(event_buddy_idle
, gc
, b
->name
);
1048 system_log(log_idle
, gc
, b
, OPT_LOG_BUDDY_IDLE
);
1050 if (b
->idle
&& !idle
) {
1051 gaim_pounce_execute(gc
->account
, b
->name
, GAIM_POUNCE_IDLE_RETURN
);
1052 gaim_event_broadcast(event_buddy_unidle
, gc
, b
->name
);
1053 system_log(log_unidle
, gc
, b
, OPT_LOG_BUDDY_IDLE
);
1056 gaim_blist_update_buddy_idle(b
, idle
);
1057 gaim_blist_update_buddy_evil(b
, evil
);
1059 if ((b
->uc
& UC_UNAVAILABLE
) && !(type
& UC_UNAVAILABLE
)) {
1060 gaim_pounce_execute(gc
->account
, b
->name
, GAIM_POUNCE_AWAY_RETURN
);
1061 system_log(log_back
, gc
, b
, OPT_LOG_BUDDY_AWAY
);
1062 } else if (!(b
->uc
& UC_UNAVAILABLE
) && (type
& UC_UNAVAILABLE
)) {
1063 gaim_pounce_execute(gc
->account
, b
->name
, GAIM_POUNCE_AWAY
);
1064 system_log(log_away
, gc
, b
, OPT_LOG_BUDDY_AWAY
);
1067 gaim_blist_update_buddy_status(b
, type
);
1071 if (!GAIM_BUDDY_IS_ONLINE(b
)) {
1072 struct gaim_conversation
*c
= gaim_find_conversation(b
->name
);
1073 if (c
&& (im_options
& OPT_IM_LOGON
)) {
1074 char *tmp
= g_strdup_printf(_("%s logged in."), gaim_get_buddy_alias(b
));
1075 gaim_conversation_write(c
, NULL
, tmp
, -1,
1076 WFLAG_SYSTEM
, time(NULL
));
1078 } else if (awayqueue
&& find_queue_total_by_name(b
->name
)) {
1079 struct queued_message
*qm
= g_new0(struct queued_message
, 1);
1080 g_snprintf(qm
->name
, sizeof(qm
->name
), "%s", b
->name
);
1081 qm
->message
= g_strdup_printf(_("%s logged in."),
1082 gaim_get_buddy_alias(b
));
1083 qm
->account
= gc
->account
;
1084 qm
->tm
= time(NULL
);
1085 qm
->flags
= WFLAG_SYSTEM
;
1087 message_queue
= g_slist_append(message_queue
, qm
);
1089 gaim_sound_play_event(GAIM_SOUND_BUDDY_ARRIVE
);
1090 gaim_pounce_execute(gc
->account
, b
->name
, GAIM_POUNCE_SIGNON
);
1091 system_log(log_signon
, gc
, b
, OPT_LOG_BUDDY_SIGNON
);
1094 if (GAIM_BUDDY_IS_ONLINE(b
)) {
1095 struct gaim_conversation
*c
= gaim_find_conversation(b
->name
);
1096 if (c
&& (im_options
& OPT_IM_LOGON
)) {
1097 char *tmp
= g_strdup_printf(_("%s logged out."), gaim_get_buddy_alias(b
));
1098 gaim_conversation_write(c
, NULL
, tmp
, -1,
1099 WFLAG_SYSTEM
, time(NULL
));
1101 } else if (awayqueue
&& find_queue_total_by_name(b
->name
)) {
1102 struct queued_message
*qm
= g_new0(struct queued_message
, 1);
1103 g_snprintf(qm
->name
, sizeof(qm
->name
), "%s", b
->name
);
1104 qm
->message
= g_strdup_printf(_("%s logged out."),
1105 gaim_get_buddy_alias(b
));
1106 qm
->account
= gc
->account
;
1107 qm
->tm
= time(NULL
);
1108 qm
->flags
= WFLAG_SYSTEM
;
1110 message_queue
= g_slist_append(message_queue
, qm
);
1112 serv_got_typing_stopped(gc
, name
); /* obviously not typing */
1113 gaim_sound_play_event(GAIM_SOUND_BUDDY_LEAVE
);
1114 gaim_pounce_execute(gc
->account
, b
->name
, GAIM_POUNCE_SIGNOFF
);
1115 system_log(log_signoff
, gc
, b
, OPT_LOG_BUDDY_SIGNON
);
1119 gaim_blist_update_buddy_presence(b
, loggedin
);
1124 void serv_got_eviled(struct gaim_connection
*gc
, char *name
, int lev
)
1128 gaim_event_broadcast(event_warned
, gc
, name
, lev
);
1130 if (gc
->evil
>= lev
) {
1137 g_snprintf(buf2
, sizeof(buf2
),
1138 _("%s has just been warned by %s.\n"
1139 "Your new warning level is %d%%"),
1141 ((name
== NULL
)? _("an anonymous person") : name
), lev
);
1143 gaim_notify_info(NULL
, NULL
, buf2
, NULL
);
1146 void serv_got_typing(struct gaim_connection
*gc
, char *name
, int timeout
,
1150 struct gaim_conversation
*cnv
= gaim_find_conversation(name
);
1158 gaim_conversation_set_account(cnv
, gc
->account
);
1159 gaim_im_set_typing_state(im
, state
);
1160 gaim_im_update_typing(im
);
1162 b
= gaim_find_buddy(gc
->account
, name
);
1164 gaim_event_broadcast(event_got_typing
, gc
, name
);
1167 gaim_pounce_execute(gc
->account
, name
, GAIM_POUNCE_TYPING
);
1170 gaim_im_start_typing_timeout(im
, timeout
);
1173 void serv_got_typing_stopped(struct gaim_connection
*gc
, char *name
) {
1175 struct gaim_conversation
*c
= gaim_find_conversation(name
);
1184 if (im
->typing_state
== NOT_TYPING
)
1187 gaim_im_stop_typing_timeout(im
);
1188 gaim_im_set_typing_state(im
, NOT_TYPING
);
1189 gaim_im_update_typing(im
);
1191 b
= gaim_find_buddy(gc
->account
, name
);
1194 gaim_pounce_execute(gc
->account
, name
, GAIM_POUNCE_TYPING_STOPPED
);
1197 struct chat_invite_data
{
1198 struct gaim_connection
*gc
;
1199 GHashTable
*components
;
1202 static void chat_invite_data_free(struct chat_invite_data
*cid
)
1204 if (cid
->components
)
1205 g_hash_table_destroy(cid
->components
);
1209 static void chat_invite_accept(struct chat_invite_data
*cid
)
1211 serv_join_chat(cid
->gc
, cid
->components
);
1213 chat_invite_data_free(cid
);
1218 void serv_got_chat_invite(struct gaim_connection
*gc
, char *name
,
1219 char *who
, char *message
, GHashTable
*data
)
1221 char buf2
[BUF_LONG
];
1222 struct chat_invite_data
*cid
= g_new0(struct chat_invite_data
, 1);
1225 gaim_event_broadcast(event_chat_invited
, gc
, who
, name
, message
);
1228 g_snprintf(buf2
, sizeof(buf2
),
1229 _("User '%s' invites %s to buddy chat room: '%s'\n%s"),
1230 who
, gc
->username
, name
, message
);
1232 g_snprintf(buf2
, sizeof(buf2
),
1233 _("User '%s' invites %s to buddy chat room: '%s'\n"),
1234 who
, gc
->username
, name
);
1237 cid
->components
= data
;
1239 do_ask_dialog(_("Buddy Chat Invite"), buf2
, cid
, _("Accept"), chat_invite_accept
, _("Cancel"), chat_invite_data_free
, NULL
, FALSE
);
1242 struct gaim_conversation
*serv_got_joined_chat(struct gaim_connection
*gc
,
1245 struct gaim_conversation
*b
;
1246 struct gaim_chat
*chat
;
1248 b
= gaim_conversation_new(GAIM_CONV_CHAT
, gc
->account
, name
);
1249 chat
= GAIM_CHAT(b
);
1251 gc
->buddy_chats
= g_slist_append(gc
->buddy_chats
, b
);
1253 gaim_chat_set_id(chat
, id
);
1255 if ((logging_options
& OPT_LOG_CHATS
) ||
1256 find_log_info(gaim_conversation_get_name(b
))) {
1261 filename
= (char *)malloc(100);
1262 g_snprintf(filename
, 100, "%s.chat", gaim_conversation_get_name(b
));
1264 fd
= open_log_file(filename
, TRUE
);
1267 if (!(logging_options
& OPT_LOG_STRIP_HTML
))
1269 "<HR><BR><H3 Align=Center> ---- New Conversation @ %s ----</H3><BR>\n",
1272 fprintf(fd
, "---- New Conversation @ %s ----\n", full_date());
1279 gaim_window_show(gaim_conversation_get_window(b
));
1280 gaim_window_switch_conversation(gaim_conversation_get_window(b
),
1281 gaim_conversation_get_index(b
));
1283 gaim_event_broadcast(event_chat_join
, gc
, id
, name
);
1288 void serv_got_chat_left(struct gaim_connection
*g
, int id
)
1291 struct gaim_conversation
*conv
= NULL
;
1292 struct gaim_chat
*chat
= NULL
;
1294 for (bcs
= g
->buddy_chats
; bcs
!= NULL
; bcs
= bcs
->next
) {
1295 conv
= (struct gaim_conversation
*)bcs
->data
;
1297 chat
= GAIM_CHAT(conv
);
1299 if (gaim_chat_get_id(chat
) == id
)
1308 gaim_event_broadcast(event_chat_leave
, g
, gaim_chat_get_id(chat
));
1310 gaim_debug(GAIM_DEBUG_INFO
, "server", "Leaving room: %s\n",
1311 gaim_conversation_get_name(conv
));
1313 g
->buddy_chats
= g_slist_remove(g
->buddy_chats
, conv
);
1315 gaim_conversation_destroy(conv
);
1318 void serv_got_chat_in(struct gaim_connection
*g
, int id
, char *who
,
1319 int whisper
, char *message
, time_t mtime
)
1323 struct gaim_conversation
*conv
= NULL
;
1324 struct gaim_chat
*chat
= NULL
;
1326 char *buffy
, *angel
;
1329 for (bcs
= g
->buddy_chats
; bcs
!= NULL
; bcs
= bcs
->next
) {
1330 conv
= (struct gaim_conversation
*)bcs
->data
;
1332 chat
= GAIM_CHAT(conv
);
1334 if (gaim_chat_get_id(chat
) == id
)
1344 * Plugin stuff. We pass a char ** but we don't want to pass what's
1345 * been given us by the prpls. so we create temp holders and pass those
1346 * instead. It's basically just to avoid segfaults. Of course, if the
1347 * data is binary, plugins don't see it. Bitch all you want; i really
1348 * don't want you to be dealing with it.
1351 buffy
= g_malloc(MAX(strlen(message
) + 1, BUF_LONG
));
1352 strcpy(buffy
, message
);
1353 angel
= g_strdup(who
);
1354 plugin_return
= gaim_event_broadcast(event_chat_recv
, g
, gaim_chat_get_id(chat
),
1357 if (!buffy
|| !angel
|| plugin_return
) {
1369 if (convo_options
& OPT_CONVO_SEND_LINKS
)
1370 buf
= linkify_text(message
);
1372 buf
= g_strdup(message
);
1379 gaim_chat_write(chat
, who
, buf
, w
, mtime
);
1386 static void des_popup(GtkWidget
*w
, GtkWidget
*window
)
1389 char *u
= g_object_get_data(G_OBJECT(window
), "url");
1392 gtk_widget_destroy(window
);
1395 void serv_got_popup(char *msg
, char *u
, int wid
, int hei
)
1403 char *url
= g_strdup(u
);
1405 GAIM_DIALOG(window
);
1406 gtk_window_set_role(GTK_WINDOW(window
), "popup");
1407 gtk_window_set_resizable(GTK_WINDOW(window
), FALSE
);
1408 gtk_window_set_title(GTK_WINDOW(window
), _("Gaim - Popup"));
1409 gtk_container_set_border_width(GTK_CONTAINER(window
), 5);
1410 g_signal_connect(G_OBJECT(window
), "destroy",
1411 G_CALLBACK(des_popup
), window
);
1412 g_object_set_data(G_OBJECT(window
), "url", url
);
1413 gtk_widget_realize(window
);
1415 vbox
= gtk_vbox_new(FALSE
, 5);
1416 gtk_container_add(GTK_CONTAINER(window
), vbox
);
1418 sw
= gtk_scrolled_window_new(NULL
, NULL
);
1419 gtk_widget_set_size_request(sw
, wid
, hei
);
1420 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw
), GTK_POLICY_NEVER
, GTK_POLICY_ALWAYS
);
1421 gtk_box_pack_start(GTK_BOX(vbox
), sw
, TRUE
, TRUE
, 5);
1423 text
= gtk_imhtml_new(NULL
, NULL
);
1424 gtk_container_add(GTK_CONTAINER(sw
), text
);
1425 gaim_setup_imhtml(text
);
1427 hbox
= gtk_hbox_new(FALSE
, 5);
1428 gtk_box_pack_end(GTK_BOX(vbox
), hbox
, FALSE
, FALSE
, 5);
1430 button
= gaim_pixbuf_button_from_stock(_("Close"), GTK_STOCK_CLOSE
, GAIM_BUTTON_HORIZONTAL
);
1431 gtk_box_pack_end(GTK_BOX(hbox
), button
, FALSE
, FALSE
, 5);
1432 g_signal_connect(G_OBJECT(button
), "clicked",
1433 G_CALLBACK(des_popup
), window
);
1435 button
= gaim_pixbuf_button_from_stock(_("More Info"), GTK_STOCK_FIND
, GAIM_BUTTON_HORIZONTAL
);
1436 gtk_box_pack_end(GTK_BOX(hbox
), button
, FALSE
, FALSE
, 5);
1437 g_signal_connect(G_OBJECT(button
), "clicked",
1438 G_CALLBACK(open_url
), url
);
1440 gtk_widget_show_all(window
);
1442 gtk_imhtml_append_text(GTK_IMHTML(text
), msg
, -1, GTK_IMHTML_NO_NEWLINE
);