Replace strcmp() with purple_strequal()
[pidgin-git.git] / pidgin / gtkaccount.c
blob0681734ceb64f797d7da2d81bff741627665c4a1
1 /**
2 * @file gtkaccount.c GTK+ Account Editor UI
3 * @ingroup pidgin
4 */
6 /* pidgin
8 * Pidgin is the legal property of its developers, whose names are too numerous
9 * to list here. Please refer to the COPYRIGHT file distributed with this
10 * source distribution.
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
27 #include "internal.h"
28 #include "pidgin.h"
30 #include "account.h"
31 #include "accountopt.h"
32 #include "core.h"
33 #include "debug.h"
34 #include "notify.h"
35 #include "plugin.h"
36 #include "prefs.h"
37 #include "prpl.h"
38 #include "request.h"
39 #include "savedstatuses.h"
40 #include "signals.h"
41 #include "util.h"
43 #include "gtkaccount.h"
44 #include "gtkblist.h"
45 #include "gtkdialogs.h"
46 #include "gtkutils.h"
47 #include "gtkstatusbox.h"
48 #include "pidginstock.h"
49 #include "minidialog.h"
51 enum
53 COLUMN_ICON,
54 COLUMN_BUDDYICON,
55 COLUMN_USERNAME,
56 COLUMN_ENABLED,
57 COLUMN_PROTOCOL,
58 COLUMN_DATA,
59 NUM_COLUMNS
62 typedef struct
64 PurpleAccount *account;
65 char *username;
66 char *alias;
68 } PidginAccountAddUserData;
70 typedef struct
72 GtkWidget *window;
73 GtkWidget *treeview;
75 GtkWidget *modify_button;
76 GtkWidget *delete_button;
77 GtkWidget *notebook;
79 GtkListStore *model;
80 GtkTreeIter drag_iter;
82 GtkTreeViewColumn *username_col;
84 } AccountsWindow;
86 typedef struct
88 GtkWidget *widget;
89 gchar *setting;
90 PurplePrefType type;
91 } ProtocolOptEntry;
93 typedef struct
95 PidginAccountDialogType type;
97 PurpleAccount *account;
98 char *protocol_id;
99 PurplePlugin *plugin;
100 PurplePluginProtocolInfo *prpl_info;
102 PurpleProxyType new_proxy_type;
104 GList *user_split_entries;
105 GList *protocol_opt_entries;
107 GtkSizeGroup *sg;
108 GtkWidget *window;
110 GtkWidget *notebook;
111 GtkWidget *top_vbox;
112 GtkWidget *ok_button;
113 GtkWidget *register_button;
115 /* Login Options */
116 GtkWidget *login_frame;
117 GtkWidget *protocol_menu;
118 GtkWidget *password_box;
119 GtkWidget *username_entry;
120 GtkWidget *password_entry;
121 GtkWidget *alias_entry;
122 GtkWidget *remember_pass_check;
124 /* User Options */
125 GtkWidget *user_frame;
126 GtkWidget *new_mail_check;
127 GtkWidget *icon_hbox;
128 GtkWidget *icon_check;
129 GtkWidget *icon_entry;
130 GtkWidget *icon_filesel;
131 GtkWidget *icon_preview;
132 GtkWidget *icon_text;
133 PurpleStoredImage *icon_img;
135 /* Protocol Options */
136 GtkWidget *protocol_frame;
138 /* Proxy Options */
139 GtkWidget *proxy_frame;
140 GtkWidget *proxy_vbox;
141 GtkWidget *proxy_dropdown;
142 GtkWidget *proxy_host_entry;
143 GtkWidget *proxy_port_entry;
144 GtkWidget *proxy_user_entry;
145 GtkWidget *proxy_pass_entry;
147 /* Voice & Video Options*/
148 GtkWidget *voice_frame;
149 GtkWidget *suppression_check;
151 } AccountPrefsDialog;
153 static AccountsWindow *accounts_window = NULL;
154 static GHashTable *account_pref_wins;
156 static void add_account_to_liststore(PurpleAccount *account, gpointer user_data);
157 static void set_account(GtkListStore *store, GtkTreeIter *iter,
158 PurpleAccount *account, GdkPixbuf *global_buddyicon);
160 /**************************************************************************
161 * Add/Modify Account dialog
162 **************************************************************************/
163 static void add_login_options(AccountPrefsDialog *dialog, GtkWidget *parent);
164 static void add_user_options(AccountPrefsDialog *dialog, GtkWidget *parent);
165 static void add_protocol_options(AccountPrefsDialog *dialog);
166 static void add_proxy_options(AccountPrefsDialog *dialog, GtkWidget *parent);
167 static void add_voice_options(AccountPrefsDialog *dialog);
169 static GtkWidget *
170 add_pref_box(AccountPrefsDialog *dialog, GtkWidget *parent,
171 const char *text, GtkWidget *widget)
173 return pidgin_add_widget_to_vbox(GTK_BOX(parent), text, dialog->sg, widget, TRUE, NULL);
176 static void
177 set_dialog_icon(AccountPrefsDialog *dialog, gpointer data, size_t len, gchar *new_icon_path)
179 GdkPixbuf *pixbuf = NULL;
181 dialog->icon_img = purple_imgstore_unref(dialog->icon_img);
182 if (data != NULL)
184 if (len > 0)
185 dialog->icon_img = purple_imgstore_add(data, len, new_icon_path);
186 else
187 g_free(data);
190 if (dialog->icon_img != NULL) {
191 pixbuf = pidgin_pixbuf_from_imgstore(dialog->icon_img);
194 if (pixbuf && dialog->prpl_info &&
195 (dialog->prpl_info->icon_spec.scale_rules & PURPLE_ICON_SCALE_DISPLAY))
197 /* Scale the icon to something reasonable */
198 int width, height;
199 GdkPixbuf *scale;
201 pidgin_buddy_icon_get_scale_size(pixbuf, &dialog->prpl_info->icon_spec,
202 PURPLE_ICON_SCALE_DISPLAY, &width, &height);
203 scale = gdk_pixbuf_scale_simple(pixbuf, width, height, GDK_INTERP_BILINEAR);
205 g_object_unref(G_OBJECT(pixbuf));
206 pixbuf = scale;
209 if (pixbuf == NULL)
211 /* Show a placeholder icon */
212 GtkIconSize icon_size = gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_SMALL);
213 pixbuf = gtk_widget_render_icon(dialog->window, PIDGIN_STOCK_TOOLBAR_SELECT_AVATAR,
214 icon_size, "PidginAccount");
217 gtk_image_set_from_pixbuf(GTK_IMAGE(dialog->icon_entry), pixbuf);
218 if (pixbuf != NULL)
219 g_object_unref(G_OBJECT(pixbuf));
222 static void
223 set_account_protocol_cb(GtkWidget *item, const char *id,
224 AccountPrefsDialog *dialog)
226 PurplePlugin *new_plugin;
228 new_plugin = purple_find_prpl(id);
230 dialog->plugin = new_plugin;
232 if (dialog->plugin != NULL)
234 PurplePlugin *old_plugin = NULL;
236 dialog->prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(dialog->plugin);
238 if (dialog->protocol_id)
239 old_plugin = purple_find_prpl(dialog->protocol_id);
241 if (old_plugin != new_plugin) {
242 g_free(dialog->protocol_id);
243 dialog->protocol_id = g_strdup(dialog->plugin->info->id);
247 if (dialog->account != NULL)
248 purple_account_clear_settings(dialog->account);
250 add_login_options(dialog, dialog->top_vbox);
251 add_user_options(dialog, dialog->top_vbox);
252 add_protocol_options(dialog);
253 add_voice_options(dialog);
255 gtk_widget_grab_focus(dialog->protocol_menu);
257 if (!dialog->prpl_info || !dialog->prpl_info->register_user ||
258 g_object_get_data(G_OBJECT(item), "fake")) {
259 gtk_widget_hide(dialog->register_button);
260 } else {
261 if (dialog->prpl_info != NULL &&
262 (dialog->prpl_info->options & OPT_PROTO_REGISTER_NOSCREENNAME)) {
263 gtk_widget_set_sensitive(dialog->register_button, TRUE);
264 } else {
265 gtk_widget_set_sensitive(dialog->register_button, FALSE);
267 gtk_widget_show(dialog->register_button);
271 static gboolean
272 username_focus_cb(GtkWidget *widget, GdkEventFocus *event, AccountPrefsDialog *dialog)
274 GHashTable *table;
275 const char *label;
277 table = dialog->prpl_info->get_account_text_table(NULL);
278 label = g_hash_table_lookup(table, "login_label");
280 if(purple_strequal(gtk_entry_get_text(GTK_ENTRY(widget)), label)) {
281 gtk_entry_set_text(GTK_ENTRY(widget), "");
282 gtk_widget_modify_text(widget, GTK_STATE_NORMAL,NULL);
285 g_hash_table_destroy(table);
287 return FALSE;
290 static void
291 username_changed_cb(GtkEntry *entry, AccountPrefsDialog *dialog)
293 if (dialog->ok_button)
294 gtk_widget_set_sensitive(dialog->ok_button,
295 *gtk_entry_get_text(entry) != '\0');
296 if (dialog->register_button) {
297 if (dialog->prpl_info != NULL && (dialog->prpl_info->options & OPT_PROTO_REGISTER_NOSCREENNAME))
298 gtk_widget_set_sensitive(dialog->register_button, TRUE);
299 else
300 gtk_widget_set_sensitive(dialog->register_button,
301 *gtk_entry_get_text(entry) != '\0');
305 static gboolean
306 username_nofocus_cb(GtkWidget *widget, GdkEventFocus *event, AccountPrefsDialog *dialog)
308 GdkColor color = {0, 34952, 35466, 34181};
309 GHashTable *table = NULL;
310 const char *label = NULL;
312 if(PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(dialog->prpl_info, get_account_text_table)) {
313 table = dialog->prpl_info->get_account_text_table(NULL);
314 label = g_hash_table_lookup(table, "login_label");
316 if (*gtk_entry_get_text(GTK_ENTRY(widget)) == '\0') {
317 /* We have to avoid hitting the username_changed_cb function
318 * because it enables buttons we don't want enabled yet ;)
320 g_signal_handlers_block_by_func(widget, G_CALLBACK(username_changed_cb), dialog);
321 gtk_entry_set_text(GTK_ENTRY(widget), label);
322 /* Make sure we can hit it again */
323 g_signal_handlers_unblock_by_func(widget, G_CALLBACK(username_changed_cb), dialog);
324 gtk_widget_modify_text(widget, GTK_STATE_NORMAL, &color);
327 g_hash_table_destroy(table);
330 return FALSE;
333 static void
334 icon_filesel_choose_cb(const char *filename, gpointer data)
336 AccountPrefsDialog *dialog = data;
338 if (filename != NULL)
340 size_t len;
341 gpointer data = pidgin_convert_buddy_icon(dialog->plugin, filename, &len);
342 set_dialog_icon(dialog, data, len, g_strdup(filename));
345 dialog->icon_filesel = NULL;
348 static void
349 icon_select_cb(GtkWidget *button, AccountPrefsDialog *dialog)
351 dialog->icon_filesel = pidgin_buddy_icon_chooser_new(GTK_WINDOW(dialog->window), icon_filesel_choose_cb, dialog);
352 gtk_widget_show_all(dialog->icon_filesel);
355 static void
356 icon_reset_cb(GtkWidget *button, AccountPrefsDialog *dialog)
358 set_dialog_icon(dialog, NULL, 0, NULL);
361 static void
362 account_dnd_recv(GtkWidget *widget, GdkDragContext *dc, gint x, gint y,
363 GtkSelectionData *sd, guint info, guint t, AccountPrefsDialog *dialog)
365 gchar *name = (gchar *)sd->data;
367 if ((sd->length >= 0) && (sd->format == 8)) {
368 /* Well, it looks like the drag event was cool.
369 * Let's do something with it */
370 if (!g_ascii_strncasecmp(name, "file://", 7)) {
371 GError *converr = NULL;
372 gchar *tmp, *rtmp;
373 gpointer data;
374 size_t len;
376 /* It looks like we're dealing with a local file. */
377 if(!(tmp = g_filename_from_uri(name, NULL, &converr))) {
378 purple_debug(PURPLE_DEBUG_ERROR, "buddyicon", "%s\n",
379 (converr ? converr->message :
380 "g_filename_from_uri error"));
381 return;
383 if ((rtmp = strchr(tmp, '\r')) || (rtmp = strchr(tmp, '\n')))
384 *rtmp = '\0';
386 data = pidgin_convert_buddy_icon(dialog->plugin, tmp, &len);
387 /* This takes ownership of tmp */
388 set_dialog_icon(dialog, data, len, tmp);
390 gtk_drag_finish(dc, TRUE, FALSE, t);
392 gtk_drag_finish(dc, FALSE, FALSE, t);
395 static void
396 update_editable(PurpleConnection *gc, AccountPrefsDialog *dialog)
398 GtkStyle *style;
399 gboolean set;
400 GList *l;
402 if (dialog->account == NULL)
403 return;
405 if (gc != NULL && dialog->account != purple_connection_get_account(gc))
406 return;
408 set = !(purple_account_is_connected(dialog->account) || purple_account_is_connecting(dialog->account));
409 gtk_widget_set_sensitive(dialog->protocol_menu, set);
410 gtk_editable_set_editable(GTK_EDITABLE(dialog->username_entry), set);
411 style = set ? NULL : gtk_widget_get_style(dialog->username_entry);
412 gtk_widget_modify_base(dialog->username_entry, GTK_STATE_NORMAL,
413 style ? &style->base[GTK_STATE_INSENSITIVE] : NULL);
415 for (l = dialog->user_split_entries ; l != NULL ; l = l->next) {
416 if (GTK_IS_EDITABLE(l->data)) {
417 gtk_editable_set_editable(GTK_EDITABLE(l->data), set);
418 style = set ? NULL : gtk_widget_get_style(GTK_WIDGET(l->data));
419 gtk_widget_modify_base(GTK_WIDGET(l->data), GTK_STATE_NORMAL,
420 style ? &style->base[GTK_STATE_INSENSITIVE] : NULL);
421 } else {
422 gtk_widget_set_sensitive(GTK_WIDGET(l->data), set);
427 static void
428 add_login_options(AccountPrefsDialog *dialog, GtkWidget *parent)
430 GtkWidget *frame;
431 GtkWidget *hbox;
432 GtkWidget *vbox;
433 GtkWidget *entry;
434 GtkWidget *menu;
435 GtkWidget *item;
436 GList *user_splits;
437 GList *l, *l2;
438 char *username = NULL;
440 if (dialog->protocol_menu != NULL)
442 #if GTK_CHECK_VERSION(2,12,0)
443 g_object_ref(G_OBJECT(dialog->protocol_menu));
444 #else
445 gtk_widget_ref(dialog->protocol_menu);
446 #endif
447 hbox = g_object_get_data(G_OBJECT(dialog->protocol_menu), "container");
448 gtk_container_remove(GTK_CONTAINER(hbox), dialog->protocol_menu);
451 if (dialog->login_frame != NULL)
452 gtk_widget_destroy(dialog->login_frame);
454 /* Build the login options frame. */
455 frame = pidgin_make_frame(parent, _("Login Options"));
457 /* cringe */
458 dialog->login_frame = gtk_widget_get_parent(gtk_widget_get_parent(frame));
460 gtk_box_reorder_child(GTK_BOX(parent), dialog->login_frame, 0);
461 gtk_widget_show(dialog->login_frame);
463 /* Main vbox */
464 vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
465 gtk_container_add(GTK_CONTAINER(frame), vbox);
466 gtk_widget_show(vbox);
468 /* Protocol */
469 if (dialog->protocol_menu == NULL)
471 dialog->protocol_menu = pidgin_protocol_option_menu_new(
472 dialog->protocol_id, G_CALLBACK(set_account_protocol_cb), dialog);
473 #if GTK_CHECK_VERSION(2,12,0)
474 g_object_ref(G_OBJECT(dialog->protocol_menu));
475 #else
476 gtk_widget_ref(dialog->protocol_menu);
477 #endif
480 hbox = add_pref_box(dialog, vbox, _("Pro_tocol:"), dialog->protocol_menu);
481 g_object_set_data(G_OBJECT(dialog->protocol_menu), "container", hbox);
483 #if GTK_CHECK_VERSION(2,12,0)
484 g_object_unref(G_OBJECT(dialog->protocol_menu));
485 #else
486 gtk_widget_unref(dialog->protocol_menu);
487 #endif
489 /* Username */
490 dialog->username_entry = gtk_entry_new();
491 g_object_set(G_OBJECT(dialog->username_entry), "truncate-multiline", TRUE, NULL);
493 add_pref_box(dialog, vbox, _("_Username:"), dialog->username_entry);
495 if (dialog->account != NULL)
496 username = g_strdup(purple_account_get_username(dialog->account));
498 if (!username && dialog->prpl_info
499 && PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(dialog->prpl_info, get_account_text_table)) {
500 GdkColor color = {0, 34952, 35466, 34181};
501 GHashTable *table;
502 const char *label;
503 table = dialog->prpl_info->get_account_text_table(NULL);
504 label = g_hash_table_lookup(table, "login_label");
506 gtk_entry_set_text(GTK_ENTRY(dialog->username_entry), label);
507 g_signal_connect(G_OBJECT(dialog->username_entry), "focus-in-event",
508 G_CALLBACK(username_focus_cb), dialog);
509 g_signal_connect(G_OBJECT(dialog->username_entry), "focus-out-event",
510 G_CALLBACK(username_nofocus_cb), dialog);
511 gtk_widget_modify_text(dialog->username_entry, GTK_STATE_NORMAL, &color);
512 g_hash_table_destroy(table);
515 g_signal_connect(G_OBJECT(dialog->username_entry), "changed",
516 G_CALLBACK(username_changed_cb), dialog);
518 /* Do the user split thang */
519 if (dialog->prpl_info == NULL)
520 user_splits = NULL;
521 else
522 user_splits = dialog->prpl_info->user_splits;
524 if (dialog->user_split_entries != NULL) {
525 g_list_free(dialog->user_split_entries);
526 dialog->user_split_entries = NULL;
529 for (l = user_splits; l != NULL; l = l->next) {
530 PurpleAccountUserSplit *split = l->data;
531 char *buf;
533 buf = g_strdup_printf("_%s:", purple_account_user_split_get_text(split));
535 entry = gtk_entry_new();
537 add_pref_box(dialog, vbox, buf, entry);
539 g_free(buf);
541 dialog->user_split_entries =
542 g_list_append(dialog->user_split_entries, entry);
545 for (l = g_list_last(dialog->user_split_entries),
546 l2 = g_list_last(user_splits);
547 l != NULL && l2 != NULL;
548 l = l->prev, l2 = l2->prev) {
550 GtkWidget *entry = l->data;
551 PurpleAccountUserSplit *split = l2->data;
552 const char *value = NULL;
553 char *c;
555 if (dialog->account != NULL) {
556 if(purple_account_user_split_get_reverse(split))
557 c = strrchr(username,
558 purple_account_user_split_get_separator(split));
559 else
560 c = strchr(username,
561 purple_account_user_split_get_separator(split));
563 if (c != NULL) {
564 *c = '\0';
565 c++;
567 value = c;
570 if (value == NULL)
571 value = purple_account_user_split_get_default_value(split);
573 /* Google Talk default domain hackery! */
574 menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(dialog->protocol_menu));
575 item = gtk_menu_get_active(GTK_MENU(menu));
576 if (value == NULL && g_object_get_data(G_OBJECT(item), "fakegoogle") &&
577 purple_strequal(purple_account_user_split_get_text(split), _("Domain")))
578 value = "gmail.com";
580 if (value != NULL)
581 gtk_entry_set_text(GTK_ENTRY(entry), value);
584 if (username != NULL)
585 gtk_entry_set_text(GTK_ENTRY(dialog->username_entry), username);
587 g_free(username);
590 /* Password */
591 dialog->password_entry = gtk_entry_new();
592 gtk_entry_set_visibility(GTK_ENTRY(dialog->password_entry), FALSE);
593 #if !GTK_CHECK_VERSION(2,16,0)
594 if (gtk_entry_get_invisible_char(GTK_ENTRY(dialog->password_entry)) == '*')
595 gtk_entry_set_invisible_char(GTK_ENTRY(dialog->password_entry), PIDGIN_INVISIBLE_CHAR);
596 #endif /* Less than GTK+ 2.16 */
597 dialog->password_box = add_pref_box(dialog, vbox, _("_Password:"),
598 dialog->password_entry);
600 /* Remember Password */
601 dialog->remember_pass_check =
602 gtk_check_button_new_with_mnemonic(_("Remember pass_word"));
603 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->remember_pass_check),
604 FALSE);
605 gtk_box_pack_start(GTK_BOX(vbox), dialog->remember_pass_check,
606 FALSE, FALSE, 0);
607 gtk_widget_show(dialog->remember_pass_check);
609 /* Set the fields. */
610 if (dialog->account != NULL) {
611 if (purple_account_get_password(dialog->account) &&
612 purple_account_get_remember_password(dialog->account))
613 gtk_entry_set_text(GTK_ENTRY(dialog->password_entry),
614 purple_account_get_password(dialog->account));
616 gtk_toggle_button_set_active(
617 GTK_TOGGLE_BUTTON(dialog->remember_pass_check),
618 purple_account_get_remember_password(dialog->account));
621 if (dialog->prpl_info != NULL &&
622 (dialog->prpl_info->options & OPT_PROTO_NO_PASSWORD)) {
624 gtk_widget_hide(dialog->password_box);
625 gtk_widget_hide(dialog->remember_pass_check);
628 /* Do not let the user change the protocol/username while connected. */
629 update_editable(NULL, dialog);
630 purple_signal_connect(purple_connections_get_handle(), "signing-on", dialog,
631 G_CALLBACK(update_editable), dialog);
632 purple_signal_connect(purple_connections_get_handle(), "signed-off", dialog,
633 G_CALLBACK(update_editable), dialog);
636 static void
637 icon_check_cb(GtkWidget *checkbox, AccountPrefsDialog *dialog)
639 gtk_widget_set_sensitive(dialog->icon_hbox, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->icon_check)));
642 static void
643 add_user_options(AccountPrefsDialog *dialog, GtkWidget *parent)
645 GtkWidget *frame;
646 GtkWidget *vbox;
647 GtkWidget *vbox2;
648 GtkWidget *hbox;
649 GtkWidget *hbox2;
650 GtkWidget *button;
651 GtkWidget *label;
653 if (dialog->user_frame != NULL)
654 gtk_widget_destroy(dialog->user_frame);
656 /* Build the user options frame. */
657 frame = pidgin_make_frame(parent, _("User Options"));
658 dialog->user_frame = gtk_widget_get_parent(gtk_widget_get_parent(frame));
660 gtk_box_reorder_child(GTK_BOX(parent), dialog->user_frame, 1);
661 gtk_widget_show(dialog->user_frame);
663 /* Main vbox */
664 vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
665 gtk_container_add(GTK_CONTAINER(frame), vbox);
666 gtk_widget_show(vbox);
668 /* Alias */
669 dialog->alias_entry = gtk_entry_new();
670 add_pref_box(dialog, vbox, _("_Local alias:"), dialog->alias_entry);
672 /* New mail notifications */
673 dialog->new_mail_check =
674 gtk_check_button_new_with_mnemonic(_("New _mail notifications"));
675 gtk_box_pack_start(GTK_BOX(vbox), dialog->new_mail_check, FALSE, FALSE, 0);
676 gtk_widget_show(dialog->new_mail_check);
678 /* Buddy icon */
679 dialog->icon_check = gtk_check_button_new_with_mnemonic(_("Use this buddy _icon for this account:"));
680 g_signal_connect(G_OBJECT(dialog->icon_check), "toggled", G_CALLBACK(icon_check_cb), dialog);
681 gtk_widget_show(dialog->icon_check);
682 gtk_box_pack_start(GTK_BOX(vbox), dialog->icon_check, FALSE, FALSE, 0);
684 dialog->icon_hbox = hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
685 gtk_widget_set_sensitive(hbox, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->icon_check)));
686 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
687 gtk_widget_show(hbox);
689 label = gtk_label_new(" ");
690 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
691 gtk_widget_show(label);
693 button = gtk_button_new();
694 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
695 gtk_widget_show(button);
696 g_signal_connect(G_OBJECT(button), "clicked",
697 G_CALLBACK(icon_select_cb), dialog);
699 dialog->icon_entry = gtk_image_new();
700 gtk_container_add(GTK_CONTAINER(button), dialog->icon_entry);
701 gtk_widget_show(dialog->icon_entry);
702 /* TODO: Uh, isn't this next line pretty useless? */
703 pidgin_set_accessible_label (dialog->icon_entry, label);
704 purple_imgstore_unref(dialog->icon_img);
705 dialog->icon_img = NULL;
707 vbox2 = gtk_vbox_new(FALSE, 0);
708 gtk_box_pack_start(GTK_BOX(hbox), vbox2, TRUE, TRUE, 0);
709 gtk_widget_show(vbox2);
711 hbox2 = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
712 gtk_box_pack_start(GTK_BOX(vbox2), hbox2, FALSE, FALSE, PIDGIN_HIG_BORDER);
713 gtk_widget_show(hbox2);
715 button = gtk_button_new_from_stock(GTK_STOCK_REMOVE);
716 g_signal_connect(G_OBJECT(button), "clicked",
717 G_CALLBACK(icon_reset_cb), dialog);
718 gtk_box_pack_start(GTK_BOX(hbox2), button, FALSE, FALSE, 0);
719 gtk_widget_show(button);
721 if (dialog->prpl_info != NULL) {
722 if (!(dialog->prpl_info->options & OPT_PROTO_MAIL_CHECK))
723 gtk_widget_hide(dialog->new_mail_check);
725 if (dialog->prpl_info->icon_spec.format == NULL) {
726 gtk_widget_hide(dialog->icon_check);
727 gtk_widget_hide(dialog->icon_hbox);
731 if (dialog->account != NULL) {
732 PurpleStoredImage *img;
733 gpointer data = NULL;
734 size_t len = 0;
736 if (purple_account_get_alias(dialog->account))
737 gtk_entry_set_text(GTK_ENTRY(dialog->alias_entry),
738 purple_account_get_alias(dialog->account));
740 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->new_mail_check),
741 purple_account_get_check_mail(dialog->account));
743 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->icon_check),
744 !purple_account_get_bool(dialog->account, "use-global-buddyicon",
745 TRUE));
747 img = purple_buddy_icons_find_account_icon(dialog->account);
748 if (img)
750 len = purple_imgstore_get_size(img);
751 data = g_memdup(purple_imgstore_get_data(img), len);
753 set_dialog_icon(dialog, data, len,
754 g_strdup(purple_account_get_buddy_icon_path(dialog->account)));
755 } else {
756 set_dialog_icon(dialog, NULL, 0, NULL);
759 #if 0
760 if (!dialog->prpl_info ||
761 (!(dialog->prpl_info->options & OPT_PROTO_MAIL_CHECK) &&
762 (dialog->prpl_info->icon_spec.format == NULL))) {
764 /* Nothing to see :( aww. */
765 gtk_widget_hide(dialog->user_frame);
767 #endif
770 static void
771 add_protocol_options(AccountPrefsDialog *dialog)
773 PurpleAccountOption *option;
774 PurpleAccount *account;
775 GtkWidget *vbox, *check, *entry, *combo;
776 GList *list, *node;
777 gint i, idx, int_value;
778 GtkListStore *model;
779 GtkTreeIter iter;
780 GtkCellRenderer *renderer;
781 PurpleKeyValuePair *kvp;
782 GList *l;
783 char buf[1024];
784 char *title, *tmp;
785 const char *str_value;
786 gboolean bool_value;
787 ProtocolOptEntry *opt_entry;
789 if (dialog->protocol_frame != NULL) {
790 gtk_notebook_remove_page (GTK_NOTEBOOK(dialog->notebook), 1);
791 dialog->protocol_frame = NULL;
794 while (dialog->protocol_opt_entries != NULL) {
795 ProtocolOptEntry *opt_entry = dialog->protocol_opt_entries->data;
796 g_free(opt_entry->setting);
797 g_free(opt_entry);
798 dialog->protocol_opt_entries = g_list_delete_link(dialog->protocol_opt_entries, dialog->protocol_opt_entries);
801 if (dialog->prpl_info == NULL ||
802 dialog->prpl_info->protocol_options == NULL)
803 return;
805 account = dialog->account;
807 /* Main vbox */
808 dialog->protocol_frame = vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
809 gtk_container_set_border_width(GTK_CONTAINER(vbox), PIDGIN_HIG_BORDER);
810 gtk_notebook_insert_page(GTK_NOTEBOOK(dialog->notebook), vbox,
811 gtk_label_new_with_mnemonic(_("Ad_vanced")), 1);
812 gtk_widget_show(vbox);
814 for (l = dialog->prpl_info->protocol_options; l != NULL; l = l->next)
816 option = (PurpleAccountOption *)l->data;
818 opt_entry = g_new0(ProtocolOptEntry, 1);
819 opt_entry->type = purple_account_option_get_type(option);
820 opt_entry->setting = g_strdup(purple_account_option_get_setting(option));
822 switch (opt_entry->type)
824 case PURPLE_PREF_BOOLEAN:
825 if (account == NULL ||
826 !purple_strequal(purple_account_get_protocol_id(account),
827 dialog->protocol_id))
829 bool_value = purple_account_option_get_default_bool(option);
831 else
833 bool_value = purple_account_get_bool(account,
834 purple_account_option_get_setting(option),
835 purple_account_option_get_default_bool(option));
838 tmp = g_strconcat("_", purple_account_option_get_text(option), NULL);
839 opt_entry->widget = check = gtk_check_button_new_with_mnemonic(tmp);
840 g_free(tmp);
842 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check),
843 bool_value);
845 gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0);
846 gtk_widget_show(check);
847 break;
849 case PURPLE_PREF_INT:
850 if (account == NULL ||
851 !purple_strequal(purple_account_get_protocol_id(account),
852 dialog->protocol_id))
854 int_value = purple_account_option_get_default_int(option);
856 else
858 int_value = purple_account_get_int(account,
859 purple_account_option_get_setting(option),
860 purple_account_option_get_default_int(option));
863 g_snprintf(buf, sizeof(buf), "%d", int_value);
865 opt_entry->widget = entry = gtk_entry_new();
866 gtk_entry_set_text(GTK_ENTRY(entry), buf);
868 title = g_strdup_printf("_%s:",
869 purple_account_option_get_text(option));
870 add_pref_box(dialog, vbox, title, entry);
871 g_free(title);
872 break;
874 case PURPLE_PREF_STRING:
875 if (account == NULL ||
876 !purple_strequal(purple_account_get_protocol_id(account),
877 dialog->protocol_id))
879 str_value = purple_account_option_get_default_string(option);
881 else
883 str_value = purple_account_get_string(account,
884 purple_account_option_get_setting(option),
885 purple_account_option_get_default_string(option));
888 opt_entry->widget = entry = gtk_entry_new();
889 if (purple_account_option_get_masked(option))
891 gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
892 #if !GTK_CHECK_VERSION(2,16,0)
893 if (gtk_entry_get_invisible_char(GTK_ENTRY(entry)) == '*')
894 gtk_entry_set_invisible_char(GTK_ENTRY(entry), PIDGIN_INVISIBLE_CHAR);
895 #endif /* Less than GTK+ 2.16 */
898 if (str_value != NULL)
899 gtk_entry_set_text(GTK_ENTRY(entry), str_value);
901 title = g_strdup_printf("_%s:",
902 purple_account_option_get_text(option));
903 add_pref_box(dialog, vbox, title, entry);
904 g_free(title);
905 break;
907 case PURPLE_PREF_STRING_LIST:
908 i = 0;
909 idx = 0;
911 if (account == NULL ||
912 !purple_strequal(purple_account_get_protocol_id(account),
913 dialog->protocol_id))
915 str_value = purple_account_option_get_default_list_value(option);
917 else
919 str_value = purple_account_get_string(account,
920 purple_account_option_get_setting(option),
921 purple_account_option_get_default_list_value(option));
924 list = purple_account_option_get_list(option);
925 model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
926 opt_entry->widget = combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(model));
928 /* Loop through list of PurpleKeyValuePair items */
929 for (node = list; node != NULL; node = node->next) {
930 if (node->data != NULL) {
931 kvp = (PurpleKeyValuePair *) node->data;
932 if ((kvp->value != NULL) && (str_value != NULL) &&
933 !g_utf8_collate(kvp->value, str_value))
934 idx = i;
936 gtk_list_store_append(model, &iter);
937 gtk_list_store_set(model, &iter,
938 0, kvp->key,
939 1, kvp->value,
940 -1);
943 i++;
946 /* Set default */
947 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), idx);
949 /* Define renderer */
950 renderer = gtk_cell_renderer_text_new();
951 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), renderer,
952 TRUE);
953 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo),
954 renderer, "text", 0, NULL);
956 title = g_strdup_printf("_%s:",
957 purple_account_option_get_text(option));
958 add_pref_box(dialog, vbox, title, combo);
959 g_free(title);
960 break;
962 default:
963 purple_debug_error("gtkaccount", "Invalid Account Option pref type (%d)\n",
964 opt_entry->type);
965 g_free(opt_entry->setting);
966 g_free(opt_entry);
967 continue;
970 dialog->protocol_opt_entries =
971 g_list_append(dialog->protocol_opt_entries, opt_entry);
976 static GtkWidget *
977 make_proxy_dropdown(void)
979 GtkWidget *dropdown;
980 GtkListStore *model;
981 GtkTreeIter iter;
982 GtkCellRenderer *renderer;
984 model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
985 dropdown = gtk_combo_box_new_with_model(GTK_TREE_MODEL(model));
987 gtk_list_store_append(model, &iter);
988 gtk_list_store_set(model, &iter,
989 0, purple_running_gnome() ? _("Use GNOME Proxy Settings")
990 :_("Use Global Proxy Settings"),
991 1, PURPLE_PROXY_USE_GLOBAL,
992 -1);
994 gtk_list_store_append(model, &iter);
995 gtk_list_store_set(model, &iter,
996 0, _("No Proxy"),
997 1, PURPLE_PROXY_NONE,
998 -1);
1000 gtk_list_store_append(model, &iter);
1001 gtk_list_store_set(model, &iter,
1002 0, _("SOCKS 4"),
1003 1, PURPLE_PROXY_SOCKS4,
1004 -1);
1006 gtk_list_store_append(model, &iter);
1007 gtk_list_store_set(model, &iter,
1008 0, _("SOCKS 5"),
1009 1, PURPLE_PROXY_SOCKS5,
1010 -1);
1012 gtk_list_store_append(model, &iter);
1013 gtk_list_store_set(model, &iter,
1014 0, _("Tor/Privacy (SOCKS5)"),
1015 1, PURPLE_PROXY_TOR,
1016 -1);
1018 gtk_list_store_append(model, &iter);
1019 gtk_list_store_set(model, &iter,
1020 0, _("HTTP"),
1021 1, PURPLE_PROXY_HTTP,
1022 -1);
1024 gtk_list_store_append(model, &iter);
1025 gtk_list_store_set(model, &iter,
1026 0, _("Use Environmental Settings"),
1027 1, PURPLE_PROXY_USE_ENVVAR,
1028 -1);
1030 renderer = gtk_cell_renderer_text_new();
1031 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(dropdown), renderer, TRUE);
1032 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(dropdown), renderer,
1033 "text", 0, NULL);
1035 return dropdown;
1038 static void
1039 proxy_type_changed_cb(GtkWidget *menu, AccountPrefsDialog *dialog)
1041 GtkTreeIter iter;
1043 if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(menu), &iter)) {
1044 int int_value;
1045 gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(menu)), &iter,
1046 1, &int_value, -1);
1047 dialog->new_proxy_type = int_value;
1050 if (dialog->new_proxy_type == PURPLE_PROXY_USE_GLOBAL ||
1051 dialog->new_proxy_type == PURPLE_PROXY_NONE ||
1052 dialog->new_proxy_type == PURPLE_PROXY_USE_ENVVAR) {
1054 gtk_widget_hide_all(dialog->proxy_vbox);
1056 else
1057 gtk_widget_show_all(dialog->proxy_vbox);
1060 static void
1061 port_popup_cb(GtkWidget *w, GtkMenu *menu, gpointer data)
1063 GtkWidget *item1;
1064 GtkWidget *item2;
1066 /* This is an easter egg.
1067 It means one of two things, both intended as humourus:
1068 A) your network is really slow and you have nothing better to do than
1069 look at butterflies.
1070 B)You are looking really closely at something that shouldn't matter. */
1071 item1 = gtk_menu_item_new_with_label(_("If you look real closely"));
1073 /* This is an easter egg. See the comment on the previous line in the source. */
1074 item2 = gtk_menu_item_new_with_label(_("you can see the butterflies mating"));
1076 gtk_widget_show(item1);
1077 gtk_widget_show(item2);
1079 /* Prepend these in reverse order so they appear correctly. */
1080 gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), item2);
1081 gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), item1);
1084 static void
1085 add_proxy_options(AccountPrefsDialog *dialog, GtkWidget *parent)
1087 PurpleProxyInfo *proxy_info;
1088 GtkWidget *vbox;
1089 GtkWidget *vbox2;
1090 GtkTreeIter iter;
1091 GtkTreeModel *proxy_model;
1093 if (dialog->proxy_frame != NULL)
1094 gtk_widget_destroy(dialog->proxy_frame);
1096 /* Main vbox */
1097 dialog->proxy_frame = vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
1098 gtk_container_add(GTK_CONTAINER(parent), vbox);
1099 gtk_widget_show(vbox);
1101 /* Proxy Type drop-down. */
1102 dialog->proxy_dropdown = make_proxy_dropdown();
1104 add_pref_box(dialog, vbox, _("Proxy _type:"), dialog->proxy_dropdown);
1106 /* Setup the second vbox, which may be hidden at times. */
1107 dialog->proxy_vbox = vbox2 = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
1108 gtk_box_pack_start(GTK_BOX(vbox), vbox2, FALSE, FALSE, PIDGIN_HIG_BORDER);
1109 gtk_widget_show(vbox2);
1111 /* Host */
1112 dialog->proxy_host_entry = gtk_entry_new();
1113 add_pref_box(dialog, vbox2, _("_Host:"), dialog->proxy_host_entry);
1115 /* Port */
1116 dialog->proxy_port_entry = gtk_entry_new();
1117 add_pref_box(dialog, vbox2, _("_Port:"), dialog->proxy_port_entry);
1119 g_signal_connect(G_OBJECT(dialog->proxy_port_entry), "populate-popup",
1120 G_CALLBACK(port_popup_cb), NULL);
1122 /* User */
1123 dialog->proxy_user_entry = gtk_entry_new();
1125 add_pref_box(dialog, vbox2, _("_Username:"), dialog->proxy_user_entry);
1127 /* Password */
1128 dialog->proxy_pass_entry = gtk_entry_new();
1129 gtk_entry_set_visibility(GTK_ENTRY(dialog->proxy_pass_entry), FALSE);
1130 #if !GTK_CHECK_VERSION(2,16,0)
1131 if (gtk_entry_get_invisible_char(GTK_ENTRY(dialog->proxy_pass_entry)) == '*')
1132 gtk_entry_set_invisible_char(GTK_ENTRY(dialog->proxy_pass_entry), PIDGIN_INVISIBLE_CHAR);
1133 #endif /* Less than GTK+ 2.16 */
1134 add_pref_box(dialog, vbox2, _("Pa_ssword:"), dialog->proxy_pass_entry);
1136 if (dialog->account != NULL &&
1137 (proxy_info = purple_account_get_proxy_info(dialog->account)) != NULL) {
1138 const char *value;
1139 int int_val;
1141 dialog->new_proxy_type = purple_proxy_info_get_type(proxy_info);
1143 if ((value = purple_proxy_info_get_host(proxy_info)) != NULL)
1144 gtk_entry_set_text(GTK_ENTRY(dialog->proxy_host_entry), value);
1146 if ((int_val = purple_proxy_info_get_port(proxy_info)) != 0) {
1147 char buf[11];
1149 g_snprintf(buf, sizeof(buf), "%d", int_val);
1151 gtk_entry_set_text(GTK_ENTRY(dialog->proxy_port_entry), buf);
1154 if ((value = purple_proxy_info_get_username(proxy_info)) != NULL)
1155 gtk_entry_set_text(GTK_ENTRY(dialog->proxy_user_entry), value);
1157 if ((value = purple_proxy_info_get_password(proxy_info)) != NULL)
1158 gtk_entry_set_text(GTK_ENTRY(dialog->proxy_pass_entry), value);
1160 } else
1161 dialog->new_proxy_type = PURPLE_PROXY_USE_GLOBAL;
1163 proxy_model = gtk_combo_box_get_model(
1164 GTK_COMBO_BOX(dialog->proxy_dropdown));
1165 if (gtk_tree_model_get_iter_first(proxy_model, &iter)) {
1166 int int_val;
1167 do {
1168 gtk_tree_model_get(proxy_model, &iter, 1, &int_val, -1);
1169 if (int_val == dialog->new_proxy_type) {
1170 gtk_combo_box_set_active_iter(
1171 GTK_COMBO_BOX(dialog->proxy_dropdown), &iter);
1172 break;
1174 } while(gtk_tree_model_iter_next(proxy_model, &iter));
1177 proxy_type_changed_cb(dialog->proxy_dropdown, dialog);
1179 /* Connect signals. */
1180 g_signal_connect(G_OBJECT(dialog->proxy_dropdown), "changed",
1181 G_CALLBACK(proxy_type_changed_cb), dialog);
1184 static void
1185 add_voice_options(AccountPrefsDialog *dialog)
1187 #ifdef USE_VV
1188 if (!dialog->prpl_info || !PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(dialog->prpl_info, initiate_media)) {
1189 if (dialog->voice_frame) {
1190 gtk_widget_destroy(dialog->voice_frame);
1191 dialog->voice_frame = NULL;
1192 dialog->suppression_check = NULL;
1194 return;
1197 if (!dialog->voice_frame) {
1198 dialog->voice_frame = gtk_vbox_new(FALSE, PIDGIN_HIG_BORDER);
1199 gtk_container_set_border_width(GTK_CONTAINER(dialog->voice_frame),
1200 PIDGIN_HIG_BORDER);
1202 dialog->suppression_check =
1203 gtk_check_button_new_with_mnemonic(_("Use _silence suppression"));
1204 gtk_box_pack_start(GTK_BOX(dialog->voice_frame), dialog->suppression_check,
1205 FALSE, FALSE, 0);
1207 gtk_notebook_append_page(GTK_NOTEBOOK(dialog->notebook),
1208 dialog->voice_frame, gtk_label_new_with_mnemonic(_("_Voice and Video")));
1209 gtk_widget_show_all(dialog->voice_frame);
1212 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->suppression_check),
1213 purple_account_get_silence_suppression(dialog->account));
1214 #endif
1217 static gboolean
1218 account_win_destroy_cb(GtkWidget *w, GdkEvent *event,
1219 AccountPrefsDialog *dialog)
1221 g_hash_table_remove(account_pref_wins, dialog->account);
1223 gtk_widget_destroy(dialog->window);
1225 g_list_free(dialog->user_split_entries);
1226 while (dialog->protocol_opt_entries != NULL) {
1227 ProtocolOptEntry *opt_entry = dialog->protocol_opt_entries->data;
1228 g_free(opt_entry->setting);
1229 g_free(opt_entry);
1230 dialog->protocol_opt_entries = g_list_delete_link(dialog->protocol_opt_entries, dialog->protocol_opt_entries);
1232 g_free(dialog->protocol_id);
1233 g_object_unref(dialog->sg);
1235 purple_imgstore_unref(dialog->icon_img);
1237 if (dialog->icon_filesel)
1238 gtk_widget_destroy(dialog->icon_filesel);
1240 purple_signals_disconnect_by_handle(dialog);
1242 g_free(dialog);
1243 return FALSE;
1246 static void
1247 cancel_account_prefs_cb(GtkWidget *w, AccountPrefsDialog *dialog)
1249 account_win_destroy_cb(NULL, NULL, dialog);
1252 static void
1253 ok_account_prefs_cb(GtkWidget *w, AccountPrefsDialog *dialog)
1255 PurpleProxyInfo *proxy_info = NULL;
1256 GList *l, *l2;
1257 const char *value;
1258 char *username;
1259 char *tmp;
1260 gboolean new_acct = FALSE, icon_change = FALSE;
1261 PurpleAccount *account;
1263 /* Build the username string. */
1264 username = g_strdup(gtk_entry_get_text(GTK_ENTRY(dialog->username_entry)));
1266 if (dialog->prpl_info != NULL)
1268 for (l = dialog->prpl_info->user_splits,
1269 l2 = dialog->user_split_entries;
1270 l != NULL && l2 != NULL;
1271 l = l->next, l2 = l2->next)
1273 PurpleAccountUserSplit *split = l->data;
1274 GtkEntry *entry = l2->data;
1275 char sep[2] = " ";
1277 value = gtk_entry_get_text(entry);
1279 *sep = purple_account_user_split_get_separator(split);
1281 tmp = g_strconcat(username, sep,
1282 (*value ? value :
1283 purple_account_user_split_get_default_value(split)),
1284 NULL);
1286 g_free(username);
1287 username = tmp;
1291 if (dialog->account == NULL)
1293 if (purple_accounts_find(username, dialog->protocol_id) != NULL) {
1294 purple_debug_warning("gtkaccount", "Trying to add a duplicate %s account (%s).\n",
1295 dialog->protocol_id, username);
1297 purple_notify_error(NULL, NULL, _("Unable to save new account"),
1298 _("An account already exists with the specified criteria."));
1300 g_free(username);
1301 return;
1304 if (purple_accounts_get_all() == NULL) {
1305 /* We're adding our first account. Be polite and show the buddy list */
1306 purple_blist_set_visible(TRUE);
1309 account = purple_account_new(username, dialog->protocol_id);
1310 new_acct = TRUE;
1312 else
1314 account = dialog->account;
1316 /* Protocol */
1317 purple_account_set_protocol_id(account, dialog->protocol_id);
1320 /* Alias */
1321 value = gtk_entry_get_text(GTK_ENTRY(dialog->alias_entry));
1323 if (*value != '\0')
1324 purple_account_set_alias(account, value);
1325 else
1326 purple_account_set_alias(account, NULL);
1328 /* Buddy Icon */
1329 if (dialog->prpl_info != NULL && dialog->prpl_info->icon_spec.format != NULL)
1331 const char *filename;
1333 if (new_acct || purple_account_get_bool(account, "use-global-buddyicon", TRUE) ==
1334 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->icon_check)))
1336 icon_change = TRUE;
1338 purple_account_set_bool(account, "use-global-buddyicon", !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->icon_check)));
1340 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->icon_check)))
1342 if (dialog->icon_img)
1344 size_t len = purple_imgstore_get_size(dialog->icon_img);
1345 purple_buddy_icons_set_account_icon(account,
1346 g_memdup(purple_imgstore_get_data(dialog->icon_img), len),
1347 len);
1348 purple_account_set_buddy_icon_path(account, purple_imgstore_get_filename(dialog->icon_img));
1350 else
1352 purple_buddy_icons_set_account_icon(account, NULL, 0);
1353 purple_account_set_buddy_icon_path(account, NULL);
1356 else if ((filename = purple_prefs_get_path(PIDGIN_PREFS_ROOT "/accounts/buddyicon")) && icon_change)
1358 size_t len;
1359 gpointer data = pidgin_convert_buddy_icon(dialog->plugin, filename, &len);
1360 purple_account_set_buddy_icon_path(account, filename);
1361 purple_buddy_icons_set_account_icon(account, data, len);
1366 /* Remember Password */
1367 purple_account_set_remember_password(account,
1368 gtk_toggle_button_get_active(
1369 GTK_TOGGLE_BUTTON(dialog->remember_pass_check)));
1371 /* Check Mail */
1372 if (dialog->prpl_info && dialog->prpl_info->options & OPT_PROTO_MAIL_CHECK)
1373 purple_account_set_check_mail(account,
1374 gtk_toggle_button_get_active(
1375 GTK_TOGGLE_BUTTON(dialog->new_mail_check)));
1377 /* Password */
1378 value = gtk_entry_get_text(GTK_ENTRY(dialog->password_entry));
1381 * We set the password if this is a new account because new accounts
1382 * will be set to online, and if the user has entered a password into
1383 * the account editor (but has not checked the 'save' box), then we
1384 * don't want to prompt them.
1386 if ((purple_account_get_remember_password(account) || new_acct) && (*value != '\0'))
1387 purple_account_set_password(account, value);
1388 else
1389 purple_account_set_password(account, NULL);
1391 purple_account_set_username(account, username);
1392 g_free(username);
1394 /* Add the protocol settings */
1395 if (dialog->prpl_info) {
1396 ProtocolOptEntry *opt_entry;
1397 GtkTreeIter iter;
1398 char *value2;
1399 int int_value;
1400 gboolean bool_value;
1402 for (l2 = dialog->protocol_opt_entries; l2; l2 = l2->next) {
1404 opt_entry = l2->data;
1406 switch (opt_entry->type) {
1407 case PURPLE_PREF_STRING:
1408 value = gtk_entry_get_text(GTK_ENTRY(opt_entry->widget));
1409 purple_account_set_string(account, opt_entry->setting, value);
1410 break;
1412 case PURPLE_PREF_INT:
1413 int_value = atoi(gtk_entry_get_text(GTK_ENTRY(opt_entry->widget)));
1414 purple_account_set_int(account, opt_entry->setting, int_value);
1415 break;
1417 case PURPLE_PREF_BOOLEAN:
1418 bool_value =
1419 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(opt_entry->widget));
1420 purple_account_set_bool(account, opt_entry->setting, bool_value);
1421 break;
1423 case PURPLE_PREF_STRING_LIST:
1424 value2 = NULL;
1425 if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(opt_entry->widget), &iter))
1426 gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(opt_entry->widget)), &iter, 1, &value2, -1);
1427 purple_account_set_string(account, opt_entry->setting, value2);
1428 break;
1430 default:
1431 break;
1436 /* Set the proxy stuff. */
1437 proxy_info = purple_account_get_proxy_info(account);
1439 /* Create the proxy info if it doesn't exist. */
1440 if (proxy_info == NULL) {
1441 proxy_info = purple_proxy_info_new();
1442 purple_account_set_proxy_info(account, proxy_info);
1445 /* Set the proxy info type. */
1446 purple_proxy_info_set_type(proxy_info, dialog->new_proxy_type);
1448 /* Host */
1449 value = gtk_entry_get_text(GTK_ENTRY(dialog->proxy_host_entry));
1451 if (*value != '\0')
1452 purple_proxy_info_set_host(proxy_info, value);
1453 else
1454 purple_proxy_info_set_host(proxy_info, NULL);
1456 /* Port */
1457 value = gtk_entry_get_text(GTK_ENTRY(dialog->proxy_port_entry));
1459 if (*value != '\0')
1460 purple_proxy_info_set_port(proxy_info, atoi(value));
1461 else
1462 purple_proxy_info_set_port(proxy_info, 0);
1464 /* Username */
1465 value = gtk_entry_get_text(GTK_ENTRY(dialog->proxy_user_entry));
1467 if (*value != '\0')
1468 purple_proxy_info_set_username(proxy_info, value);
1469 else
1470 purple_proxy_info_set_username(proxy_info, NULL);
1472 /* Password */
1473 value = gtk_entry_get_text(GTK_ENTRY(dialog->proxy_pass_entry));
1475 if (*value != '\0')
1476 purple_proxy_info_set_password(proxy_info, value);
1477 else
1478 purple_proxy_info_set_password(proxy_info, NULL);
1480 /* If there are no values set then proxy_info NULL */
1481 if ((purple_proxy_info_get_type(proxy_info) == PURPLE_PROXY_USE_GLOBAL) &&
1482 (purple_proxy_info_get_host(proxy_info) == NULL) &&
1483 (purple_proxy_info_get_port(proxy_info) == 0) &&
1484 (purple_proxy_info_get_username(proxy_info) == NULL) &&
1485 (purple_proxy_info_get_password(proxy_info) == NULL))
1487 purple_account_set_proxy_info(account, NULL);
1488 proxy_info = NULL;
1491 /* Voice and Video settings */
1492 if (dialog->voice_frame) {
1493 purple_account_set_silence_suppression(account,
1494 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->suppression_check)));
1497 /* If this is a new account, add it to our list */
1498 if (new_acct)
1499 purple_accounts_add(account);
1500 else
1501 purple_signal_emit(pidgin_account_get_handle(), "account-modified", account);
1503 /* If this is a new account, then sign on! */
1504 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->register_button))) {
1505 purple_account_register(account);
1506 } else if (new_acct) {
1507 const PurpleSavedStatus *saved_status;
1509 saved_status = purple_savedstatus_get_current();
1510 if (saved_status != NULL) {
1511 purple_savedstatus_activate_for_account(saved_status, account);
1512 purple_account_set_enabled(account, PIDGIN_UI, TRUE);
1516 /* We no longer need the data from the dialog window */
1517 account_win_destroy_cb(NULL, NULL, dialog);
1521 static const GtkTargetEntry dnd_targets[] = {
1522 {"text/plain", 0, 0},
1523 {"text/uri-list", 0, 1},
1524 {"STRING", 0, 2}
1527 void
1528 pidgin_account_dialog_show(PidginAccountDialogType type,
1529 PurpleAccount *account)
1531 AccountPrefsDialog *dialog;
1532 GtkWidget *win;
1533 GtkWidget *main_vbox;
1534 GtkWidget *vbox;
1535 GtkWidget *dbox;
1536 GtkWidget *notebook;
1537 GtkWidget *button;
1539 if (accounts_window != NULL && account != NULL &&
1540 (dialog = g_hash_table_lookup(account_pref_wins, account)) != NULL)
1542 gtk_window_present(GTK_WINDOW(dialog->window));
1543 return;
1546 dialog = g_new0(AccountPrefsDialog, 1);
1548 if (accounts_window != NULL && account != NULL)
1550 g_hash_table_insert(account_pref_wins, account, dialog);
1553 dialog->account = account;
1554 dialog->type = type;
1555 dialog->sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
1557 if (dialog->account == NULL) {
1558 /* Select the first prpl in the list*/
1559 GList *prpl_list = purple_plugins_get_protocols();
1560 if (prpl_list != NULL)
1561 dialog->protocol_id = g_strdup(((PurplePlugin *) prpl_list->data)->info->id);
1563 else
1565 dialog->protocol_id =
1566 g_strdup(purple_account_get_protocol_id(dialog->account));
1569 if ((dialog->plugin = purple_find_prpl(dialog->protocol_id)) != NULL)
1570 dialog->prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(dialog->plugin);
1572 dialog->window = win = pidgin_create_dialog((type == PIDGIN_ADD_ACCOUNT_DIALOG) ? _("Add Account") : _("Modify Account"),
1573 PIDGIN_HIG_BOX_SPACE, "account", FALSE);
1575 g_signal_connect(G_OBJECT(win), "delete_event",
1576 G_CALLBACK(account_win_destroy_cb), dialog);
1578 /* Setup the vbox */
1579 main_vbox = pidgin_dialog_get_vbox_with_properties(GTK_DIALOG(win), FALSE, PIDGIN_HIG_BOX_SPACE);
1581 dialog->notebook = notebook = gtk_notebook_new();
1582 gtk_box_pack_start(GTK_BOX(main_vbox), notebook, FALSE, FALSE, 0);
1583 gtk_widget_show(GTK_WIDGET(notebook));
1585 /* Setup the inner vbox */
1586 dialog->top_vbox = vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BORDER);
1587 gtk_container_set_border_width(GTK_CONTAINER(vbox), PIDGIN_HIG_BORDER);
1588 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox,
1589 gtk_label_new_with_mnemonic(_("_Basic")));
1590 gtk_widget_show(vbox);
1592 /* Setup the top frames. */
1593 add_login_options(dialog, vbox);
1594 add_user_options(dialog, vbox);
1596 button = gtk_check_button_new_with_mnemonic(
1597 _("Create _this new account on the server"));
1598 gtk_box_pack_start(GTK_BOX(main_vbox), button, FALSE, FALSE, 0);
1599 gtk_widget_show(button);
1600 dialog->register_button = button;
1601 if (dialog->account == NULL)
1602 gtk_widget_set_sensitive(button, FALSE);
1604 if (!dialog->prpl_info || !dialog->prpl_info->register_user)
1605 gtk_widget_hide(button);
1607 /* Setup the page with 'Advanced' (protocol options). */
1608 add_protocol_options(dialog);
1610 /* Setup the page with 'Proxy'. */
1611 dbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BORDER);
1612 gtk_container_set_border_width(GTK_CONTAINER(dbox), PIDGIN_HIG_BORDER);
1613 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), dbox,
1614 gtk_label_new_with_mnemonic(_("P_roxy")));
1615 gtk_widget_show(dbox);
1616 add_proxy_options(dialog, dbox);
1618 add_voice_options(dialog);
1620 /* Cancel button */
1621 pidgin_dialog_add_button(GTK_DIALOG(win), GTK_STOCK_CANCEL, G_CALLBACK(cancel_account_prefs_cb), dialog);
1623 /* Save button */
1624 button = pidgin_dialog_add_button(GTK_DIALOG(win),
1625 (type == PIDGIN_ADD_ACCOUNT_DIALOG) ? GTK_STOCK_ADD : GTK_STOCK_SAVE,
1626 G_CALLBACK(ok_account_prefs_cb),
1627 dialog);
1628 if (dialog->account == NULL)
1629 gtk_widget_set_sensitive(button, FALSE);
1630 dialog->ok_button = button;
1632 /* Set up DND */
1633 gtk_drag_dest_set(dialog->window,
1634 GTK_DEST_DEFAULT_MOTION |
1635 GTK_DEST_DEFAULT_DROP,
1636 dnd_targets,
1637 sizeof(dnd_targets) / sizeof(GtkTargetEntry),
1638 GDK_ACTION_COPY);
1640 g_signal_connect(G_OBJECT(dialog->window), "drag_data_received",
1641 G_CALLBACK(account_dnd_recv), dialog);
1643 /* Show the window. */
1644 gtk_widget_show(win);
1645 if (!account)
1646 gtk_widget_grab_focus(dialog->protocol_menu);
1649 /**************************************************************************
1650 * Accounts Dialog
1651 **************************************************************************/
1652 static void
1653 signed_on_off_cb(PurpleConnection *gc, gpointer user_data)
1655 PurpleAccount *account;
1656 GtkTreeModel *model;
1657 GtkTreeIter iter;
1658 GdkPixbuf *pixbuf;
1659 size_t index;
1661 /* Don't need to do anything if the accounts window is not visible */
1662 if (accounts_window == NULL)
1663 return;
1665 account = purple_connection_get_account(gc);
1666 model = GTK_TREE_MODEL(accounts_window->model);
1667 index = g_list_index(purple_accounts_get_all(), account);
1669 if (gtk_tree_model_iter_nth_child(model, &iter, NULL, index))
1671 pixbuf = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_MEDIUM);
1672 if ((pixbuf != NULL) && purple_account_is_disconnected(account))
1673 gdk_pixbuf_saturate_and_pixelate(pixbuf, pixbuf, 0.0, FALSE);
1675 gtk_list_store_set(accounts_window->model, &iter,
1676 COLUMN_ICON, pixbuf,
1677 -1);
1679 if (pixbuf != NULL)
1680 g_object_unref(G_OBJECT(pixbuf));
1685 * Get the GtkTreeIter of the specified account in the
1686 * GtkListStore
1688 static gboolean
1689 accounts_window_find_account_in_treemodel(GtkTreeIter *iter, PurpleAccount *account)
1691 GtkTreeModel *model;
1692 PurpleAccount *cur;
1694 g_return_val_if_fail(account != NULL, FALSE);
1695 g_return_val_if_fail(accounts_window != NULL, FALSE);
1697 model = GTK_TREE_MODEL(accounts_window->model);
1699 if (!gtk_tree_model_get_iter_first(model, iter))
1700 return FALSE;
1702 gtk_tree_model_get(model, iter, COLUMN_DATA, &cur, -1);
1703 if (cur == account)
1704 return TRUE;
1706 while (gtk_tree_model_iter_next(model, iter))
1708 gtk_tree_model_get(model, iter, COLUMN_DATA, &cur, -1);
1709 if (cur == account)
1710 return TRUE;
1713 return FALSE;
1716 static void
1717 account_removed_cb(PurpleAccount *account, gpointer user_data)
1719 AccountPrefsDialog *dialog;
1720 GtkTreeIter iter;
1722 /* If the account was being modified, close the edit window */
1723 if ((dialog = g_hash_table_lookup(account_pref_wins, account)) != NULL)
1724 account_win_destroy_cb(NULL, NULL, dialog);
1726 if (accounts_window == NULL)
1727 return;
1729 /* Remove the account from the GtkListStore */
1730 if (accounts_window_find_account_in_treemodel(&iter, account))
1731 gtk_list_store_remove(accounts_window->model, &iter);
1733 if (purple_accounts_get_all() == NULL)
1734 gtk_notebook_set_current_page(GTK_NOTEBOOK(accounts_window->notebook), 0);
1737 static void
1738 account_abled_cb(PurpleAccount *account, gpointer user_data)
1740 GtkTreeIter iter;
1742 if (accounts_window == NULL)
1743 return;
1745 /* update the account in the GtkListStore */
1746 if (accounts_window_find_account_in_treemodel(&iter, account))
1747 gtk_list_store_set(accounts_window->model, &iter,
1748 COLUMN_ENABLED, GPOINTER_TO_INT(user_data),
1749 -1);
1752 static void
1753 drag_data_get_cb(GtkWidget *widget, GdkDragContext *ctx,
1754 GtkSelectionData *data, guint info, guint time,
1755 AccountsWindow *dialog)
1757 if (data->target == gdk_atom_intern("PURPLE_ACCOUNT", FALSE)) {
1758 GtkTreeRowReference *ref;
1759 GtkTreePath *source_row;
1760 GtkTreeIter iter;
1761 PurpleAccount *account = NULL;
1762 GValue val;
1764 ref = g_object_get_data(G_OBJECT(ctx), "gtk-tree-view-source-row");
1765 source_row = gtk_tree_row_reference_get_path(ref);
1767 if (source_row == NULL)
1768 return;
1770 gtk_tree_model_get_iter(GTK_TREE_MODEL(dialog->model), &iter,
1771 source_row);
1772 val.g_type = 0;
1773 gtk_tree_model_get_value(GTK_TREE_MODEL(dialog->model), &iter,
1774 COLUMN_DATA, &val);
1776 dialog->drag_iter = iter;
1778 account = g_value_get_pointer(&val);
1780 gtk_selection_data_set(data, gdk_atom_intern("PURPLE_ACCOUNT", FALSE),
1781 8, (void *)&account, sizeof(account));
1783 gtk_tree_path_free(source_row);
1787 static void
1788 move_account_after(GtkListStore *store, GtkTreeIter *iter,
1789 GtkTreeIter *position)
1791 GtkTreeIter new_iter;
1792 PurpleAccount *account;
1794 gtk_tree_model_get(GTK_TREE_MODEL(store), iter,
1795 COLUMN_DATA, &account,
1796 -1);
1798 gtk_list_store_insert_after(store, &new_iter, position);
1800 set_account(store, &new_iter, account, NULL);
1802 gtk_list_store_remove(store, iter);
1805 static void
1806 move_account_before(GtkListStore *store, GtkTreeIter *iter,
1807 GtkTreeIter *position)
1809 GtkTreeIter new_iter;
1810 PurpleAccount *account;
1812 gtk_tree_model_get(GTK_TREE_MODEL(store), iter,
1813 COLUMN_DATA, &account,
1814 -1);
1816 gtk_list_store_insert_before(store, &new_iter, position);
1818 set_account(store, &new_iter, account, NULL);
1820 gtk_list_store_remove(store, iter);
1823 static void
1824 drag_data_received_cb(GtkWidget *widget, GdkDragContext *ctx,
1825 guint x, guint y, GtkSelectionData *sd,
1826 guint info, guint t, AccountsWindow *dialog)
1828 if (sd->target == gdk_atom_intern("PURPLE_ACCOUNT", FALSE) && sd->data) {
1829 gint dest_index;
1830 PurpleAccount *a = NULL;
1831 GtkTreePath *path = NULL;
1832 GtkTreeViewDropPosition position;
1834 memcpy(&a, sd->data, sizeof(a));
1836 if (gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(widget), x, y,
1837 &path, &position)) {
1839 GtkTreeIter iter;
1840 PurpleAccount *account;
1841 GValue val;
1843 gtk_tree_model_get_iter(GTK_TREE_MODEL(dialog->model), &iter, path);
1844 val.g_type = 0;
1845 gtk_tree_model_get_value(GTK_TREE_MODEL(dialog->model), &iter,
1846 COLUMN_DATA, &val);
1848 account = g_value_get_pointer(&val);
1850 switch (position) {
1851 case GTK_TREE_VIEW_DROP_AFTER:
1852 case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
1853 move_account_after(dialog->model, &dialog->drag_iter,
1854 &iter);
1855 dest_index = g_list_index(purple_accounts_get_all(),
1856 account) + 1;
1857 break;
1859 case GTK_TREE_VIEW_DROP_BEFORE:
1860 case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
1861 dest_index = g_list_index(purple_accounts_get_all(),
1862 account);
1864 move_account_before(dialog->model, &dialog->drag_iter,
1865 &iter);
1866 break;
1868 default:
1869 return;
1872 purple_accounts_reorder(a, dest_index);
1877 static gboolean
1878 accedit_win_destroy_cb(GtkWidget *w, GdkEvent *event, AccountsWindow *dialog)
1880 dialog->window = NULL;
1882 pidgin_accounts_window_hide();
1884 return FALSE;
1887 static void
1888 add_account_cb(GtkWidget *w, AccountsWindow *dialog)
1890 pidgin_account_dialog_show(PIDGIN_ADD_ACCOUNT_DIALOG, NULL);
1893 static void
1894 modify_account_sel(GtkTreeModel *model, GtkTreePath *path,
1895 GtkTreeIter *iter, gpointer data)
1897 PurpleAccount *account;
1899 gtk_tree_model_get(model, iter, COLUMN_DATA, &account, -1);
1901 if (account != NULL)
1902 pidgin_account_dialog_show(PIDGIN_MODIFY_ACCOUNT_DIALOG, account);
1905 static void
1906 modify_account_cb(GtkWidget *w, AccountsWindow *dialog)
1908 GtkTreeSelection *selection;
1910 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview));
1912 gtk_tree_selection_selected_foreach(selection, modify_account_sel, dialog);
1915 static void
1916 delete_account_cb(PurpleAccount *account)
1918 purple_accounts_delete(account);
1921 static void
1922 ask_delete_account_sel(GtkTreeModel *model, GtkTreePath *path,
1923 GtkTreeIter *iter, gpointer data)
1925 PurpleAccount *account;
1927 gtk_tree_model_get(model, iter, COLUMN_DATA, &account, -1);
1929 if (account != NULL) {
1930 char *buf;
1932 buf = g_strdup_printf(_("Are you sure you want to delete %s?"),
1933 purple_account_get_username(account));
1935 purple_request_close_with_handle(account);
1936 purple_request_action(account, NULL, buf, NULL,
1937 PURPLE_DEFAULT_ACTION_NONE,
1938 account, NULL, NULL,
1939 account, 2,
1940 _("Delete"), delete_account_cb,
1941 _("Cancel"), NULL);
1942 g_free(buf);
1946 static void
1947 ask_delete_account_cb(GtkWidget *w, AccountsWindow *dialog)
1949 GtkTreeSelection *selection;
1951 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview));
1953 gtk_tree_selection_selected_foreach(selection, ask_delete_account_sel,
1954 dialog);
1957 static void
1958 close_accounts_cb(GtkWidget *w, AccountsWindow *dialog)
1960 pidgin_accounts_window_hide();
1964 static void
1965 enabled_cb(GtkCellRendererToggle *renderer, gchar *path_str,
1966 gpointer data)
1968 AccountsWindow *dialog = (AccountsWindow *)data;
1969 PurpleAccount *account;
1970 GtkTreeModel *model = GTK_TREE_MODEL(dialog->model);
1971 GtkTreeIter iter;
1972 gboolean enabled;
1973 const PurpleSavedStatus *saved_status;
1975 gtk_tree_model_get_iter_from_string(model, &iter, path_str);
1976 gtk_tree_model_get(model, &iter,
1977 COLUMN_DATA, &account,
1978 COLUMN_ENABLED, &enabled,
1979 -1);
1982 * If we just enabled the account, then set the statuses
1983 * to the current status.
1985 if (!enabled)
1987 saved_status = purple_savedstatus_get_current();
1988 purple_savedstatus_activate_for_account(saved_status, account);
1991 purple_account_set_enabled(account, PIDGIN_UI, !enabled);
1994 static void
1995 add_columns(GtkWidget *treeview, AccountsWindow *dialog)
1997 GtkCellRenderer *renderer;
1998 GtkTreeViewColumn *column;
2000 /* Enabled */
2001 renderer = gtk_cell_renderer_toggle_new();
2003 g_signal_connect(G_OBJECT(renderer), "toggled",
2004 G_CALLBACK(enabled_cb), dialog);
2006 column = gtk_tree_view_column_new_with_attributes(_("Enabled"),
2007 renderer, "active", COLUMN_ENABLED, NULL);
2009 gtk_tree_view_column_set_resizable(column, FALSE);
2010 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
2012 /* Username column */
2013 column = gtk_tree_view_column_new();
2014 gtk_tree_view_column_set_title(column, _("Username"));
2015 gtk_tree_view_column_set_resizable(column, TRUE);
2016 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
2018 /* Buddy Icon */
2019 renderer = gtk_cell_renderer_pixbuf_new();
2020 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2021 gtk_tree_view_column_add_attribute(column, renderer,
2022 "pixbuf", COLUMN_BUDDYICON);
2024 /* Username */
2025 renderer = gtk_cell_renderer_text_new();
2026 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2027 gtk_tree_view_column_add_attribute(column, renderer,
2028 "text", COLUMN_USERNAME);
2029 dialog->username_col = column;
2032 /* Protocol name */
2033 column = gtk_tree_view_column_new();
2034 gtk_tree_view_column_set_title(column, _("Protocol"));
2035 gtk_tree_view_column_set_resizable(column, FALSE);
2036 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
2038 /* Icon */
2039 renderer = gtk_cell_renderer_pixbuf_new();
2040 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2041 gtk_tree_view_column_add_attribute(column, renderer,
2042 "pixbuf", COLUMN_ICON);
2044 renderer = gtk_cell_renderer_text_new();
2045 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2046 gtk_tree_view_column_add_attribute(column, renderer,
2047 "text", COLUMN_PROTOCOL);
2050 static void
2051 set_account(GtkListStore *store, GtkTreeIter *iter, PurpleAccount *account, GdkPixbuf *global_buddyicon)
2053 GdkPixbuf *pixbuf, *buddyicon = NULL;
2054 PurpleStoredImage *img = NULL;
2055 PurplePlugin *prpl;
2056 PurplePluginProtocolInfo *prpl_info = NULL;
2058 pixbuf = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_MEDIUM);
2059 if ((pixbuf != NULL) && purple_account_is_disconnected(account))
2060 gdk_pixbuf_saturate_and_pixelate(pixbuf, pixbuf, 0.0, FALSE);
2062 prpl = purple_find_prpl(purple_account_get_protocol_id(account));
2063 if (prpl != NULL)
2064 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
2065 if (prpl_info != NULL && prpl_info->icon_spec.format != NULL) {
2066 if (purple_account_get_bool(account, "use-global-buddyicon", TRUE)) {
2067 if (global_buddyicon != NULL)
2068 buddyicon = g_object_ref(G_OBJECT(global_buddyicon));
2069 else {
2070 /* This is for when set_account() is called for a single account */
2071 const char *path;
2072 path = purple_prefs_get_path(PIDGIN_PREFS_ROOT "/accounts/buddyicon");
2073 if ((path != NULL) && (*path != '\0')) {
2074 img = purple_imgstore_new_from_file(path);
2077 } else {
2078 img = purple_buddy_icons_find_account_icon(account);
2082 if (img != NULL) {
2083 GdkPixbuf *buddyicon_pixbuf;
2084 buddyicon_pixbuf = pidgin_pixbuf_from_imgstore(img);
2085 purple_imgstore_unref(img);
2087 if (buddyicon_pixbuf != NULL) {
2088 buddyicon = gdk_pixbuf_scale_simple(buddyicon_pixbuf, 22, 22, GDK_INTERP_HYPER);
2089 g_object_unref(G_OBJECT(buddyicon_pixbuf));
2093 gtk_list_store_set(store, iter,
2094 COLUMN_ICON, pixbuf,
2095 COLUMN_BUDDYICON, buddyicon,
2096 COLUMN_USERNAME, purple_account_get_username(account),
2097 COLUMN_ENABLED, purple_account_get_enabled(account, PIDGIN_UI),
2098 COLUMN_PROTOCOL, purple_account_get_protocol_name(account),
2099 COLUMN_DATA, account,
2100 -1);
2102 if (pixbuf != NULL)
2103 g_object_unref(G_OBJECT(pixbuf));
2104 if (buddyicon != NULL)
2105 g_object_unref(G_OBJECT(buddyicon));
2108 static void
2109 add_account_to_liststore(PurpleAccount *account, gpointer user_data)
2111 GtkTreeIter iter;
2112 GdkPixbuf *global_buddyicon = user_data;
2114 if (accounts_window == NULL)
2115 return;
2117 gtk_list_store_append(accounts_window->model, &iter);
2118 gtk_notebook_set_current_page(GTK_NOTEBOOK(accounts_window->notebook),1);
2120 set_account(accounts_window->model, &iter, account, global_buddyicon);
2123 static gboolean
2124 populate_accounts_list(AccountsWindow *dialog)
2126 GList *l;
2127 gboolean ret = FALSE;
2128 GdkPixbuf *global_buddyicon = NULL;
2129 const char *path;
2131 gtk_list_store_clear(dialog->model);
2133 if ((path = purple_prefs_get_path(PIDGIN_PREFS_ROOT "/accounts/buddyicon")) != NULL) {
2134 GdkPixbuf *pixbuf = pidgin_pixbuf_new_from_file(path);
2135 if (pixbuf != NULL) {
2136 global_buddyicon = gdk_pixbuf_scale_simple(pixbuf, 22, 22, GDK_INTERP_HYPER);
2137 g_object_unref(G_OBJECT(pixbuf));
2141 for (l = purple_accounts_get_all(); l != NULL; l = l->next) {
2142 ret = TRUE;
2143 add_account_to_liststore((PurpleAccount *)l->data, global_buddyicon);
2146 if (global_buddyicon != NULL)
2147 g_object_unref(G_OBJECT(global_buddyicon));
2149 return ret;
2152 static void
2153 account_selected_cb(GtkTreeSelection *sel, AccountsWindow *dialog)
2155 gboolean selected = FALSE;
2157 selected = (gtk_tree_selection_count_selected_rows(sel) > 0);
2159 gtk_widget_set_sensitive(dialog->modify_button, selected);
2160 gtk_widget_set_sensitive(dialog->delete_button, selected);
2163 static gboolean
2164 account_treeview_double_click_cb(GtkTreeView *treeview, GdkEventButton *event, gpointer user_data)
2166 AccountsWindow *dialog;
2167 GtkTreePath *path;
2168 GtkTreeViewColumn *column;
2169 GtkTreeIter iter;
2170 PurpleAccount *account;
2172 dialog = (AccountsWindow *)user_data;
2174 if (event->window != gtk_tree_view_get_bin_window(treeview))
2175 return FALSE;
2177 /* Figure out which node was clicked */
2178 if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(dialog->treeview), event->x, event->y, &path, &column, NULL, NULL))
2179 return FALSE;
2180 if (column == gtk_tree_view_get_column(treeview, 0)) {
2181 gtk_tree_path_free(path);
2182 return FALSE;
2185 gtk_tree_model_get_iter(GTK_TREE_MODEL(dialog->model), &iter, path);
2186 gtk_tree_path_free(path);
2187 gtk_tree_model_get(GTK_TREE_MODEL(dialog->model), &iter, COLUMN_DATA, &account, -1);
2189 if ((account != NULL) && (event->button == 1) &&
2190 (event->type == GDK_2BUTTON_PRESS))
2192 pidgin_account_dialog_show(PIDGIN_MODIFY_ACCOUNT_DIALOG, account);
2193 return TRUE;
2196 return FALSE;
2199 static GtkWidget *
2200 create_accounts_list(AccountsWindow *dialog)
2202 GtkWidget *frame;
2203 GtkWidget *label;
2204 GtkWidget *treeview;
2205 GtkTreeSelection *sel;
2206 GtkTargetEntry gte[] = {{"PURPLE_ACCOUNT", GTK_TARGET_SAME_APP, 0}};
2207 char *pretty, *tmp;
2209 frame = gtk_frame_new(NULL);
2210 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
2212 accounts_window->notebook = gtk_notebook_new();
2213 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(accounts_window->notebook), FALSE);
2214 gtk_notebook_set_show_border(GTK_NOTEBOOK(accounts_window->notebook), FALSE);
2215 gtk_container_add(GTK_CONTAINER(frame), accounts_window->notebook);
2217 /* Create a helpful first-time-use label */
2218 label = gtk_label_new(NULL);
2219 /* Translators: Please maintain the use of -> or <- to represent the menu heirarchy */
2220 tmp = g_strdup_printf(_(
2221 "<span size='larger' weight='bold'>Welcome to %s!</span>\n\n"
2223 "You have no IM accounts configured. To start connecting with %s "
2224 "press the <b>Add...</b> button below and configure your first "
2225 "account. If you want %s to connect to multiple IM accounts, "
2226 "press <b>Add...</b> again to configure them all.\n\n"
2228 "You can come back to this window to add, edit, or remove "
2229 "accounts from <b>Accounts->Manage Accounts</b> in the Buddy "
2230 "List window"), PIDGIN_NAME, PIDGIN_NAME, PIDGIN_NAME);
2231 pretty = pidgin_make_pretty_arrows(tmp);
2232 g_free(tmp);
2233 gtk_label_set_markup(GTK_LABEL(label), pretty);
2234 g_free(pretty);
2236 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
2237 gtk_widget_show(label);
2239 gtk_misc_set_alignment(GTK_MISC(label), 0.5, 0.5);
2240 gtk_notebook_append_page(GTK_NOTEBOOK(accounts_window->notebook), label, NULL);
2242 /* Create the list model. */
2243 dialog->model = gtk_list_store_new(NUM_COLUMNS,
2244 GDK_TYPE_PIXBUF, /* COLUMN_ICON */
2245 GDK_TYPE_PIXBUF, /* COLUMN_BUDDYICON */
2246 G_TYPE_STRING, /* COLUMN_USERNAME */
2247 G_TYPE_BOOLEAN, /* COLUMN_ENABLED */
2248 G_TYPE_STRING, /* COLUMN_PROTOCOL */
2249 G_TYPE_POINTER /* COLUMN_DATA */
2252 /* And now the actual treeview */
2253 treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(dialog->model));
2254 dialog->treeview = treeview;
2255 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
2256 g_object_unref(G_OBJECT(dialog->model));
2258 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
2259 gtk_tree_selection_set_mode(sel, GTK_SELECTION_MULTIPLE);
2260 g_signal_connect(G_OBJECT(sel), "changed",
2261 G_CALLBACK(account_selected_cb), dialog);
2263 /* Handle double-clicking */
2264 g_signal_connect(G_OBJECT(treeview), "button_press_event",
2265 G_CALLBACK(account_treeview_double_click_cb), dialog);
2267 gtk_notebook_append_page(GTK_NOTEBOOK(accounts_window->notebook),
2268 pidgin_make_scrollable(treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_NONE, -1, -1),
2269 NULL);
2271 add_columns(treeview, dialog);
2272 gtk_tree_view_columns_autosize(GTK_TREE_VIEW(treeview));
2274 if (populate_accounts_list(dialog))
2275 gtk_notebook_set_current_page(GTK_NOTEBOOK(accounts_window->notebook), 1);
2276 else
2277 gtk_notebook_set_current_page(GTK_NOTEBOOK(accounts_window->notebook), 0);
2279 /* Setup DND. I wanna be an orc! */
2280 gtk_tree_view_enable_model_drag_source(
2281 GTK_TREE_VIEW(treeview), GDK_BUTTON1_MASK, gte,
2282 1, GDK_ACTION_COPY);
2283 gtk_tree_view_enable_model_drag_dest(
2284 GTK_TREE_VIEW(treeview), gte, 1,
2285 GDK_ACTION_COPY | GDK_ACTION_MOVE);
2287 g_signal_connect(G_OBJECT(treeview), "drag-data-received",
2288 G_CALLBACK(drag_data_received_cb), dialog);
2289 g_signal_connect(G_OBJECT(treeview), "drag-data-get",
2290 G_CALLBACK(drag_data_get_cb), dialog);
2292 gtk_widget_show_all(frame);
2293 return frame;
2296 static void
2297 account_modified_cb(PurpleAccount *account, AccountsWindow *window)
2299 GtkTreeIter iter;
2301 if (!accounts_window_find_account_in_treemodel(&iter, account))
2302 return;
2304 set_account(window->model, &iter, account, NULL);
2307 static void
2308 global_buddyicon_changed(const char *name, PurplePrefType type,
2309 gconstpointer value, gpointer window)
2311 GList *list;
2312 for (list = purple_accounts_get_all(); list; list = list->next) {
2313 account_modified_cb(list->data, window);
2317 void
2318 pidgin_accounts_window_show(void)
2320 AccountsWindow *dialog;
2321 GtkWidget *win;
2322 GtkWidget *vbox;
2323 GtkWidget *sw;
2324 GtkWidget *button;
2325 int width, height;
2327 if (accounts_window != NULL) {
2328 gtk_window_present(GTK_WINDOW(accounts_window->window));
2329 return;
2332 accounts_window = dialog = g_new0(AccountsWindow, 1);
2334 width = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/accounts/dialog/width");
2335 height = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/accounts/dialog/height");
2337 dialog->window = win = pidgin_create_dialog(_("Accounts"), PIDGIN_HIG_BORDER, "accounts", TRUE);
2338 gtk_window_set_default_size(GTK_WINDOW(win), width, height);
2340 g_signal_connect(G_OBJECT(win), "delete_event",
2341 G_CALLBACK(accedit_win_destroy_cb), accounts_window);
2343 /* Setup the vbox */
2344 vbox = pidgin_dialog_get_vbox_with_properties(GTK_DIALOG(win), FALSE, PIDGIN_HIG_BORDER);
2346 /* Setup the scrolled window that will contain the list of accounts. */
2347 sw = create_accounts_list(dialog);
2348 gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0);
2349 gtk_widget_show(sw);
2351 /* Add button */
2352 pidgin_dialog_add_button(GTK_DIALOG(win), PIDGIN_STOCK_ADD, G_CALLBACK(add_account_cb), dialog);
2354 /* Modify button */
2355 button = pidgin_dialog_add_button(GTK_DIALOG(win), PIDGIN_STOCK_MODIFY, G_CALLBACK(modify_account_cb), dialog);
2356 dialog->modify_button = button;
2357 gtk_widget_set_sensitive(button, FALSE);
2359 /* Delete button */
2360 button = pidgin_dialog_add_button(GTK_DIALOG(win), GTK_STOCK_DELETE, G_CALLBACK(ask_delete_account_cb), dialog);
2361 dialog->delete_button = button;
2362 gtk_widget_set_sensitive(button, FALSE);
2364 /* Close button */
2365 pidgin_dialog_add_button(GTK_DIALOG(win), GTK_STOCK_CLOSE, G_CALLBACK(close_accounts_cb), dialog);
2367 purple_signal_connect(pidgin_account_get_handle(), "account-modified",
2368 accounts_window,
2369 PURPLE_CALLBACK(account_modified_cb), accounts_window);
2370 purple_prefs_connect_callback(accounts_window,
2371 PIDGIN_PREFS_ROOT "/accounts/buddyicon",
2372 global_buddyicon_changed, accounts_window);
2374 gtk_widget_show(win);
2377 void
2378 pidgin_accounts_window_hide(void)
2380 if (accounts_window == NULL)
2381 return;
2383 if (accounts_window->window != NULL)
2384 gtk_widget_destroy(accounts_window->window);
2386 purple_signals_disconnect_by_handle(accounts_window);
2387 purple_prefs_disconnect_by_handle(accounts_window);
2389 g_free(accounts_window);
2390 accounts_window = NULL;
2393 static void
2394 free_add_user_data(PidginAccountAddUserData *data)
2396 g_free(data->username);
2397 g_free(data->alias);
2398 g_free(data);
2401 static void
2402 add_user_cb(PidginAccountAddUserData *data)
2404 PurpleConnection *gc = purple_account_get_connection(data->account);
2406 if (g_list_find(purple_connections_get_all(), gc))
2408 purple_blist_request_add_buddy(data->account, data->username,
2409 NULL, data->alias);
2412 free_add_user_data(data);
2415 static char *
2416 make_info(PurpleAccount *account, PurpleConnection *gc, const char *remote_user,
2417 const char *id, const char *alias, const char *msg)
2419 if (msg != NULL && *msg == '\0')
2420 msg = NULL;
2422 return g_strdup_printf(_("%s%s%s%s has made %s his or her buddy%s%s"),
2423 remote_user,
2424 (alias != NULL ? " (" : ""),
2425 (alias != NULL ? alias : ""),
2426 (alias != NULL ? ")" : ""),
2427 (id != NULL
2428 ? id
2429 : (purple_connection_get_display_name(gc) != NULL
2430 ? purple_connection_get_display_name(gc)
2431 : purple_account_get_username(account))),
2432 (msg != NULL ? ": " : "."),
2433 (msg != NULL ? msg : ""));
2436 static void
2437 pidgin_accounts_notify_added(PurpleAccount *account, const char *remote_user,
2438 const char *id, const char *alias,
2439 const char *msg)
2441 char *buffer;
2442 PurpleConnection *gc;
2443 GtkWidget *alert;
2445 gc = purple_account_get_connection(account);
2447 buffer = make_info(account, gc, remote_user, id, alias, msg);
2448 alert = pidgin_make_mini_dialog(gc, PIDGIN_STOCK_DIALOG_INFO, buffer,
2449 NULL, NULL, _("Close"), NULL, NULL);
2450 pidgin_blist_add_alert(alert);
2452 g_free(buffer);
2455 static void
2456 pidgin_accounts_request_add(PurpleAccount *account, const char *remote_user,
2457 const char *id, const char *alias,
2458 const char *msg)
2460 char *buffer;
2461 PurpleConnection *gc;
2462 PidginAccountAddUserData *data;
2463 GtkWidget *alert;
2465 gc = purple_account_get_connection(account);
2467 data = g_new0(PidginAccountAddUserData, 1);
2468 data->account = account;
2469 data->username = g_strdup(remote_user);
2470 data->alias = g_strdup(alias);
2472 buffer = make_info(account, gc, remote_user, id, alias, msg);
2473 alert = pidgin_make_mini_dialog(gc, PIDGIN_STOCK_DIALOG_QUESTION,
2474 _("Add buddy to your list?"), buffer, data,
2475 _("Add"), G_CALLBACK(add_user_cb),
2476 _("Cancel"), G_CALLBACK(free_add_user_data), NULL);
2477 pidgin_blist_add_alert(alert);
2479 g_free(buffer);
2482 struct auth_request
2484 PurpleAccountRequestAuthorizationCb auth_cb;
2485 PurpleAccountRequestAuthorizationCb deny_cb;
2486 void *data;
2487 char *username;
2488 char *alias;
2489 PurpleAccount *account;
2490 gboolean add_buddy_after_auth;
2493 static void
2494 free_auth_request(struct auth_request *ar)
2496 g_free(ar->username);
2497 g_free(ar->alias);
2498 g_free(ar);
2501 static void
2502 authorize_and_add_cb(struct auth_request *ar)
2504 ar->auth_cb(ar->data);
2505 if (ar->add_buddy_after_auth) {
2506 purple_blist_request_add_buddy(ar->account, ar->username, NULL, ar->alias);
2510 static void
2511 deny_no_add_cb(struct auth_request *ar)
2513 ar->deny_cb(ar->data);
2516 static gboolean
2517 get_user_info_cb(GtkWidget *label,
2518 const gchar *uri,
2519 gpointer data)
2521 struct auth_request *ar = data;
2522 if (purple_strequal(uri, "viewinfo")) {
2523 pidgin_retrieve_user_info(purple_account_get_connection(ar->account), ar->username);
2524 return TRUE;
2526 return FALSE;
2529 static void
2530 send_im_cb(PidginMiniDialog *mini_dialog,
2531 GtkButton *button,
2532 gpointer data)
2534 struct auth_request *ar = data;
2535 pidgin_dialogs_im_with_user(ar->account, ar->username);
2538 static void *
2539 pidgin_accounts_request_authorization(PurpleAccount *account,
2540 const char *remote_user,
2541 const char *id,
2542 const char *alias,
2543 const char *message,
2544 gboolean on_list,
2545 PurpleAccountRequestAuthorizationCb auth_cb,
2546 PurpleAccountRequestAuthorizationCb deny_cb,
2547 void *user_data)
2549 char *buffer;
2550 PurpleConnection *gc;
2551 GtkWidget *alert;
2552 PidginMiniDialog *dialog;
2553 GdkPixbuf *prpl_icon;
2554 struct auth_request *aa;
2555 const char *our_name;
2556 gboolean have_valid_alias = alias && *alias;
2558 gc = purple_account_get_connection(account);
2559 if (message != NULL && *message == '\0')
2560 message = NULL;
2562 our_name = (id != NULL) ? id :
2563 (purple_connection_get_display_name(gc) != NULL) ? purple_connection_get_display_name(gc) :
2564 purple_account_get_username(account);
2566 if (pidgin_mini_dialog_links_supported()) {
2567 char *escaped_remote_user = g_markup_escape_text(remote_user, -1);
2568 char *escaped_alias = alias != NULL ? g_markup_escape_text(alias, -1) : g_strdup("");
2569 char *escaped_our_name = g_markup_escape_text(our_name, -1);
2570 char *escaped_message = message != NULL ? g_markup_escape_text(message, -1) : g_strdup("");
2571 buffer = g_strdup_printf(_("<a href=\"viewinfo\">%s</a>%s%s%s wants to add you (%s) to his or her buddy list%s%s"),
2572 escaped_remote_user,
2573 (have_valid_alias ? " (" : ""),
2574 escaped_alias,
2575 (have_valid_alias ? ")" : ""),
2576 escaped_our_name,
2577 (have_valid_alias ? ": " : "."),
2578 escaped_message);
2579 g_free(escaped_remote_user);
2580 g_free(escaped_alias);
2581 g_free(escaped_our_name);
2582 g_free(escaped_message);
2583 } else {
2584 buffer = g_strdup_printf(_("%s%s%s%s wants to add you (%s) to his or her buddy list%s%s"),
2585 remote_user,
2586 (have_valid_alias ? " (" : ""),
2587 (have_valid_alias ? alias : ""),
2588 (have_valid_alias ? ")" : ""),
2589 our_name,
2590 (message != NULL ? ": " : "."),
2591 (message != NULL ? message : ""));
2594 prpl_icon = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_SMALL);
2596 aa = g_new0(struct auth_request, 1);
2597 aa->auth_cb = auth_cb;
2598 aa->deny_cb = deny_cb;
2599 aa->data = user_data;
2600 aa->username = g_strdup(remote_user);
2601 aa->alias = g_strdup(alias);
2602 aa->account = account;
2603 aa->add_buddy_after_auth = !on_list;
2605 alert = pidgin_make_mini_dialog_with_custom_icon(
2606 gc, prpl_icon,
2607 _("Authorize buddy?"), NULL, aa,
2608 _("Authorize"), authorize_and_add_cb,
2609 _("Deny"), deny_no_add_cb,
2610 NULL);
2612 dialog = PIDGIN_MINI_DIALOG(alert);
2613 if (pidgin_mini_dialog_links_supported()) {
2614 pidgin_mini_dialog_enable_description_markup(dialog);
2615 pidgin_mini_dialog_set_link_callback(dialog, G_CALLBACK(get_user_info_cb), aa);
2617 pidgin_mini_dialog_set_description(dialog, buffer);
2618 pidgin_mini_dialog_add_non_closing_button(dialog, _("Send Instant Message"), send_im_cb, aa);
2620 g_signal_connect_swapped(G_OBJECT(alert), "destroy", G_CALLBACK(free_auth_request), aa);
2621 g_signal_connect(G_OBJECT(alert), "destroy", G_CALLBACK(purple_account_request_close), NULL);
2622 pidgin_blist_add_alert(alert);
2624 g_free(buffer);
2626 return alert;
2629 static void
2630 pidgin_accounts_request_close(void *ui_handle)
2632 gtk_widget_destroy(GTK_WIDGET(ui_handle));
2635 static PurpleAccountUiOps ui_ops =
2637 pidgin_accounts_notify_added,
2638 NULL,
2639 pidgin_accounts_request_add,
2640 pidgin_accounts_request_authorization,
2641 pidgin_accounts_request_close,
2642 NULL,
2643 NULL,
2644 NULL,
2645 NULL
2648 PurpleAccountUiOps *
2649 pidgin_accounts_get_ui_ops(void)
2651 return &ui_ops;
2654 void *
2655 pidgin_account_get_handle(void) {
2656 static int handle;
2658 return &handle;
2661 void
2662 pidgin_account_init(void)
2664 char *default_avatar = NULL;
2665 purple_prefs_add_none(PIDGIN_PREFS_ROOT "/accounts");
2666 purple_prefs_add_none(PIDGIN_PREFS_ROOT "/accounts/dialog");
2667 purple_prefs_add_int(PIDGIN_PREFS_ROOT "/accounts/dialog/width", 520);
2668 purple_prefs_add_int(PIDGIN_PREFS_ROOT "/accounts/dialog/height", 321);
2669 default_avatar = g_build_filename(g_get_home_dir(), ".face.icon", NULL);
2670 if (!g_file_test(default_avatar, G_FILE_TEST_EXISTS)) {
2671 g_free(default_avatar);
2672 default_avatar = g_build_filename(g_get_home_dir(), ".face", NULL);
2673 if (!g_file_test(default_avatar, G_FILE_TEST_EXISTS)) {
2674 g_free(default_avatar);
2675 default_avatar = NULL;
2679 purple_prefs_add_path(PIDGIN_PREFS_ROOT "/accounts/buddyicon", default_avatar);
2680 g_free(default_avatar);
2682 purple_signal_register(pidgin_account_get_handle(), "account-modified",
2683 purple_marshal_VOID__POINTER, NULL, 1,
2684 purple_value_new(PURPLE_TYPE_SUBTYPE,
2685 PURPLE_SUBTYPE_ACCOUNT));
2687 /* Setup some purple signal handlers. */
2688 purple_signal_connect(purple_connections_get_handle(), "signed-on",
2689 pidgin_account_get_handle(),
2690 PURPLE_CALLBACK(signed_on_off_cb), NULL);
2691 purple_signal_connect(purple_connections_get_handle(), "signed-off",
2692 pidgin_account_get_handle(),
2693 PURPLE_CALLBACK(signed_on_off_cb), NULL);
2694 purple_signal_connect(purple_accounts_get_handle(), "account-added",
2695 pidgin_account_get_handle(),
2696 PURPLE_CALLBACK(add_account_to_liststore), NULL);
2697 purple_signal_connect(purple_accounts_get_handle(), "account-removed",
2698 pidgin_account_get_handle(),
2699 PURPLE_CALLBACK(account_removed_cb), NULL);
2700 purple_signal_connect(purple_accounts_get_handle(), "account-disabled",
2701 pidgin_account_get_handle(),
2702 PURPLE_CALLBACK(account_abled_cb), GINT_TO_POINTER(FALSE));
2703 purple_signal_connect(purple_accounts_get_handle(), "account-enabled",
2704 pidgin_account_get_handle(),
2705 PURPLE_CALLBACK(account_abled_cb), GINT_TO_POINTER(TRUE));
2707 account_pref_wins =
2708 g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, NULL);
2711 void
2712 pidgin_account_uninit(void)
2715 * TODO: Need to free all the dialogs in here. Could probably create
2716 * a callback function to use for the free-some-data-function
2717 * parameter of g_hash_table_new_full, above.
2719 g_hash_table_destroy(account_pref_wins);
2721 purple_signals_disconnect_by_handle(pidgin_account_get_handle());
2722 purple_signals_unregister_by_instance(pidgin_account_get_handle());