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 #include "pixmaps/ok.xpm"
43 #include "pixmaps/cancel.xpm"
44 #include "pixmaps/tb_search.xpm"
46 void serv_login(struct aim_user
*user
)
48 struct prpl
*p
= find_prpl(user
->protocol
);
54 if (!strlen(user
->password
) && !(p
->options
& OPT_PROTO_NO_PASSWORD
)) {
55 do_error_dialog(_("Please enter your password"), _("Signon Error"));
59 debug_printf(PACKAGE
" " VERSION
" logging in %s using %s\n", user
->username
, p
->name());
62 do_error_dialog(_("You cannot log this account in; you do not have "
63 "the protocol it uses loaded, or the protocol does "
64 "not have a login function."), _("Login Error"));
68 static gboolean
send_keepalive(gpointer d
)
70 struct gaim_connection
*gc
= d
;
71 if (gc
->prpl
&& gc
->prpl
->keepalive
)
72 gc
->prpl
->keepalive(gc
);
76 static void update_keepalive(struct gaim_connection
*gc
, gboolean on
)
78 if (on
&& !gc
->keepalive
) {
79 debug_printf("allowing NOP\n");
80 gc
->keepalive
= g_timeout_add(60000, send_keepalive
, gc
);
81 } else if (!on
&& gc
->keepalive
> 0) {
82 debug_printf("removing NOP\n");
83 g_source_remove(gc
->keepalive
);
88 void serv_close(struct gaim_connection
*gc
)
90 while (gc
->buddy_chats
) {
91 struct conversation
*b
= gc
->buddy_chats
->data
;
92 gc
->buddy_chats
= g_slist_remove(gc
->buddy_chats
, b
);
94 update_buttons_by_protocol(b
);
97 if (gc
->idle_timer
> 0)
98 g_source_remove(gc
->idle_timer
);
101 update_keepalive(gc
, FALSE
);
103 if (gc
->prpl
&& gc
->prpl
->close
)
107 destroy_gaim_conn(gc
);
110 void serv_touch_idle(struct gaim_connection
*gc
)
112 /* Are we idle? If so, not anymore */
113 if (gc
->is_idle
> 0) {
115 serv_set_idle(gc
, 0);
118 if (gc
->is_auto_away
)
122 void serv_finish_login(struct gaim_connection
*gc
)
124 if (strlen(gc
->user
->user_info
)) {
125 /* g_malloc(strlen(gc->user->user_info) * 4);
126 strncpy_withhtml(buf, gc->user->user_info, strlen(gc->user->user_info) * 4); */
127 serv_set_info(gc
, gc
->user
->user_info
);
131 if (gc
->idle_timer
> 0)
132 g_source_remove(gc
->idle_timer
);
134 gc
->idle_timer
= g_timeout_add(20000, check_idle
, gc
);
137 time(&gc
->login_time
);
139 if (gc
->prpl
->options
& OPT_PROTO_CORRECT_TIME
)
140 serv_add_buddy(gc
, gc
->username
);
142 update_keepalive(gc
, TRUE
);
145 /* This should return the elapsed time in seconds in which Gaim will not send
146 * typing notifications.
147 * if it returns zero, it will not send any more typing notifications
148 * typing is a flag - TRUE for typing, FALSE for stopped typing */
149 int serv_send_typing(struct gaim_connection
*g
, char *name
, int typing
) {
150 if (g
&& g
->prpl
&& g
->prpl
->send_typing
)
151 return g
->prpl
->send_typing(g
, name
, typing
);
155 int serv_send_im(struct gaim_connection
*gc
, char *name
, char *message
, int len
, int flags
)
158 if (gc
->prpl
&& gc
->prpl
->send_im
)
159 val
= gc
->prpl
->send_im(gc
, name
, message
, len
, flags
);
161 if (!(flags
& IM_FLAG_AWAY
))
164 serv_send_typing(gc
, name
, FALSE
);
168 void serv_get_info(struct gaim_connection
*g
, char *name
)
170 if (g
&& g
->prpl
&& g
->prpl
->get_info
)
171 g
->prpl
->get_info(g
, name
);
174 void serv_get_away(struct gaim_connection
*g
, char *name
)
176 if (g
&& g
->prpl
&& g
->prpl
->get_away
)
177 g
->prpl
->get_away(g
, name
);
180 void serv_get_dir(struct gaim_connection
*g
, char *name
)
182 if (g
&& g_slist_find(connections
, g
) && g
->prpl
&& g
->prpl
->get_dir
)
183 g
->prpl
->get_dir(g
, name
);
186 void serv_set_dir(struct gaim_connection
*g
, char *first
, char *middle
, char *last
, char *maiden
,
187 char *city
, char *state
, char *country
, int web
)
189 if (g
&& g_slist_find(connections
, g
) && g
->prpl
&& g
->prpl
->set_dir
)
190 g
->prpl
->set_dir(g
, first
, middle
, last
, maiden
, city
, state
, country
, web
);
193 void serv_dir_search(struct gaim_connection
*g
, char *first
, char *middle
, char *last
, char *maiden
,
194 char *city
, char *state
, char *country
, char *email
)
196 if (g
&& g_slist_find(connections
, g
) && g
->prpl
&& g
->prpl
->dir_search
)
197 g
->prpl
->dir_search(g
, first
, middle
, last
, maiden
, city
, state
, country
, email
);
201 void serv_set_away(struct gaim_connection
*gc
, char *state
, char *message
)
203 if (gc
&& gc
->prpl
&& gc
->prpl
->set_away
) {
206 buf
= g_malloc(strlen(message
) + 1);
207 if (gc
->flags
& OPT_CONN_HTML
)
208 strncpy(buf
, message
, strlen(message
) + 1);
210 strncpy_nohtml(buf
, message
, strlen(message
) + 1);
213 gc
->prpl
->set_away(gc
, state
, buf
);
215 plugin_event(event_away
, gc
, state
, buf
, 0);
221 system_log(log_away
, gc
, NULL
, OPT_LOG_BUDDY_AWAY
| OPT_LOG_MY_SIGNON
);
224 void serv_set_away_all(char *message
)
226 GSList
*c
= connections
;
227 struct gaim_connection
*g
;
230 g
= (struct gaim_connection
*)c
->data
;
231 serv_set_away(g
, GAIM_AWAY_CUSTOM
, message
);
236 void serv_set_info(struct gaim_connection
*g
, char *info
)
238 if (g
&& g_slist_find(connections
, g
) && g
->prpl
&& g
->prpl
->set_info
) {
239 plugin_event(event_set_info
, g
, info
, 0, 0);
240 g
->prpl
->set_info(g
, info
);
244 void serv_change_passwd(struct gaim_connection
*g
, char *orig
, char *new)
246 if (g
&& g_slist_find(connections
, g
) && g
->prpl
&& g
->prpl
->change_passwd
)
247 g
->prpl
->change_passwd(g
, orig
, new);
250 void serv_add_buddy(struct gaim_connection
*g
, char *name
)
252 if (g
&& g_slist_find(connections
, g
) && g
->prpl
&& g
->prpl
->add_buddy
)
253 g
->prpl
->add_buddy(g
, name
);
256 void serv_add_buddies(struct gaim_connection
*g
, GList
*buddies
)
258 if (g
&& g_slist_find(connections
, g
) && g
->prpl
) {
259 if (g
->prpl
->add_buddies
)
260 g
->prpl
->add_buddies(g
, buddies
);
261 else if (g
->prpl
->add_buddy
)
263 g
->prpl
->add_buddy(g
, buddies
->data
);
264 buddies
= buddies
->next
;
270 void serv_remove_buddy(struct gaim_connection
*g
, char *name
, char *group
)
272 if (g
&& g_slist_find(connections
, g
) && g
->prpl
&& g
->prpl
->remove_buddy
)
273 g
->prpl
->remove_buddy(g
, name
, group
);
276 void serv_remove_buddies(struct gaim_connection
*gc
, GList
*g
, char *group
)
278 if (!g_slist_find(connections
, gc
))
281 return; /* how the hell did that happen? */
282 if (gc
->prpl
->remove_buddies
)
283 gc
->prpl
->remove_buddies(gc
, g
, group
);
286 serv_remove_buddy(gc
, g
->data
, group
);
292 void serv_add_permit(struct gaim_connection
*g
, char *name
)
294 if (g
&& g_slist_find(connections
, g
) && g
->prpl
&& g
->prpl
->add_permit
)
295 g
->prpl
->add_permit(g
, name
);
298 void serv_add_deny(struct gaim_connection
*g
, char *name
)
300 if (g
&& g_slist_find(connections
, g
) && g
->prpl
&& g
->prpl
->add_deny
)
301 g
->prpl
->add_deny(g
, name
);
304 void serv_rem_permit(struct gaim_connection
*g
, char *name
)
306 if (g
&& g_slist_find(connections
, g
) && g
->prpl
&& g
->prpl
->rem_permit
)
307 g
->prpl
->rem_permit(g
, name
);
310 void serv_rem_deny(struct gaim_connection
*g
, char *name
)
312 if (g
&& g_slist_find(connections
, g
) && g
->prpl
&& g
->prpl
->rem_deny
)
313 g
->prpl
->rem_deny(g
, name
);
316 void serv_set_permit_deny(struct gaim_connection
*g
)
318 /* this is called when either you import a buddy list, and make lots of changes that way,
319 * or when the user toggles the permit/deny mode in the prefs. In either case you should
320 * probably be resetting and resending the permit/deny info when you get this. */
321 if (g
&& g_slist_find(connections
, g
) && g
->prpl
&& g
->prpl
->set_permit_deny
)
322 g
->prpl
->set_permit_deny(g
);
326 void serv_set_idle(struct gaim_connection
*g
, int time
)
328 if (g
&& g_slist_find(connections
, g
) && g
->prpl
&& g
->prpl
->set_idle
)
329 g
->prpl
->set_idle(g
, time
);
332 void serv_warn(struct gaim_connection
*g
, char *name
, int anon
)
334 if (g
&& g_slist_find(connections
, g
) && g
->prpl
&& g
->prpl
->warn
)
335 g
->prpl
->warn(g
, name
, anon
);
338 void serv_join_chat(struct gaim_connection
*g
, GList
*data
)
340 if (g
&& g_slist_find(connections
, g
) && g
->prpl
&& g
->prpl
->join_chat
)
341 g
->prpl
->join_chat(g
, data
);
344 void serv_chat_invite(struct gaim_connection
*g
, int id
, char *message
, char *name
)
346 char *buffy
= message
&& *message
? g_strdup(message
) : NULL
;
347 plugin_event(event_chat_send_invite
, g
, (void *)id
, name
, &buffy
);
348 if (g
&& g_slist_find(connections
, g
) && g
->prpl
&& g
->prpl
->chat_invite
)
349 g
->prpl
->chat_invite(g
, id
, buffy
, name
);
354 void serv_chat_leave(struct gaim_connection
*g
, int id
)
356 if (!g_slist_find(connections
, g
))
359 if (g
->prpl
&& g
->prpl
->chat_leave
)
360 g
->prpl
->chat_leave(g
, id
);
363 void serv_chat_whisper(struct gaim_connection
*g
, int id
, char *who
, char *message
)
365 if (g
->prpl
&& g
->prpl
->chat_whisper
)
366 g
->prpl
->chat_whisper(g
, id
, who
, message
);
369 int serv_chat_send(struct gaim_connection
*g
, int id
, char *message
)
372 if (g
->prpl
&& g
->prpl
->chat_send
)
373 val
= g
->prpl
->chat_send(g
, id
, message
);
378 int find_queue_row_by_name(char *name
)
384 templist
= message_queue
;
386 for (i
= 0; i
< GTK_CLIST(clistqueue
)->rows
; i
++) {
387 gtk_clist_get_text(GTK_CLIST(clistqueue
), i
, 0, &temp
);
389 if (!strcmp(name
, temp
))
396 int find_queue_total_by_name(char *name
)
401 templist
= message_queue
;
404 struct queued_message
*qm
= (struct queued_message
*)templist
->data
;
405 if ((qm
->flags
& WFLAG_RECV
) && !strcmp(name
, qm
->name
))
408 templist
= templist
->next
;
414 struct queued_away_response
{
419 struct queued_away_response
*find_queued_away_response_by_name(char *name
)
422 struct queued_away_response
*qar
;
424 templist
= away_time_queue
;
427 qar
= (struct queued_away_response
*)templist
->data
;
429 if (!strcmp(name
, qar
->name
))
432 templist
= templist
->next
;
438 /* woo. i'm actually going to comment this function. isn't that fun. make sure to follow along, kids */
439 void serv_got_im(struct gaim_connection
*gc
, char *name
, char *message
, guint32 flags
, time_t mtime
, gint len
)
446 struct conversation
*cnv
;
449 /* pay no attention to the man behind the curtain.
451 * the reason i feel okay with this is because it's useful to some plugins.
452 * Gaim doesn't ever use it itself. Besides, it's not entirely accurate; it's
453 * possible to have false negatives with most protocols. Also with some it's
454 * easy to have false positives as well. So if you're a plugin author, don't
455 * rely on this, still do your own checks. but uh. it's a start. */
456 if (flags
& IM_FLAG_GAIMUSER
)
457 debug_printf("%s is a gaim user.\n", name
);
459 /* we should update the conversation window buttons and menu, if it exists. */
460 cnv
= find_conversation(name
);
462 set_convo_gc(cnv
, gc
);
463 /* we do the new_conv check here in case any plugins decide to create it */
467 /* plugin stuff. we pass a char ** but we don't want to pass what's been given us
468 * by the prpls. so we create temp holders and pass those instead. it's basically
469 * just to avoid segfaults. of course, if the data is binary, plugins don't see it.
470 * bitch all you want; i really don't want you to be dealing with it. */
472 buffy
= g_malloc(MAX(strlen(message
) + 1, BUF_LONG
));
473 strcpy(buffy
, message
);
474 angel
= g_strdup(name
);
475 plugin_return
= plugin_event(event_im_recv
, gc
, &angel
, &buffy
, (void *)flags
);
477 if (!buffy
|| !angel
|| plugin_return
) {
487 name
= g_strdup(name
);
488 message
= g_memdup(message
, len
);
491 /* TiK, using TOC, sends an automated message in order to get your away message. Now,
492 * this is one of the biggest hacks I think I've seen. But, in order to be nice to
493 * TiK, we're going to give users the option to ignore it. */
494 if ((away_options
& OPT_AWAY_TIK_HACK
) && gc
->away
&& strlen(gc
->away
) && (len
< 0) &&
495 !strcmp(message
, ">>>Automated Message: Getting Away Message<<<")) {
496 char *tmpmsg
= stylize(awaymessage
->message
, MSG_LEN
);
497 serv_send_im(gc
, name
, tmpmsg
, -1, IM_FLAG_AWAY
);
504 /* if you can't figure this out, stop reading right now.
505 * "we're not worthy! we're not worthy!" */
506 if ((len
< 0) && (convo_options
& OPT_CONVO_SEND_LINKS
))
507 linkify_text(message
);
509 /* um. when we call write_to_conv with the message we received, it's nice to pass whether
510 * or not it was an auto-response. so if it was an auto-response, we set the appropriate
511 * flag. this is just so prpls don't have to know about WFLAG_* (though some do anyway) */
512 if (flags
& IM_FLAG_AWAY
)
515 /* alright. two cases for how to handle this. either we're away or we're not. if we're not,
516 * then it's easy. if we are, then there are three or four different ways of handling it
517 * and different things we have to do for each. */
521 struct buddy
*b
= find_buddy(gc
, name
);
522 char *alias
= b
? b
->show
: name
;
524 struct queued_away_response
*qar
;
528 /* either we're going to queue it or not. Because of the way awayness currently
529 * works, this is fucked up. it's possible for an account to be away without the
530 * imaway dialog being shown. in fact, it's possible for *all* the accounts to be
531 * away without the imaway dialog being shown. so in order for this to be queued
532 * properly, we have to make sure that the imaway dialog actually exists, first. */
533 if (!cnv
&& clistqueue
&& (away_options
& OPT_AWAY_QUEUE
)) {
534 /* alright, so we're going to queue it. neat, eh? :) so first we create
535 * something to store the message, and add it to our queue. Then we update
536 * the away dialog to indicate that we've queued something. */
537 struct queued_message
*qm
;
539 qm
= g_new0(struct queued_message
, 1);
540 g_snprintf(qm
->name
, sizeof(qm
->name
), "%s", name
);
541 qm
->message
= g_memdup(message
, len
== -1 ? strlen(message
) + 1 : len
);
544 qm
->flags
= WFLAG_RECV
| away
;
546 message_queue
= g_slist_append(message_queue
, qm
);
549 set_user_state(away
);
552 row
= find_queue_row_by_name(qm
->name
);
558 qtotal
= find_queue_total_by_name(qm
->name
);
559 g_snprintf(number
, 32, _("(%d messages)"), qtotal
);
560 gtk_clist_set_text(GTK_CLIST(clistqueue
), row
, 1, number
);
565 heh
[1] = _("(1 message)");
566 gtk_clist_append(GTK_CLIST(clistqueue
), heh
);
569 /* ok, so we're not queuing it. well then, we'll try to handle it normally.
570 * Some people think that ignoring it is a perfectly acceptible way to handle
571 * it. i think they're on crack, but hey, that's why it's optional. */
572 if (away_options
& OPT_AWAY_DISCARD
) {
578 /* ok, so we're not ignoring it. make sure the conversation exists and is
579 * updated (partly handled above already), play the receive sound (sound.c
580 * will take care of not playing while away), and then write it to the
583 cnv
= new_conversation(name
);
584 set_convo_gc(cnv
, gc
);
586 if (new_conv
&& (sound_options
& OPT_SOUND_FIRST_RCV
))
587 play_sound(FIRST_RECEIVE
);
588 else if (cnv
->makesound
&& (sound_options
& OPT_SOUND_RECV
))
591 write_to_conv(cnv
, message
, away
| WFLAG_RECV
, NULL
, mtime
, len
);
594 /* regardless of whether we queue it or not, we should send an auto-response. That is,
595 * of course, unless the horse.... no wait. */
596 if ((away_options
& OPT_AWAY_NO_AUTO_RESP
) || !strlen(gc
->away
) ||
597 ((away_options
& OPT_AWAY_IDLE_RESP
) && !gc
->is_idle
)) {
603 /* this used to be based on the conversation window. but um, if you went away, and
604 * someone sent you a message and got your auto-response, and then you closed the
605 * window, and then the sent you another one, they'd get the auto-response back
606 * too soon. besides that, we need to keep track of this even if we've got a queue.
607 * so the rest of this block is just the auto-response, if necessary */
608 qar
= find_queued_away_response_by_name(name
);
610 qar
= (struct queued_away_response
*)g_new0(struct queued_away_response
, 1);
611 g_snprintf(qar
->name
, sizeof(qar
->name
), "%s", name
);
613 away_time_queue
= g_slist_append(away_time_queue
, qar
);
615 if ((t
- qar
->sent_away
) < away_resend
) {
622 /* apply default fonts and colors */
623 tmpmsg
= stylize(gc
->away
, MSG_LEN
);
624 serv_send_im(gc
, name
, away_subs(tmpmsg
, alias
), -1, IM_FLAG_AWAY
);
625 if (!cnv
&& clistqueue
&& (away_options
& OPT_AWAY_QUEUE
)) {
626 struct queued_message
*qm
;
627 qm
= g_new0(struct queued_message
, 1);
628 g_snprintf(qm
->name
, sizeof(qm
->name
), "%s", name
);
629 qm
->message
= g_strdup(away_subs(tmpmsg
, alias
));
632 qm
->flags
= WFLAG_SEND
| WFLAG_AUTO
;
634 message_queue
= g_slist_append(message_queue
, qm
);
635 } else if (cnv
!= NULL
)
636 write_to_conv(cnv
, away_subs(tmpmsg
, alias
), WFLAG_SEND
| WFLAG_AUTO
, NULL
,
640 /* we're not away. this is easy. if the convo window doesn't exist, create and update
641 * it (if it does exist it was updated earlier), then play a sound indicating we've
642 * received it and then display it. easy. */
644 cnv
= new_conversation(name
);
645 set_convo_gc(cnv
, gc
);
647 if (new_conv
&& (sound_options
& OPT_SOUND_FIRST_RCV
))
648 play_sound(FIRST_RECEIVE
);
649 else if (cnv
->makesound
&& (sound_options
& OPT_SOUND_RECV
))
652 set_convo_name(cnv
, name
);
654 write_to_conv(cnv
, message
, away
| WFLAG_RECV
, NULL
, mtime
, len
);
657 plugin_event(event_im_displayed_rcvd
, gc
, name
, message
, (void *)flags
);
664 void serv_got_update(struct gaim_connection
*gc
, char *name
, int loggedin
, int evil
, time_t signon
,
665 time_t idle
, int type
, guint caps
)
667 struct buddy
*b
= find_buddy(gc
, name
);
669 if (signon
&& (gc
->prpl
->options
& OPT_PROTO_CORRECT_TIME
)) {
670 char *tmp
= g_strdup(normalize(name
));
671 if (!g_strcasecmp(tmp
, normalize(gc
->username
))) {
673 gc
->correction_time
= (signon
- gc
->login_time
);
680 debug_printf("Error, no such buddy %s\n", name
);
684 /* This code will 'align' the name from the TOC */
685 /* server with what's in our record. We want to */
686 /* store things how THEY want it... */
687 if (strcmp(name
, b
->name
)) {
688 char *who
= g_strdup(b
->name
);
689 g_snprintf(b
->name
, sizeof(b
->name
), "%s", name
);
690 handle_buddy_rename(b
, who
);
694 if (!b
->idle
&& idle
) {
695 plugin_event(event_buddy_idle
, gc
, b
->name
, 0, 0);
696 system_log(log_idle
, gc
, b
, OPT_LOG_BUDDY_IDLE
);
698 if (b
->idle
&& !idle
) {
699 do_pounce(gc
, b
->name
, OPT_POUNCE_UNIDLE
);
700 plugin_event(event_buddy_unidle
, gc
, b
->name
, 0, 0);
701 system_log(log_unidle
, gc
, b
, OPT_LOG_BUDDY_IDLE
);
707 if ((b
->uc
& UC_UNAVAILABLE
) && !(type
& UC_UNAVAILABLE
)) {
708 do_pounce(gc
, b
->name
, OPT_POUNCE_UNAWAY
);
709 plugin_event(event_buddy_back
, gc
, b
->name
, 0, 0);
710 system_log(log_back
, gc
, b
, OPT_LOG_BUDDY_AWAY
);
711 } else if (!(b
->uc
& UC_UNAVAILABLE
) && (type
& UC_UNAVAILABLE
)) {
712 plugin_event(event_buddy_away
, gc
, b
->name
, 0, 0);
713 system_log(log_away
, gc
, b
, OPT_LOG_BUDDY_AWAY
);
725 do_pounce(gc
, b
->name
, OPT_POUNCE_SIGNON
);
726 plugin_event(event_buddy_signon
, gc
, b
->name
, 0, 0);
727 system_log(log_signon
, gc
, b
, OPT_LOG_BUDDY_SIGNON
);
731 plugin_event(event_buddy_signoff
, gc
, b
->name
, 0, 0);
732 system_log(log_signoff
, gc
, b
, OPT_LOG_BUDDY_SIGNON
);
741 void serv_got_eviled(struct gaim_connection
*gc
, char *name
, int lev
)
745 plugin_event(event_warned
, gc
, name
, (void *)lev
, 0);
747 if (gc
->evil
>= lev
) {
754 g_snprintf(buf2
, sizeof(buf2
), "%s has just been warned by %s.\nYour new warning level is %d%%",
755 gc
->username
, ((name
== NULL
)? "an anonymous person" : name
), lev
);
757 do_error_dialog(buf2
, _("Warned"));
760 void serv_got_typing(struct gaim_connection
*gc
, char *name
, int timeout
) {
761 struct conversation
*cnv
= find_conversation(name
);
763 set_convo_gc(cnv
, gc
);
766 plugin_event(event_got_typing
, gc
, name
, 0, 0);
767 do_pounce(gc
, name
, OPT_POUNCE_TYPING
);
769 if (cnv
->typing_timeout
)
770 gtk_timeout_remove (cnv
->typing_timeout
);
771 cnv
->typing_timeout
= gtk_timeout_add(timeout
* 1000,(GtkFunction
)reset_typing
,
776 void serv_got_typing_stopped(struct gaim_connection
*gc
, char *name
) {
777 struct conversation
*c
= find_conversation(name
);
778 if (c
&& c
->typing_timeout
) {
779 gtk_timeout_remove (c
->typing_timeout
);
781 reset_typing(g_strdup(name
));
784 static void close_invite(GtkWidget
*w
, GtkWidget
*w2
)
786 GList
*str
= gtk_object_get_user_data(GTK_OBJECT(w2
));
796 gtk_widget_destroy(w2
);
799 static void chat_invite_callback(GtkWidget
*w
, GtkWidget
*w2
)
801 struct gaim_connection
*g
= (struct gaim_connection
*)
802 gtk_object_get_user_data(GTK_OBJECT(GTK_DIALOG(w2
)->vbox
));
805 str
= gtk_object_get_user_data(GTK_OBJECT(w2
));
807 serv_join_chat(g
, str
);
812 /* this is either a g_malloc'd char* or g_malloc'd int* */
819 gtk_widget_destroy(w2
);
824 void serv_got_chat_invite(struct gaim_connection
*g
, char *name
, char *who
, char *message
, GList
*data
)
834 plugin_event(event_chat_invited
, g
, who
, name
, message
);
837 g_snprintf(buf2
, sizeof(buf2
), "User '%s' invites %s to buddy chat room: '%s'\n%s", who
,
838 g
->username
, name
, message
);
840 g_snprintf(buf2
, sizeof(buf2
), "User '%s' invites %s to buddy chat room: '%s'\n", who
,
843 d
= gtk_dialog_new();
844 gtk_widget_realize(d
);
848 label
= gtk_label_new(buf2
);
849 gtk_widget_show(label
);
850 yesbtn
= picture_button(d
, _("Yes"), ok_xpm
);
851 nobtn
= picture_button(d
, _("No"), cancel_xpm
);
852 gtk_widget_show(nobtn
);
853 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(d
)->vbox
), label
, FALSE
, FALSE
, 5);
854 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(d
)->action_area
), yesbtn
, FALSE
, FALSE
, 5);
855 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(d
)->action_area
), nobtn
, FALSE
, FALSE
, 5);
857 gtk_object_set_user_data(GTK_OBJECT(GTK_DIALOG(d
)->vbox
), g
);
858 gtk_object_set_user_data(GTK_OBJECT(d
), data
);
861 gtk_window_set_title(GTK_WINDOW(d
), "Buddy chat invite");
862 gtk_signal_connect(GTK_OBJECT(nobtn
), "clicked", GTK_SIGNAL_FUNC(close_invite
), d
);
863 gtk_signal_connect(GTK_OBJECT(yesbtn
), "clicked", GTK_SIGNAL_FUNC(chat_invite_callback
), d
);
869 struct conversation
*serv_got_joined_chat(struct gaim_connection
*gc
, int id
, char *name
)
871 struct conversation
*b
;
873 plugin_event(event_chat_join
, gc
, (void *)id
, name
, 0);
875 b
= (struct conversation
*)g_new0(struct conversation
, 1);
876 gc
->buddy_chats
= g_slist_append(gc
->buddy_chats
, b
);
877 chats
= g_list_append(chats
, b
);
884 b
->history
= g_string_new("");
885 g_snprintf(b
->name
, 80, "%s", name
);
887 if ((logging_options
& OPT_LOG_ALL
) || find_log_info(b
->name
)) {
891 filename
= (char *)malloc(100);
892 g_snprintf(filename
, 100, "%s.chat", b
->name
);
894 fd
= open_log_file(filename
);
896 if (!(logging_options
& OPT_LOG_STRIP_HTML
))
898 "<HR><BR><H3 Align=Center> ---- New Conversation @ %s ----</H3><BR>\n",
901 fprintf(fd
, "---- New Conversation @ %s ----\n", full_date());
908 show_new_buddy_chat(b
);
913 void serv_got_chat_left(struct gaim_connection
*g
, int id
)
915 GSList
*bcs
= g
->buddy_chats
;
916 struct conversation
*b
= NULL
;
920 b
= (struct conversation
*)bcs
->data
;
931 plugin_event(event_chat_leave
, g
, (void *)b
->id
, 0, 0);
933 debug_printf("Leaving room %s.\n", b
->name
);
935 g
->buddy_chats
= g_slist_remove(g
->buddy_chats
, b
);
940 void serv_got_chat_in(struct gaim_connection
*g
, int id
, char *who
, int whisper
, char *message
,
944 GSList
*bcs
= g
->buddy_chats
;
945 struct conversation
*b
= NULL
;
949 b
= (struct conversation
*)bcs
->data
;
959 if (plugin_event(event_chat_recv
, g
, (void *)b
->id
, who
, message
))
962 buf
= g_malloc(MAX(strlen(message
) * 2, 8192));
963 strcpy(buf
, message
);
965 if (convo_options
& OPT_CONVO_SEND_LINKS
)
973 chat_write(b
, who
, w
, buf
, mtime
);
977 static void des_popup(GtkWidget
*w
, GtkWidget
*window
)
980 char *u
= gtk_object_get_user_data(GTK_OBJECT(window
));
983 gtk_widget_destroy(window
);
986 void serv_got_popup(char *msg
, char *u
, int wid
, int hei
)
994 char *url
= g_strdup(u
);
997 gtk_window_set_wmclass(GTK_WINDOW(window
), "popup", "Gaim");
998 gtk_window_set_policy(GTK_WINDOW(window
), FALSE
, FALSE
, TRUE
);
999 gtk_window_set_title(GTK_WINDOW(window
), "Gaim - Popup");
1000 gtk_container_set_border_width(GTK_CONTAINER(window
), 5);
1001 gtk_signal_connect(GTK_OBJECT(window
), "destroy", GTK_SIGNAL_FUNC(des_popup
), window
);
1002 gtk_object_set_user_data(GTK_OBJECT(window
), url
);
1003 gtk_widget_realize(window
);
1004 aol_icon(window
->window
);
1006 vbox
= gtk_vbox_new(FALSE
, 5);
1007 gtk_container_add(GTK_CONTAINER(window
), vbox
);
1009 sw
= gtk_scrolled_window_new(NULL
, NULL
);
1010 gtk_widget_set_usize(sw
, wid
, hei
);
1011 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw
), GTK_POLICY_NEVER
, GTK_POLICY_ALWAYS
);
1012 gtk_box_pack_start(GTK_BOX(vbox
), sw
, TRUE
, TRUE
, 5);
1014 text
= gtk_imhtml_new(NULL
, NULL
);
1015 gtk_container_add(GTK_CONTAINER(sw
), text
);
1016 GTK_LAYOUT(text
)->hadjustment
->step_increment
= 10.0;
1017 GTK_LAYOUT(text
)->vadjustment
->step_increment
= 10.0;
1018 gaim_setup_imhtml(text
);
1020 hbox
= gtk_hbox_new(FALSE
, 5);
1021 gtk_box_pack_end(GTK_BOX(vbox
), hbox
, FALSE
, FALSE
, 5);
1023 button
= picture_button(window
, _("Close"), cancel_xpm
);
1024 gtk_box_pack_end(GTK_BOX(hbox
), button
, FALSE
, FALSE
, 5);
1025 gtk_signal_connect(GTK_OBJECT(button
), "clicked", GTK_SIGNAL_FUNC(des_popup
), window
);
1027 button
= picture_button(window
, _("More Info"), tb_search_xpm
);
1028 gtk_box_pack_end(GTK_BOX(hbox
), button
, FALSE
, FALSE
, 5);
1029 gtk_signal_connect(GTK_OBJECT(button
), "clicked", GTK_SIGNAL_FUNC(open_url
), url
);
1031 gtk_widget_show_all(window
);
1033 gtk_imhtml_append_text(GTK_IMHTML(text
), msg
, -1, GTK_IMHTML_NO_NEWLINE
);