1 /**
2 * @file gntaccount.c GNT Account API
3 * @ingroup finch
4 */
5
6 /* finch
7 *
8 * Finch 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.
11 *
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.
16 *
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.
21 *
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
25 */
26 #include <internal.h>
27
28 #include <gnt.h>
29 #include <gntbox.h>
30 #include <gntbutton.h>
31 #include <gntcheckbox.h>
32 #include <gntcombobox.h>
33 #include <gntentry.h>
34 #include <gntlabel.h>
35 #include <gntline.h>
36 #include <gnttree.h>
37 #include <gntutils.h>
38 #include <gntwindow.h>
39
40 #include "finch.h"
41
42 #include <account.h>
43 #include <accountopt.h>
44 #include <connection.h>
45 #include <notify.h>
46 #include <plugin.h>
47 #include <request.h>
48 #include <savedstatuses.h>
49
50 #include "gntaccount.h"
51 #include "gntblist.h"
52
53 #include <string.h>
54
55 typedef struct
56 {
57 GntWidget *window;
58 GntWidget *tree;
59 } FinchAccountList;
60
61 static FinchAccountList accounts;
62
63 typedef struct
64 {
65 PurpleAccount *account; /* NULL for a new account */
66
67 GntWidget *window;
68
69 GntWidget *protocol;
70 GntWidget *username;
71 GntWidget *password;
72 GntWidget *alias;
73
74 GntWidget *splits;
75 GList *split_entries;
76
77 GList *prpl_entries;
78 GntWidget *prpls;
79
80 GntWidget *newmail;
81 GntWidget *remember;
82 GntWidget *regserver;
83 } AccountEditDialog;
84
85 /* This is necessary to close an edit-dialog when an account is deleted */
86 static GList *accountdialogs;
87
88 static void
account_add(PurpleAccount * account)89 account_add(PurpleAccount *account)
90 {
91 gnt_tree_add_choice(GNT_TREE(accounts.tree), account,
92 gnt_tree_create_row(GNT_TREE(accounts.tree),
93 purple_account_get_username(account),
94 purple_account_get_protocol_name(account)),
95 NULL, NULL);
96 gnt_tree_set_choice(GNT_TREE(accounts.tree), account,
97 purple_account_get_enabled(account, FINCH_UI));
98 }
99
100 static void
edit_dialog_destroy(AccountEditDialog * dialog)101 edit_dialog_destroy(AccountEditDialog *dialog)
102 {
103 accountdialogs = g_list_remove(accountdialogs, dialog);
104 g_list_free(dialog->prpl_entries);
105 g_list_free(dialog->split_entries);
106 g_free(dialog);
107 }
108
109 static void
save_account_cb(AccountEditDialog * dialog)110 save_account_cb(AccountEditDialog *dialog)
111 {
112 PurpleAccount *account;
113 PurplePlugin *plugin;
114 PurplePluginProtocolInfo *prplinfo;
115 const char *value;
116 GString *username;
117
118 /* XXX: Do some error checking first. */
119
120 plugin = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(dialog->protocol));
121 prplinfo = PURPLE_PLUGIN_PROTOCOL_INFO(plugin);
122
123 /* Username && user-splits */
124 value = gnt_entry_get_text(GNT_ENTRY(dialog->username));
125
126 if (value == NULL || *value == '\0')
127 {
128 purple_notify_error(NULL, _("Error"),
129 dialog->account ? _("Account was not modified") : _("Account was not added"),
130 _("Username of an account must be non-empty."));
131 return;
132 }
133
134 username = g_string_new(value);
135
136 if (prplinfo != NULL)
137 {
138 GList *iter, *entries;
139 for (iter = prplinfo->user_splits, entries = dialog->split_entries;
140 iter && entries; iter = iter->next, entries = entries->next)
141 {
142 PurpleAccountUserSplit *split = iter->data;
143 GntWidget *entry = entries->data;
144
145 value = gnt_entry_get_text(GNT_ENTRY(entry));
146 if (value == NULL || *value == '\0')
147 value = purple_account_user_split_get_default_value(split);
148 g_string_append_printf(username, "%c%s",
149 purple_account_user_split_get_separator(split),
150 value);
151 }
152 }
153
154 if (dialog->account == NULL)
155 {
156 account = purple_account_new(username->str, purple_plugin_get_id(plugin));
157 purple_accounts_add(account);
158 }
159 else
160 {
161 account = dialog->account;
162
163 /* Protocol */
164 if (purple_account_is_disconnected(account)) {
165 purple_account_set_protocol_id(account, purple_plugin_get_id(plugin));
166 purple_account_set_username(account, username->str);
167 } else {
168 const char *old = purple_account_get_protocol_id(account);
169 char *oldprpl;
170 if (!purple_strequal(old, purple_plugin_get_id(plugin))) {
171 purple_notify_error(NULL, _("Error"), _("Account was not modified"),
172 _("The account's protocol cannot be changed while it is connected to the server."));
173 return;
174 }
175
176 oldprpl = g_strdup(purple_normalize(account, purple_account_get_username(account)));
177 if (g_utf8_collate(oldprpl, purple_normalize(account, username->str))) {
178 purple_notify_error(NULL, _("Error"), _("Account was not modified"),
179 _("The account's username cannot be changed while it is connected to the server."));
180 g_free(oldprpl);
181 return;
182 }
183 g_free(oldprpl);
184 purple_account_set_username(account, username->str);
185 }
186 }
187 g_string_free(username, TRUE);
188
189 /* Alias */
190 value = gnt_entry_get_text(GNT_ENTRY(dialog->alias));
191 purple_account_set_alias(account, value);
192
193 /* Remember password and password */
194 purple_account_set_remember_password(account,
195 gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->remember)));
196 value = gnt_entry_get_text(GNT_ENTRY(dialog->password));
197 if (value && *value)
198 purple_account_set_password(account, value);
199 else
200 purple_account_set_password(account, NULL);
201
202 /* Mail notification */
203 purple_account_set_check_mail(account,
204 gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->newmail)));
205
206 /* Protocol options */
207 if (prplinfo)
208 {
209 GList *iter, *entries;
210
211 for (iter = prplinfo->protocol_options, entries = dialog->prpl_entries;
212 iter && entries; iter = iter->next, entries = entries->next)
213 {
214 PurpleAccountOption *option = iter->data;
215 GntWidget *entry = entries->data;
216 PurplePrefType type = purple_account_option_get_type(option);
217 const char *setting = purple_account_option_get_setting(option);
218
219 if (type == PURPLE_PREF_STRING)
220 {
221 const char *value = gnt_entry_get_text(GNT_ENTRY(entry));
222 purple_account_set_string(account, setting, value);
223 }
224 else if (type == PURPLE_PREF_INT)
225 {
226 const char *str = gnt_entry_get_text(GNT_ENTRY(entry));
227 int value = 0;
228 if (str)
229 value = atoi(str);
230 purple_account_set_int(account, setting, value);
231 }
232 else if (type == PURPLE_PREF_BOOLEAN)
233 {
234 gboolean value = gnt_check_box_get_checked(GNT_CHECK_BOX(entry));
235 purple_account_set_bool(account, setting, value);
236 }
237 else if (type == PURPLE_PREF_STRING_LIST)
238 {
239 gchar *value = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(entry));
240 purple_account_set_string(account, setting, value);
241 }
242 else
243 {
244 g_assert_not_reached();
245 }
246 }
247 }
248
249 /* XXX: Proxy options */
250
251 if (accounts.window && accounts.tree) {
252 gnt_tree_set_selected(GNT_TREE(accounts.tree), account);
253 gnt_box_give_focus_to_child(GNT_BOX(accounts.window), accounts.tree);
254 }
255
256 if (prplinfo && prplinfo->register_user &&
257 gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->regserver))) {
258 purple_account_register(account);
259 } else if (dialog->account == NULL) {
260 /* This is a new account. Set it to the current status. */
261 /* Xerox from gtkaccount.c :D */
262 const PurpleSavedStatus *saved_status;
263 saved_status = purple_savedstatus_get_current();
264 if (saved_status != NULL) {
265 purple_savedstatus_activate_for_account(saved_status, account);
266 purple_account_set_enabled(account, FINCH_UI, TRUE);
267 }
268 }
269
270 /* In case of a new account, the 'Accounts' window is updated from the account-added
271 * callback. In case of changes in an existing account, we need to explicitly do it
272 * here.
273 */
274 if (dialog->account != NULL && accounts.window) {
275 gnt_tree_change_text(GNT_TREE(accounts.tree), dialog->account,
276 0, purple_account_get_username(dialog->account));
277 gnt_tree_change_text(GNT_TREE(accounts.tree), dialog->account,
278 1, purple_account_get_protocol_name(dialog->account));
279 }
280
281 gnt_widget_destroy(dialog->window);
282 }
283
284 static void
update_user_splits(AccountEditDialog * dialog)285 update_user_splits(AccountEditDialog *dialog)
286 {
287 GntWidget *hbox;
288 PurplePlugin *plugin;
289 PurplePluginProtocolInfo *prplinfo;
290 GList *iter, *entries;
291 char *username = NULL;
292
293 if (dialog->splits)
294 {
295 gnt_box_remove_all(GNT_BOX(dialog->splits));
296 g_list_free(dialog->split_entries);
297 }
298 else
299 {
300 dialog->splits = gnt_vbox_new(FALSE);
301 gnt_box_set_pad(GNT_BOX(dialog->splits), 0);
302 gnt_box_set_fill(GNT_BOX(dialog->splits), TRUE);
303 }
304
305 dialog->split_entries = NULL;
306
307 plugin = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(dialog->protocol));
308 if (!plugin)
309 return;
310 prplinfo = PURPLE_PLUGIN_PROTOCOL_INFO(plugin);
311
312 username = dialog->account ? g_strdup(purple_account_get_username(dialog->account)) : NULL;
313
314 for (iter = prplinfo->user_splits; iter; iter = iter->next)
315 {
316 PurpleAccountUserSplit *split = iter->data;
317 GntWidget *entry;
318 char *buf;
319
320 hbox = gnt_hbox_new(TRUE);
321 gnt_box_add_widget(GNT_BOX(dialog->splits), hbox);
322
323 buf = g_strdup_printf("%s:", purple_account_user_split_get_text(split));
324 gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new(buf));
325
326 entry = gnt_entry_new(NULL);
327 gnt_box_add_widget(GNT_BOX(hbox), entry);
328
329 dialog->split_entries = g_list_append(dialog->split_entries, entry);
330 g_free(buf);
331 }
332
333 for (iter = g_list_last(prplinfo->user_splits), entries = g_list_last(dialog->split_entries);
334 iter && entries; iter = iter->prev, entries = entries->prev)
335 {
336 GntWidget *entry = entries->data;
337 PurpleAccountUserSplit *split = iter->data;
338 const char *value = NULL;
339 char *s;
340
341 if (dialog->account)
342 {
343 if(purple_account_user_split_get_reverse(split))
344 s = strrchr(username, purple_account_user_split_get_separator(split));
345 else
346 s = strchr(username, purple_account_user_split_get_separator(split));
347
348 if (s != NULL)
349 {
350 *s = '\0';
351 s++;
352 value = s;
353 }
354 }
355 if (value == NULL)
356 value = purple_account_user_split_get_default_value(split);
357
358 if (value != NULL)
359 gnt_entry_set_text(GNT_ENTRY(entry), value);
360 }
361
362 if (username != NULL)
363 gnt_entry_set_text(GNT_ENTRY(dialog->username), username);
364
365 g_free(username);
366 }
367
368 static void
add_protocol_options(AccountEditDialog * dialog)369 add_protocol_options(AccountEditDialog *dialog)
370 {
371 PurplePlugin *plugin;
372 PurplePluginProtocolInfo *prplinfo;
373 GList *iter;
374 GntWidget *vbox, *box;
375 PurpleAccount *account;
376
377 if (dialog->prpls)
378 gnt_box_remove_all(GNT_BOX(dialog->prpls));
379 else
380 {
381 dialog->prpls = vbox = gnt_vbox_new(FALSE);
382 gnt_box_set_pad(GNT_BOX(vbox), 0);
383 gnt_box_set_alignment(GNT_BOX(vbox), GNT_ALIGN_LEFT);
384 gnt_box_set_fill(GNT_BOX(vbox), TRUE);
385 }
386
387 if (dialog->prpl_entries)
388 {
389 g_list_free(dialog->prpl_entries);
390 dialog->prpl_entries = NULL;
391 }
392
393 vbox = dialog->prpls;
394
395 plugin = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(dialog->protocol));
396 if (!plugin)
397 return;
398
399 prplinfo = PURPLE_PLUGIN_PROTOCOL_INFO(plugin);
400
401 account = dialog->account;
402
403 for (iter = prplinfo->protocol_options; iter; iter = iter->next)
404 {
405 PurpleAccountOption *option = iter->data;
406 PurplePrefType type = purple_account_option_get_type(option);
407
408 box = gnt_hbox_new(TRUE);
409 gnt_box_set_pad(GNT_BOX(box), 0);
410 gnt_box_add_widget(GNT_BOX(vbox), box);
411
412 if (type == PURPLE_PREF_BOOLEAN)
413 {
414 GntWidget *widget = gnt_check_box_new(purple_account_option_get_text(option));
415 gnt_box_add_widget(GNT_BOX(box), widget);
416 dialog->prpl_entries = g_list_append(dialog->prpl_entries, widget);
417
418 if (account)
419 gnt_check_box_set_checked(GNT_CHECK_BOX(widget),
420 purple_account_get_bool(account,
421 purple_account_option_get_setting(option),
422 purple_account_option_get_default_bool(option)));
423 else
424 gnt_check_box_set_checked(GNT_CHECK_BOX(widget),
425 purple_account_option_get_default_bool(option));
426 }
427 else
428 {
429 gnt_box_add_widget(GNT_BOX(box),
430 gnt_label_new(purple_account_option_get_text(option)));
431
432 if (type == PURPLE_PREF_STRING_LIST)
433 {
434 GntWidget *combo = gnt_combo_box_new();
435 GList *opt_iter = purple_account_option_get_list(option);
436 const char *dv = purple_account_option_get_default_list_value(option);
437 const char *active = dv;
438
439 if (account)
440 active = purple_account_get_string(account,
441 purple_account_option_get_setting(option), dv);
442
443 gnt_box_add_widget(GNT_BOX(box), combo);
444 dialog->prpl_entries = g_list_append(dialog->prpl_entries, combo);
445
446 for ( ; opt_iter; opt_iter = opt_iter->next)
447 {
448 PurpleKeyValuePair *kvp = opt_iter->data;
449 gnt_combo_box_add_data(GNT_COMBO_BOX(combo), kvp->value, kvp->key);
450
451 if (purple_strequal(kvp->value, active))
452 gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), kvp->value);
453 }
454 }
455 else
456 {
457 GntWidget *entry = gnt_entry_new(NULL);
458 gnt_box_add_widget(GNT_BOX(box), entry);
459 dialog->prpl_entries = g_list_append(dialog->prpl_entries, entry);
460
461 if (type == PURPLE_PREF_STRING)
462 {
463 const char *dv = purple_account_option_get_default_string(option);
464
465 if (account)
466 gnt_entry_set_text(GNT_ENTRY(entry),
467 purple_account_get_string(account,
468 purple_account_option_get_setting(option), dv));
469 else
470 gnt_entry_set_text(GNT_ENTRY(entry), dv);
471 }
472 else if (type == PURPLE_PREF_INT)
473 {
474 char str[32];
475 int value = purple_account_option_get_default_int(option);
476 if (account)
477 value = purple_account_get_int(account,
478 purple_account_option_get_setting(option), value);
479 snprintf(str, sizeof(str), "%d", value);
480 gnt_entry_set_flag(GNT_ENTRY(entry), GNT_ENTRY_FLAG_INT);
481 gnt_entry_set_text(GNT_ENTRY(entry), str);
482 }
483 else
484 {
485 g_assert_not_reached();
486 }
487 }
488 }
489 }
490
491 /* Show the registration checkbox only in a new account dialog,
492 * and when the selected prpl has the support for it. */
493 gnt_widget_set_visible(dialog->regserver, account == NULL &&
494 prplinfo->register_user != NULL);
495 }
496
497 static void
update_user_options(AccountEditDialog * dialog)498 update_user_options(AccountEditDialog *dialog)
499 {
500 PurplePlugin *plugin;
501 PurplePluginProtocolInfo *prplinfo;
502
503 plugin = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(dialog->protocol));
504 if (!plugin)
505 return;
506
507 prplinfo = PURPLE_PLUGIN_PROTOCOL_INFO(plugin);
508
509 if (dialog->newmail == NULL)
510 dialog->newmail = gnt_check_box_new(_("New mail notifications"));
511 if (dialog->account)
512 gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->newmail),
513 purple_account_get_check_mail(dialog->account));
514 if (!prplinfo || !(prplinfo->options & OPT_PROTO_MAIL_CHECK))
515 gnt_widget_set_visible(dialog->newmail, FALSE);
516 else
517 gnt_widget_set_visible(dialog->newmail, TRUE);
518
519 if (dialog->remember == NULL)
520 dialog->remember = gnt_check_box_new(_("Remember password"));
521 if (dialog->account)
522 gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->remember),
523 purple_account_get_remember_password(dialog->account));
524 }
525
526 static void
prpl_changed_cb(GntWidget * combo,PurplePlugin * old,PurplePlugin * new,AccountEditDialog * dialog)527 prpl_changed_cb(GntWidget *combo, PurplePlugin *old, PurplePlugin *new, AccountEditDialog *dialog)
528 {
529 update_user_splits(dialog);
530 add_protocol_options(dialog);
531 update_user_options(dialog); /* This may not be necessary here */
532 gnt_box_readjust(GNT_BOX(dialog->window));
533 gnt_widget_draw(dialog->window);
534 }
535
536 static void
edit_account(PurpleAccount * account)537 edit_account(PurpleAccount *account)
538 {
539 GntWidget *window, *hbox;
540 GntWidget *combo, *button, *entry;
541 GList *list, *iter;
542 AccountEditDialog *dialog;
543 PurplePlugin *plugin;
544
545 if (account)
546 {
547 GList *iter;
548 for (iter = accountdialogs; iter; iter = iter->next)
549 {
550 AccountEditDialog *dlg = iter->data;
551 if (dlg->account == account)
552 return;
553 }
554 }
555
556 list = purple_plugins_get_protocols();
557 if (list == NULL) {
558 purple_notify_error(NULL, _("Error"),
559 _("There are no protocol plugins installed."),
560 _("(You probably forgot to 'make install'.)"));
561 return;
562 }
563
564 dialog = g_new0(AccountEditDialog, 1);
565 accountdialogs = g_list_prepend(accountdialogs, dialog);
566
567 dialog->window = window = gnt_vbox_new(FALSE);
568 dialog->account = account;
569 gnt_box_set_toplevel(GNT_BOX(window), TRUE);
570 gnt_box_set_title(GNT_BOX(window), account ? _("Modify Account") : _("New Account"));
571 gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID);
572 gnt_box_set_pad(GNT_BOX(window), 0);
573 gnt_widget_set_name(window, "edit-account");
574 gnt_box_set_fill(GNT_BOX(window), TRUE);
575
576 hbox = gnt_hbox_new(TRUE);
577 gnt_box_set_pad(GNT_BOX(hbox), 0);
578 gnt_box_add_widget(GNT_BOX(window), hbox);
579
580 dialog->protocol = combo = gnt_combo_box_new();
581 for (iter = list; iter; iter = iter->next)
582 {
583 gnt_combo_box_add_data(GNT_COMBO_BOX(combo), iter->data,
584 ((PurplePlugin*)iter->data)->info->name);
585 }
586
587 plugin = purple_plugins_find_with_id(purple_account_get_protocol_id(account));
588
589 if (account && plugin)
590 gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), plugin);
591 else
592 gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), list->data);
593
594 g_signal_connect(G_OBJECT(combo), "selection-changed", G_CALLBACK(prpl_changed_cb), dialog);
595
596 gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new(_("Protocol:")));
597 gnt_box_add_widget(GNT_BOX(hbox), combo);
598
599 hbox = gnt_hbox_new(TRUE);
600 gnt_box_set_pad(GNT_BOX(hbox), 0);
601 gnt_box_add_widget(GNT_BOX(window), hbox);
602
603 dialog->username = entry = gnt_entry_new(NULL);
604 gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new(_("Username:")));
605 gnt_box_add_widget(GNT_BOX(hbox), entry);
606
607 /* User splits */
608 update_user_splits(dialog);
609 gnt_box_add_widget(GNT_BOX(window), dialog->splits);
610
611 hbox = gnt_hbox_new(TRUE);
612 gnt_box_set_pad(GNT_BOX(hbox), 0);
613 gnt_box_add_widget(GNT_BOX(window), hbox);
614
615 dialog->password = entry = gnt_entry_new(NULL);
616 gnt_entry_set_masked(GNT_ENTRY(entry), TRUE);
617 gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new(_("Password:")));
618 gnt_box_add_widget(GNT_BOX(hbox), entry);
619 if (account)
620 gnt_entry_set_text(GNT_ENTRY(entry), purple_account_get_password(account));
621
622 hbox = gnt_hbox_new(TRUE);
623 gnt_box_set_pad(GNT_BOX(hbox), 0);
624 gnt_box_add_widget(GNT_BOX(window), hbox);
625
626 dialog->alias = entry = gnt_entry_new(NULL);
627 gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new(_("Alias:")));
628 gnt_box_add_widget(GNT_BOX(hbox), entry);
629 if (account)
630 gnt_entry_set_text(GNT_ENTRY(entry), purple_account_get_alias(account));
631
632 /* User options */
633 update_user_options(dialog);
634 gnt_box_add_widget(GNT_BOX(window), dialog->remember);
635 gnt_box_add_widget(GNT_BOX(window), dialog->newmail);
636
637 /* Register checkbox */
638 dialog->regserver = gnt_check_box_new(_("Create this account on the server"));
639 gnt_box_add_widget(GNT_BOX(window), dialog->regserver);
640
641 gnt_box_add_widget(GNT_BOX(window), gnt_line_new(FALSE));
642
643 /* The advanced box */
644 add_protocol_options(dialog);
645 gnt_box_add_widget(GNT_BOX(window), dialog->prpls);
646
647 /* TODO: Add proxy options */
648
649 /* The button box */
650 hbox = gnt_hbox_new(FALSE);
651 gnt_box_add_widget(GNT_BOX(window), hbox);
652 gnt_box_set_alignment(GNT_BOX(hbox), GNT_ALIGN_MID);
653
654 button = gnt_button_new(_("Cancel"));
655 gnt_box_add_widget(GNT_BOX(hbox), button);
656 g_signal_connect_swapped(G_OBJECT(button), "activate", G_CALLBACK(gnt_widget_destroy), window);
657
658 button = gnt_button_new(_("Save"));
659 gnt_box_add_widget(GNT_BOX(hbox), button);
660 g_signal_connect_swapped(G_OBJECT(button), "activate", G_CALLBACK(save_account_cb), dialog);
661
662 g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK(edit_dialog_destroy), dialog);
663
664 gnt_widget_show(window);
665 gnt_box_readjust(GNT_BOX(window));
666 gnt_widget_draw(window);
667 }
668
669 static void
add_account_cb(GntWidget * widget,gpointer null)670 add_account_cb(GntWidget *widget, gpointer null)
671 {
672 edit_account(NULL);
673 }
674
675 static void
modify_account_cb(GntWidget * widget,GntTree * tree)676 modify_account_cb(GntWidget *widget, GntTree *tree)
677 {
678 PurpleAccount *account = gnt_tree_get_selection_data(tree);
679 if (!account)
680 return;
681 edit_account(account);
682 }
683
684 static void
really_delete_account(PurpleAccount * account)685 really_delete_account(PurpleAccount *account)
686 {
687 GList *iter;
688 for (iter = accountdialogs; iter; iter = iter->next)
689 {
690 AccountEditDialog *dlg = iter->data;
691 if (dlg->account == account)
692 {
693 gnt_widget_destroy(dlg->window);
694 break;
695 }
696 }
697 purple_request_close_with_handle(account); /* Close any other opened delete window */
698 purple_accounts_delete(account);
699 }
700
701 static void
delete_account_cb(GntWidget * widget,GntTree * tree)702 delete_account_cb(GntWidget *widget, GntTree *tree)
703 {
704 PurpleAccount *account;
705 char *prompt;
706
707 account = gnt_tree_get_selection_data(tree);
708 if (!account)
709 return;
710
711 prompt = g_strdup_printf(_("Are you sure you want to delete %s?"),
712 purple_account_get_username(account));
713
714 purple_request_action(account, _("Delete Account"), prompt, NULL,
715 PURPLE_DEFAULT_ACTION_NONE,
716 account, NULL, NULL, account, 2,
717 _("Delete"), really_delete_account,
718 _("Cancel"), NULL);
719 g_free(prompt);
720 }
721
722 static void
account_toggled(GntWidget * widget,void * key,gpointer null)723 account_toggled(GntWidget *widget, void *key, gpointer null)
724 {
725 PurpleAccount *account = key;
726 gboolean enabled = gnt_tree_get_choice(GNT_TREE(widget), key);
727
728 if (enabled)
729 purple_savedstatus_activate_for_account(purple_savedstatus_get_current(),
730 account);
731
732 purple_account_set_enabled(account, FINCH_UI, enabled);
733 }
734
735 static gboolean
account_list_key_pressed_cb(GntWidget * widget,const char * text,gpointer null)736 account_list_key_pressed_cb(GntWidget *widget, const char *text, gpointer null)
737 {
738 GntTree *tree = GNT_TREE(widget);
739 PurpleAccount *account = gnt_tree_get_selection_data(tree);
740 int move, pos, count;
741 GList *accounts;
742
743 if (!account)
744 return FALSE;
745
746 switch (text[0]) {
747 case '-':
748 move = -1;
749 break;
750 case '=':
751 move = 2; /* XXX: This seems to be a bug in libpurple */
752 break;
753 default:
754 return FALSE;
755 }
756
757 accounts = purple_accounts_get_all();
758 count = g_list_length(accounts);
759 pos = g_list_index(accounts, account);
760 pos = (move + pos + count + 1) % (count + 1);
761 purple_accounts_reorder(account, pos);
762
763 /* I don't like this, but recreating the entire list seems to be
764 * the easiest way of doing it */
765 gnt_tree_remove_all(tree);
766 accounts = purple_accounts_get_all();
767 for (; accounts; accounts = accounts->next)
768 account_add(accounts->data);
769 gnt_tree_set_selected(tree, account);
770
771 return TRUE;
772 }
773
774 static void
reset_accounts_win(GntWidget * widget,gpointer null)775 reset_accounts_win(GntWidget *widget, gpointer null)
776 {
777 accounts.window = NULL;
778 accounts.tree = NULL;
779 }
780
finch_accounts_show_all()781 void finch_accounts_show_all()
782 {
783 GList *iter;
784 GntWidget *box, *button;
785
786 if (accounts.window) {
787 gnt_window_present(accounts.window);
788 return;
789 }
790
791 accounts.window = gnt_vbox_new(FALSE);
792 gnt_box_set_toplevel(GNT_BOX(accounts.window), TRUE);
793 gnt_box_set_title(GNT_BOX(accounts.window), _("Accounts"));
794 gnt_box_set_pad(GNT_BOX(accounts.window), 0);
795 gnt_box_set_alignment(GNT_BOX(accounts.window), GNT_ALIGN_MID);
796 gnt_widget_set_name(accounts.window, "accounts");
797
798 gnt_box_add_widget(GNT_BOX(accounts.window),
799 gnt_label_new(_("You can enable/disable accounts from the following list.")));
800
801 gnt_box_add_widget(GNT_BOX(accounts.window), gnt_line_new(FALSE));
802
803 accounts.tree = gnt_tree_new_with_columns(2);
804 gnt_widget_set_has_border(accounts.tree, FALSE);
805
806 for (iter = purple_accounts_get_all(); iter; iter = iter->next)
807 {
808 PurpleAccount *account = iter->data;
809 account_add(account);
810 }
811
812 g_signal_connect(G_OBJECT(accounts.tree), "toggled", G_CALLBACK(account_toggled), NULL);
813 g_signal_connect(G_OBJECT(accounts.tree), "key_pressed", G_CALLBACK(account_list_key_pressed_cb), NULL);
814
815 gnt_tree_set_col_width(GNT_TREE(accounts.tree), 0, 40);
816 gnt_tree_set_col_width(GNT_TREE(accounts.tree), 1, 10);
817 gnt_box_add_widget(GNT_BOX(accounts.window), accounts.tree);
818
819 gnt_box_add_widget(GNT_BOX(accounts.window), gnt_line_new(FALSE));
820
821 box = gnt_hbox_new(FALSE);
822
823 button = gnt_button_new(_("Add"));
824 gnt_box_add_widget(GNT_BOX(box), button);
825 gnt_util_set_trigger_widget(GNT_WIDGET(accounts.tree), GNT_KEY_INS, button);
826 g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(add_account_cb), NULL);
827
828 button = gnt_button_new(_("Modify"));
829 gnt_box_add_widget(GNT_BOX(box), button);
830 g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(modify_account_cb), accounts.tree);
831
832 button = gnt_button_new(_("Delete"));
833 gnt_box_add_widget(GNT_BOX(box), button);
834 gnt_util_set_trigger_widget(GNT_WIDGET(accounts.tree), GNT_KEY_DEL, button);
835 g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(delete_account_cb), accounts.tree);
836
837 gnt_box_add_widget(GNT_BOX(accounts.window), box);
838
839 g_signal_connect(G_OBJECT(accounts.window), "destroy", G_CALLBACK(reset_accounts_win), NULL);
840
841 gnt_widget_show(accounts.window);
842 }
843
finch_account_dialog_show(PurpleAccount * account)844 void finch_account_dialog_show(PurpleAccount *account)
845 {
846 edit_account(account);
847 }
848
849 static gpointer
finch_accounts_get_handle(void)850 finch_accounts_get_handle(void)
851 {
852 static int handle;
853
854 return &handle;
855 }
856
857 static void
account_added_callback(PurpleAccount * account)858 account_added_callback(PurpleAccount *account)
859 {
860 if (accounts.window == NULL)
861 return;
862 account_add(account);
863 gnt_widget_draw(accounts.tree);
864 }
865
866 static void
account_removed_callback(PurpleAccount * account)867 account_removed_callback(PurpleAccount *account)
868 {
869 if (accounts.window == NULL)
870 return;
871
872 gnt_tree_remove(GNT_TREE(accounts.tree), account);
873 }
874
875 static void
account_abled_cb(PurpleAccount * account,gpointer user_data)876 account_abled_cb(PurpleAccount *account, gpointer user_data)
877 {
878 if (accounts.window == NULL)
879 return;
880 gnt_tree_set_choice(GNT_TREE(accounts.tree), account,
881 GPOINTER_TO_INT(user_data));
882 }
883
finch_accounts_init()884 void finch_accounts_init()
885 {
886 GList *iter;
887
888 purple_signal_connect(purple_accounts_get_handle(), "account-added",
889 finch_accounts_get_handle(), PURPLE_CALLBACK(account_added_callback),
890 NULL);
891 purple_signal_connect(purple_accounts_get_handle(), "account-removed",
892 finch_accounts_get_handle(), PURPLE_CALLBACK(account_removed_callback),
893 NULL);
894 purple_signal_connect(purple_accounts_get_handle(), "account-disabled",
895 finch_accounts_get_handle(),
896 PURPLE_CALLBACK(account_abled_cb), GINT_TO_POINTER(FALSE));
897 purple_signal_connect(purple_accounts_get_handle(), "account-enabled",
898 finch_accounts_get_handle(),
899 PURPLE_CALLBACK(account_abled_cb), GINT_TO_POINTER(TRUE));
900
901 iter = purple_accounts_get_all();
902 if (iter) {
903 for (; iter; iter = iter->next) {
904 if (purple_account_get_enabled(iter->data, FINCH_UI))
905 break;
906 }
907 if (!iter)
908 finch_accounts_show_all();
909 } else {
910 edit_account(NULL);
911 finch_accounts_show_all();
912 }
913 }
914
finch_accounts_uninit()915 void finch_accounts_uninit()
916 {
917 if (accounts.window)
918 gnt_widget_destroy(accounts.window);
919 }
920
921 /* The following uiops stuff are copied from gtkaccount.c */
922 typedef struct
923 {
924 PurpleAccount *account;
925 char *username;
926 char *alias;
927 } AddUserData;
928
929 static char *
make_info(PurpleAccount * account,PurpleConnection * gc,const char * remote_user,const char * id,const char * alias,const char * msg)930 make_info(PurpleAccount *account, PurpleConnection *gc, const char *remote_user,
931 const char *id, const char *alias, const char *msg)
932 {
933 if (msg != NULL && *msg == '\0')
934 msg = NULL;
935
936 return g_strdup_printf(_("%s%s%s%s has made %s his or her buddy%s%s"),
937 remote_user,
938 (alias != NULL ? " (" : ""),
939 (alias != NULL ? alias : ""),
940 (alias != NULL ? ")" : ""),
941 (id != NULL
942 ? id
943 : (purple_connection_get_display_name(gc) != NULL
944 ? purple_connection_get_display_name(gc)
945 : purple_account_get_username(account))),
946 (msg != NULL ? ": " : "."),
947 (msg != NULL ? msg : ""));
948 }
949
950 static void
notify_added(PurpleAccount * account,const char * remote_user,const char * id,const char * alias,const char * msg)951 notify_added(PurpleAccount *account, const char *remote_user,
952 const char *id, const char *alias,
953 const char *msg)
954 {
955 char *buffer;
956 PurpleConnection *gc;
957
958 gc = purple_account_get_connection(account);
959
960 buffer = make_info(account, gc, remote_user, id, alias, msg);
961
962 purple_notify_info(NULL, NULL, buffer, NULL);
963
964 g_free(buffer);
965 }
966
967 static void
free_add_user_data(AddUserData * data)968 free_add_user_data(AddUserData *data)
969 {
970 g_free(data->username);
971
972 if (data->alias != NULL)
973 g_free(data->alias);
974
975 g_free(data);
976 }
977
978 static void
add_user_cb(AddUserData * data)979 add_user_cb(AddUserData *data)
980 {
981 PurpleConnection *gc = purple_account_get_connection(data->account);
982
983 if (g_list_find(purple_connections_get_all(), gc))
984 {
985 purple_blist_request_add_buddy(data->account, data->username,
986 NULL, data->alias);
987 }
988
989 free_add_user_data(data);
990 }
991
992 static void
request_add(PurpleAccount * account,const char * remote_user,const char * id,const char * alias,const char * msg)993 request_add(PurpleAccount *account, const char *remote_user,
994 const char *id, const char *alias,
995 const char *msg)
996 {
997 char *buffer;
998 PurpleConnection *gc;
999 AddUserData *data;
1000
1001 gc = purple_account_get_connection(account);
1002
1003 data = g_new0(AddUserData, 1);
1004 data->account = account;
1005 data->username = g_strdup(remote_user);
1006 data->alias = (alias != NULL ? g_strdup(alias) : NULL);
1007
1008 buffer = make_info(account, gc, remote_user, id, alias, msg);
1009 purple_request_action(NULL, NULL, _("Add buddy to your list?"),
1010 buffer, PURPLE_DEFAULT_ACTION_NONE,
1011 account, remote_user, NULL,
1012 data, 2,
1013 _("Add"), G_CALLBACK(add_user_cb),
1014 _("Cancel"), G_CALLBACK(free_add_user_data));
1015 g_free(buffer);
1016 }
1017
1018 /* Copied from gtkaccount.c */
1019 typedef struct {
1020 PurpleAccountRequestAuthorizationCb auth_cb;
1021 PurpleAccountRequestAuthorizationCb deny_cb;
1022 void *data;
1023 char *username;
1024 char *alias;
1025 PurpleAccount *account;
1026 } auth_and_add;
1027
1028 static void
free_auth_and_add(auth_and_add * aa)1029 free_auth_and_add(auth_and_add *aa)
1030 {
1031 g_free(aa->username);
1032 g_free(aa->alias);
1033 g_free(aa);
1034 }
1035
1036 static void
authorize_and_add_cb(auth_and_add * aa)1037 authorize_and_add_cb(auth_and_add *aa)
1038 {
1039 aa->auth_cb(aa->data);
1040 purple_blist_request_add_buddy(aa->account, aa->username,
1041 NULL, aa->alias);
1042 }
1043
1044 static void
deny_no_add_cb(auth_and_add * aa)1045 deny_no_add_cb(auth_and_add *aa)
1046 {
1047 aa->deny_cb(aa->data);
1048 }
1049
1050 static void *
finch_request_authorize(PurpleAccount * account,const char * remote_user,const char * id,const char * alias,const char * message,gboolean on_list,PurpleAccountRequestAuthorizationCb auth_cb,PurpleAccountRequestAuthorizationCb deny_cb,void * user_data)1051 finch_request_authorize(PurpleAccount *account,
1052 const char *remote_user,
1053 const char *id,
1054 const char *alias,
1055 const char *message,
1056 gboolean on_list,
1057 PurpleAccountRequestAuthorizationCb auth_cb,
1058 PurpleAccountRequestAuthorizationCb deny_cb,
1059 void *user_data)
1060 {
1061 char *buffer;
1062 PurpleConnection *gc;
1063 void *uihandle;
1064
1065 gc = purple_account_get_connection(account);
1066 if (message != NULL && *message == '\0')
1067 message = NULL;
1068
1069 buffer = g_strdup_printf(_("%s%s%s%s wants to add %s to his or her buddy list%s%s"),
1070 remote_user,
1071 (alias != NULL ? " (" : ""),
1072 (alias != NULL ? alias : ""),
1073 (alias != NULL ? ")" : ""),
1074 (id != NULL
1075 ? id
1076 : (purple_connection_get_display_name(gc) != NULL
1077 ? purple_connection_get_display_name(gc)
1078 : purple_account_get_username(account))),
1079 (message != NULL ? ": " : "."),
1080 (message != NULL ? message : ""));
1081 if (!on_list) {
1082 GntWidget *widget;
1083 GList *iter;
1084 auth_and_add *aa = g_new(auth_and_add, 1);
1085
1086 aa->auth_cb = auth_cb;
1087 aa->deny_cb = deny_cb;
1088 aa->data = user_data;
1089 aa->username = g_strdup(remote_user);
1090 aa->alias = g_strdup(alias);
1091 aa->account = account;
1092
1093 uihandle = gnt_vwindow_new(FALSE);
1094 gnt_box_set_title(GNT_BOX(uihandle), _("Authorize buddy?"));
1095 gnt_box_set_pad(GNT_BOX(uihandle), 0);
1096
1097 widget = purple_request_action(NULL, _("Authorize buddy?"), buffer, NULL,
1098 PURPLE_DEFAULT_ACTION_NONE,
1099 account, remote_user, NULL,
1100 aa, 2,
1101 _("Authorize"), authorize_and_add_cb,
1102 _("Deny"), deny_no_add_cb);
1103 /* Since GntWindow is a GntBox, hide it so it's unmapped, then
1104 * add it to the outer window, and make it visible again. */
1105 gnt_widget_hide(widget);
1106 gnt_box_set_toplevel(GNT_BOX(widget), FALSE);
1107 gnt_box_add_widget(GNT_BOX(uihandle), widget);
1108 gnt_widget_set_visible(widget, TRUE);
1109
1110 gnt_box_add_widget(GNT_BOX(uihandle), gnt_hline_new());
1111
1112 widget = finch_retrieve_user_info(purple_account_get_connection(account), remote_user);
1113 for (iter = gnt_box_get_children(GNT_BOX(widget)); iter;
1114 iter = g_list_delete_link(iter, iter)) {
1115 if (GNT_IS_BUTTON(iter->data)) {
1116 gnt_widget_destroy(iter->data);
1117 gnt_box_remove(GNT_BOX(widget), iter->data);
1118 g_list_free(iter);
1119 break;
1120 }
1121 }
1122 /* Since GntWindow is a GntBox, hide it so it's unmapped, then
1123 * add it to the outer window, and make it visible again. */
1124 gnt_widget_hide(widget);
1125 gnt_box_set_toplevel(GNT_BOX(widget), FALSE);
1126 gnt_box_add_widget(GNT_BOX(uihandle), widget);
1127 gnt_widget_set_visible(widget, TRUE);
1128
1129 gnt_widget_show(uihandle);
1130
1131 g_signal_connect_swapped(G_OBJECT(uihandle), "destroy", G_CALLBACK(free_auth_and_add), aa);
1132 } else {
1133 uihandle = purple_request_action(NULL, _("Authorize buddy?"), buffer, NULL,
1134 PURPLE_DEFAULT_ACTION_NONE,
1135 account, remote_user, NULL,
1136 user_data, 2,
1137 _("Authorize"), auth_cb,
1138 _("Deny"), deny_cb);
1139 }
1140 g_signal_connect(G_OBJECT(uihandle), "destroy",
1141 G_CALLBACK(purple_account_request_close), NULL);
1142 g_free(buffer);
1143 return uihandle;
1144 }
1145
1146 static void
finch_request_close(void * uihandle)1147 finch_request_close(void *uihandle)
1148 {
1149 purple_request_close(PURPLE_REQUEST_ACTION, uihandle);
1150 }
1151
1152 static PurpleAccountUiOps ui_ops =
1153 {
1154 notify_added,
1155 NULL,
1156 request_add,
1157 finch_request_authorize,
1158 finch_request_close,
1159 NULL,
1160 NULL,
1161 NULL,
1162 NULL
1163 };
1164
finch_accounts_get_ui_ops()1165 PurpleAccountUiOps *finch_accounts_get_ui_ops()
1166 {
1167 return &ui_ops;
1168 }
1169
1170