[gaim-migrate @ 2985]
[pidgin-git.git] / src / away.c
blob4de9c98ca5fd31a16545e22c25ca30daca4cf64d
1 /*
2 * gaim
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
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #ifdef USE_APPLET
26 #include <gnome.h>
27 #include <applet-widget.h>
28 #include "applet.h"
29 #endif /* USE_APPLET */
30 #include <string.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <time.h>
35 #include <gtk/gtk.h>
36 #include "gaim.h"
37 #include "prpl.h"
38 #include "gtkimhtml.h"
39 #include "pixmaps/join.xpm"
41 GtkWidget *imaway = NULL;
43 GtkWidget *awaymenu = NULL;
44 GtkWidget *clistqueue = NULL;
45 GtkWidget *clistqueuesw;
47 struct away_message *awaymessage = NULL;
48 struct away_message *default_away;
49 int auto_away;
51 static void destroy_im_away()
53 if (imaway)
54 gtk_widget_destroy(imaway);
56 clistqueue = NULL;
57 clistqueuesw = NULL;
58 imaway = NULL;
61 void purge_away_queue()
63 struct conversation *cnv;
65 gtk_clist_freeze(GTK_CLIST(clistqueue));
66 gtk_clist_clear(GTK_CLIST(clistqueue));
68 while (message_queue) {
69 struct queued_message *qm = message_queue->data;
71 cnv = find_conversation(qm->name);
72 if (!cnv)
73 cnv = new_conversation(qm->name);
74 if (g_slist_index(connections, qm->gc) >= 0)
75 set_convo_gc(cnv, qm->gc);
77 write_to_conv(cnv, qm->message, qm->flags, NULL, qm->tm, qm->len);
79 message_queue = g_slist_remove(message_queue, qm);
81 g_free(qm->message);
82 g_free(qm);
85 gtk_clist_thaw(GTK_CLIST(clistqueue));
88 void dequeue_by_buddy(GtkWidget *clist, gint row, gint column, GdkEventButton *event, gpointer data) {
89 char *temp;
90 char *name;
91 GSList *templist;
92 struct conversation *cnv;
94 if(!(event->type == GDK_2BUTTON_PRESS && event->button == 1))
95 return; /* Double clicking on the clist will unqueue that users messages. */
97 gtk_clist_get_text(GTK_CLIST(clist), row, 0, &temp);
98 name = g_strdup(temp);
100 if (!name)
101 return;
102 debug_printf("Unqueueing messages from %s.\n", name);
103 templist = message_queue;
104 while (templist) {
105 struct queued_message *qm = templist->data;
106 if (templist->data) {
107 if (!g_strcasecmp(qm->name, name)) {
108 cnv = find_conversation(name);
109 if (!cnv)
110 cnv = new_conversation(qm->name);
111 if (g_slist_index(connections, qm->gc) >= 0)
112 set_convo_gc(cnv, qm->gc);
114 write_to_conv(cnv, qm->message, qm->flags, NULL, qm->tm, qm->len);
115 g_free(qm->message);
116 g_free(qm);
117 templist = message_queue = g_slist_remove(message_queue, qm);
119 } else {
120 templist = templist->next;
124 g_free(name);
125 gtk_clist_remove(GTK_CLIST(clist), row);
127 #ifdef USE_APPLET
128 set_user_state(away);
129 #endif
136 void toggle_away_queue()
138 if (!clistqueue || !clistqueuesw)
139 return;
141 if (away_options & OPT_AWAY_QUEUE) {
142 gtk_widget_show(clistqueue);
143 gtk_widget_show(clistqueuesw);
144 } else {
145 gtk_widget_hide(clistqueue);
146 gtk_widget_hide(clistqueuesw);
147 purge_away_queue();
151 void do_im_back(GtkWidget *w, GtkWidget *x)
153 if (imaway) {
154 GtkWidget *tmp = imaway;
156 purge_away_queue();
158 imaway = NULL;
159 gtk_widget_destroy(tmp);
160 if (w != tmp)
161 return;
164 while (away_time_queue) {
165 struct queued_away_response *qar = away_time_queue->data;
166 away_time_queue = g_slist_remove(away_time_queue, qar);
167 g_free(qar);
170 serv_set_away_all(NULL);
171 awaymessage = NULL;
172 clistqueue = NULL;
173 clistqueuesw = NULL;
174 #ifdef USE_APPLET
175 applet_widget_unregister_callback(APPLET_WIDGET(applet), "away");
176 set_user_state(online);
177 insert_applet_away();
178 #endif /* USE_APPLET */
182 void do_away_message(GtkWidget *w, struct away_message *a)
184 GtkWidget *back;
185 GtkWidget *awaytext;
186 GtkWidget *sw;
187 GtkWidget *vbox;
188 char *buf2;
189 char *buf;
191 if (!blist)
192 return;
194 if (!a)
195 return;
197 if (!imaway) {
198 GAIM_DIALOG(imaway);
199 gtk_window_set_wmclass(GTK_WINDOW(imaway), "imaway", "Gaim");
200 if (strlen(a->name))
201 gtk_window_set_title(GTK_WINDOW(imaway), a->name);
202 else
203 gtk_window_set_title(GTK_WINDOW(imaway), _("Gaim - Away!"));
204 gtk_signal_connect(GTK_OBJECT(imaway), "destroy", GTK_SIGNAL_FUNC(do_im_back), imaway);
205 gtk_widget_realize(imaway);
206 aol_icon(imaway->window);
208 vbox = gtk_vbox_new(FALSE, 5);
209 gtk_container_add(GTK_CONTAINER(imaway), vbox);
210 gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
211 gtk_widget_show(vbox);
213 sw = gtk_scrolled_window_new(NULL, NULL);
214 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER,
215 GTK_POLICY_ALWAYS);
216 gtk_widget_set_usize(sw, 245, 120);
217 gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0);
218 gtk_widget_show(sw);
220 awaytext = gtk_imhtml_new(NULL, NULL);
221 gtk_container_add(GTK_CONTAINER(sw), awaytext);
222 GTK_LAYOUT(awaytext)->hadjustment->step_increment = 10.0;
223 GTK_LAYOUT(awaytext)->vadjustment->step_increment = 10.0;
224 gaim_setup_imhtml(awaytext);
225 gtk_widget_show(awaytext);
226 buf = stylize(a->message, BUF_LONG);
227 gtk_imhtml_append_text(GTK_IMHTML(awaytext), buf, -1, GTK_IMHTML_NO_TITLE |
228 GTK_IMHTML_NO_COMMENTS | GTK_IMHTML_NO_SCROLL);
229 g_free(buf);
230 gtk_imhtml_append_text(GTK_IMHTML(awaytext), "<BR>", -1, GTK_IMHTML_NO_TITLE |
231 GTK_IMHTML_NO_COMMENTS | GTK_IMHTML_NO_SCROLL);
233 clistqueuesw = gtk_scrolled_window_new(NULL, NULL);
234 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clistqueuesw), GTK_POLICY_NEVER,
235 GTK_POLICY_AUTOMATIC);
236 gtk_box_pack_start(GTK_BOX(vbox), clistqueuesw, TRUE, TRUE, 0);
238 clistqueue = gtk_clist_new(2);
239 gtk_clist_set_column_width(GTK_CLIST(clistqueue), 0, 100);
240 gtk_widget_set_usize(GTK_WIDGET(clistqueue), -1, 50);
241 gtk_container_add(GTK_CONTAINER(clistqueuesw), clistqueue);
242 gtk_signal_connect(GTK_OBJECT(clistqueue), "select_row", GTK_SIGNAL_FUNC(dequeue_by_buddy), NULL);
246 if (away_options & OPT_AWAY_QUEUE) {
247 gtk_widget_show(clistqueuesw);
248 gtk_widget_show(clistqueue);
251 back = picture_button(imaway, _("I'm Back!"), join_xpm);
252 gtk_box_pack_start(GTK_BOX(vbox), back, FALSE, FALSE, 0);
253 gtk_signal_connect(GTK_OBJECT(back), "clicked", GTK_SIGNAL_FUNC(do_im_back), imaway);
254 gtk_window_set_focus(GTK_WINDOW(imaway), back);
256 awaymessage = a;
258 } else {
259 destroy_im_away();
260 do_away_message(w, a);
261 return;
264 #ifdef USE_APPLET
265 remove_applet_away();
266 applet_widget_register_callback(APPLET_WIDGET(applet),
267 "away", _("Back"), (AppletCallbackFunc)do_im_back, NULL);
268 set_user_state(away);
269 #endif
271 /* New away message... Clear out the old sent_aways */
272 while (away_time_queue) {
273 struct queued_away_response *qar = away_time_queue->data;
274 away_time_queue = g_slist_remove(away_time_queue, qar);
275 g_free(qar);
278 gtk_widget_show(imaway);
279 buf2 = g_malloc(strlen(awaymessage->message) * 4 + 1);
280 strncpy_withhtml(buf2, awaymessage->message, strlen(awaymessage->message) * 4 + 1);
281 serv_set_away_all(buf2);
282 g_free(buf2);
285 void rem_away_mess(GtkWidget *w, struct away_message *a)
287 int default_index;
288 #ifdef USE_APPLET
289 char *awayname;
290 awayname = g_malloc(sizeof(*awayname) * (6 + strlen(a->name)));
291 awayname[0] = '\0';
292 strcat(awayname, "away/");
293 strcat(awayname, a->name);
294 applet_widget_unregister_callback(APPLET_WIDGET(applet), awayname);
295 g_free(awayname);
296 #endif
297 default_index = g_slist_index(away_messages, default_away);
298 if (default_index == -1) {
299 if (away_messages != NULL)
300 default_away = away_messages->data;
301 else
302 default_away = NULL;
304 away_messages = g_slist_remove(away_messages, a);
305 g_free(a);
306 do_away_menu();
307 save_prefs();
310 static void set_gc_away(GtkObject *obj, struct gaim_connection *gc)
312 struct away_message *awy = gtk_object_get_user_data(obj);
314 if (awy)
315 serv_set_away(gc, GAIM_AWAY_CUSTOM, awy->message);
316 else
317 serv_set_away(gc, GAIM_AWAY_CUSTOM, NULL);
320 static void set_gc_state(GtkObject *obj, struct gaim_connection *gc)
322 char *awy = gtk_object_get_user_data(obj);
324 serv_set_away(gc, awy, NULL);
327 void do_away_menu()
329 GtkWidget *menuitem;
330 GtkWidget *remmenu;
331 GtkWidget *submenu, *submenu2;
332 GtkWidget *remitem;
333 GtkWidget *label;
334 GtkWidget *sep;
335 GList *l;
336 GtkWidget *list_item;
337 GSList *awy = away_messages;
338 struct away_message *a;
339 GSList *con = connections;
340 struct gaim_connection *gc = NULL;
341 int count = 0;
343 #ifdef USE_APPLET
344 remove_applet_away();
345 if (imaway && applet)
346 applet_widget_register_callback(APPLET_WIDGET(applet),
347 "away", _("Back"), (AppletCallbackFunc)do_im_back, NULL);
348 else if (applet && !imaway)
349 insert_applet_away();
350 #endif
352 if (prefs_away_list != NULL) {
353 GtkWidget *hbox;
354 gtk_list_clear_items(GTK_LIST(prefs_away_list), 0, -1);
355 while (awy) {
356 a = (struct away_message *)awy->data;
357 list_item = gtk_list_item_new();
358 gtk_container_add(GTK_CONTAINER(prefs_away_list), list_item);
359 gtk_signal_connect(GTK_OBJECT(list_item), "select",
360 GTK_SIGNAL_FUNC(away_list_clicked), a);
361 gtk_object_set_user_data(GTK_OBJECT(list_item), a);
362 gtk_widget_show(list_item);
364 hbox = gtk_hbox_new(FALSE, 5);
365 gtk_container_add(GTK_CONTAINER(list_item), hbox);
366 gtk_widget_show(hbox);
368 label = gtk_label_new(a->name);
369 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5);
370 gtk_widget_show(label);
372 awy = g_slist_next(awy);
374 if (away_messages != NULL)
375 gtk_list_select_item(GTK_LIST(prefs_away_list), 0);
378 if (awaymenu) {
379 l = gtk_container_children(GTK_CONTAINER(awaymenu));
381 while (l) {
382 gtk_container_remove(GTK_CONTAINER(awaymenu), GTK_WIDGET(l->data));
383 l = l->next;
387 remmenu = gtk_menu_new();
389 menuitem = gtk_menu_item_new_with_label(_("New Away Message"));
390 gtk_menu_append(GTK_MENU(awaymenu), menuitem);
391 gtk_widget_show(menuitem);
392 gtk_signal_connect(GTK_OBJECT(menuitem), "activate", GTK_SIGNAL_FUNC(create_away_mess),
393 NULL);
395 awy = away_messages;
396 while (awy) {
397 a = (struct away_message *)awy->data;
399 remitem = gtk_menu_item_new_with_label(a->name);
400 gtk_menu_append(GTK_MENU(remmenu), remitem);
401 gtk_widget_show(remitem);
402 gtk_signal_connect(GTK_OBJECT(remitem), "activate",
403 GTK_SIGNAL_FUNC(rem_away_mess), a);
405 awy = g_slist_next(awy);
409 menuitem = gtk_menu_item_new_with_label(_("Remove Away Message"));
410 gtk_menu_append(GTK_MENU(awaymenu), menuitem);
411 gtk_widget_show(menuitem);
412 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), remmenu);
413 gtk_widget_show(remmenu);
415 sep = gtk_hseparator_new();
416 menuitem = gtk_menu_item_new();
417 gtk_menu_append(GTK_MENU(awaymenu), menuitem);
418 gtk_container_add(GTK_CONTAINER(menuitem), sep);
419 gtk_widget_set_sensitive(menuitem, FALSE);
420 gtk_widget_show(menuitem);
421 gtk_widget_show(sep);
423 while (con) {
424 gc = con->data;
425 if (gc->prpl->away_states &&gc->prpl->set_away)
426 count++;
427 con = g_slist_next(con);
429 con = connections;
431 if (count == 0) {
432 } else if (count == 1) {
433 GList *msgs, *tmp;
434 while (con) {
435 gc = con->data;
436 if (gc->prpl->away_states &&gc->prpl->set_away)
437 break;
438 con = g_slist_next(con);
441 tmp = msgs = gc->prpl->away_states(gc);
443 if ((g_list_length(msgs) == 1) && !strcmp(msgs->data, GAIM_AWAY_CUSTOM)) {
444 awy = away_messages;
446 while (awy) {
447 a = (struct away_message *)awy->data;
449 menuitem = gtk_menu_item_new_with_label(a->name);
450 gtk_object_set_user_data(GTK_OBJECT(menuitem), a);
451 gtk_menu_append(GTK_MENU(awaymenu), menuitem);
452 gtk_widget_show(menuitem);
453 gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
454 GTK_SIGNAL_FUNC(do_away_message), a);
456 awy = g_slist_next(awy);
458 } else
459 while (msgs) {
460 awy = away_messages;
462 menuitem = gtk_menu_item_new_with_label(msgs->data);
463 gtk_object_set_user_data(GTK_OBJECT(menuitem), msgs->data);
464 gtk_menu_append(GTK_MENU(awaymenu), menuitem);
465 gtk_widget_show(menuitem);
467 if (strcmp(msgs->data, GAIM_AWAY_CUSTOM)) {
468 gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
469 GTK_SIGNAL_FUNC(set_gc_state), gc);
470 } else {
471 submenu = gtk_menu_new();
472 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem),
473 submenu);
474 gtk_widget_show(submenu);
476 while (awy) {
477 a = (struct away_message *)awy->data;
479 menuitem = gtk_menu_item_new_with_label(a->name);
480 gtk_object_set_user_data(GTK_OBJECT(menuitem),
482 gtk_menu_append(GTK_MENU(submenu), menuitem);
483 gtk_widget_show(menuitem);
484 gtk_signal_connect(GTK_OBJECT(menuitem),
485 "activate",
486 GTK_SIGNAL_FUNC
487 (do_away_message), a);
489 awy = g_slist_next(awy);
492 msgs = g_list_next(msgs);
495 g_list_free(tmp);
496 } else {
497 while (con) {
498 char buf[256];
499 GList *msgs, *tmp;
500 gc = con->data;
502 if (!gc->prpl->away_states ||!gc->prpl->set_away) {
503 con = con->next;
504 continue;
507 g_snprintf(buf, sizeof(buf), "%s (%s)",
508 gc->username, gc->prpl->name());
509 menuitem = gtk_menu_item_new_with_label(buf);
510 gtk_menu_append(GTK_MENU(awaymenu), menuitem);
511 gtk_widget_show(menuitem);
513 submenu = gtk_menu_new();
514 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
515 gtk_widget_show(submenu);
517 tmp = msgs = gc->prpl->away_states(gc);
519 if ((g_list_length(msgs) == 1) &&
520 (!strcmp(msgs->data, GAIM_AWAY_CUSTOM))) {
521 menuitem = gtk_menu_item_new_with_label(_("Back"));
522 gtk_menu_append(GTK_MENU(submenu), menuitem);
523 gtk_widget_show(menuitem);
524 gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
525 GTK_SIGNAL_FUNC(set_gc_away), gc);
527 sep = gtk_hseparator_new();
528 menuitem = gtk_menu_item_new();
529 gtk_menu_append(GTK_MENU(submenu), menuitem);
530 gtk_container_add(GTK_CONTAINER(menuitem), sep);
531 gtk_widget_set_sensitive(menuitem, FALSE);
532 gtk_widget_show(menuitem);
533 gtk_widget_show(sep);
535 awy = away_messages;
537 while (awy) {
538 a = (struct away_message *)awy->data;
540 menuitem = gtk_menu_item_new_with_label(a->name);
541 gtk_object_set_user_data(GTK_OBJECT(menuitem), a);
542 gtk_menu_append(GTK_MENU(submenu), menuitem);
543 gtk_widget_show(menuitem);
544 gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
545 GTK_SIGNAL_FUNC(set_gc_away), gc);
547 awy = g_slist_next(awy);
549 } else
550 while (msgs) {
551 awy = away_messages;
553 menuitem = gtk_menu_item_new_with_label(msgs->data);
554 gtk_object_set_user_data(GTK_OBJECT(menuitem),
555 msgs->data);
556 gtk_menu_append(GTK_MENU(submenu), menuitem);
557 gtk_widget_show(menuitem);
559 if (strcmp(msgs->data, GAIM_AWAY_CUSTOM)) {
560 gtk_signal_connect(GTK_OBJECT(menuitem),
561 "activate",
562 GTK_SIGNAL_FUNC(set_gc_state),
563 gc);
564 } else {
565 submenu2 = gtk_menu_new();
566 gtk_menu_item_set_submenu(GTK_MENU_ITEM
567 (menuitem), submenu2);
568 gtk_widget_show(submenu2);
570 while (awy) {
571 a = (struct away_message *)awy->data;
573 menuitem =
574 gtk_menu_item_new_with_label(a->
575 name);
576 gtk_object_set_user_data(GTK_OBJECT
577 (menuitem), a);
578 gtk_menu_append(GTK_MENU(submenu2),
579 menuitem);
580 gtk_widget_show(menuitem);
581 gtk_signal_connect(GTK_OBJECT(menuitem),
582 "activate",
583 GTK_SIGNAL_FUNC
584 (set_gc_away), gc);
586 awy = g_slist_next(awy);
589 msgs = g_list_next(msgs);
592 g_list_free(tmp);
594 con = g_slist_next(con);
597 menuitem = gtk_menu_item_new_with_label(_("Set All Away"));
598 gtk_menu_append(GTK_MENU(awaymenu), menuitem);
599 gtk_widget_show(menuitem);
601 submenu = gtk_menu_new();
602 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
603 gtk_widget_show(submenu);
605 awy = away_messages;
607 while (awy) {
608 a = (struct away_message *)awy->data;
610 menuitem = gtk_menu_item_new_with_label(a->name);
611 gtk_object_set_user_data(GTK_OBJECT(menuitem), a);
612 gtk_menu_append(GTK_MENU(submenu), menuitem);
613 gtk_widget_show(menuitem);
614 gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
615 GTK_SIGNAL_FUNC(do_away_message), a);
617 awy = g_slist_next(awy);
621 if (prefs_away_menu) {
622 l = gtk_container_children(GTK_CONTAINER(prefs_away_menu));
623 while (l) {
624 gtk_widget_destroy(GTK_WIDGET(l->data));
625 l = l->next;
627 gtk_widget_hide(GTK_WIDGET(prefs_away_menu));
628 default_away_menu_init(GTK_WIDGET(prefs_away_menu));
629 gtk_widget_show(prefs_away_menu);