Remove mime entry from docs.
[pidgin-git.git] / libpurple / accounts.c
blob207549296ba688bc191b70762a1efec8cb8a8cc5
1 /* purple
3 * Purple is the legal property of its developers, whose names are too numerous
4 * to list here. Please refer to the COPYRIGHT file distributed with this
5 * source distribution.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
21 #include "internal.h"
22 #include "accounts.h"
23 #include "core.h"
24 #include "debug.h"
25 #include "enums.h"
26 #include "network.h"
27 #include "pounce.h"
29 static PurpleAccountUiOps *account_ui_ops = NULL;
31 static GList *accounts = NULL;
32 static guint save_timer = 0;
33 static gboolean accounts_loaded = FALSE;
35 /*********************************************************************
36 * Writing to disk *
37 *********************************************************************/
38 static PurpleXmlNode *
39 accounts_to_xmlnode(void)
41 PurpleXmlNode *node, *child;
42 GList *cur;
44 node = purple_xmlnode_new("account");
45 purple_xmlnode_set_attrib(node, "version", "1.0");
47 for (cur = purple_accounts_get_all(); cur != NULL; cur = cur->next)
49 child = _purple_account_to_xmlnode(cur->data);
50 purple_xmlnode_insert_child(node, child);
53 return node;
56 static void
57 sync_accounts(void)
59 PurpleXmlNode *node;
60 char *data;
62 if (!accounts_loaded)
64 purple_debug_error("accounts", "Attempted to save accounts before "
65 "they were read!\n");
66 return;
69 node = accounts_to_xmlnode();
70 data = purple_xmlnode_to_formatted_str(node, NULL);
71 purple_util_write_data_to_config_file("accounts.xml", data, -1);
72 g_free(data);
73 purple_xmlnode_free(node);
76 static gboolean
77 save_cb(gpointer data)
79 sync_accounts();
80 save_timer = 0;
81 return FALSE;
84 void
85 purple_accounts_schedule_save(void)
87 if (save_timer == 0)
88 save_timer = g_timeout_add_seconds(5, save_cb, NULL);
91 static void
92 migrate_icq_server(PurpleAccount *account)
94 /* Migrate the login server setting for ICQ accounts. See
95 * 'mtn log --last 1 --no-graph --from b6d7712e90b68610df3bd2d8cbaf46d94c8b3794'
96 * for details on the change. */
98 if(purple_strequal(purple_account_get_protocol_id(account), "prpl-icq")) {
99 const char *tmp = purple_account_get_string(account, "server", NULL);
101 /* Non-secure server */
102 if(purple_strequal(tmp, "login.messaging.aol.com") ||
103 purple_strequal(tmp, "login.oscar.aol.com"))
104 purple_account_set_string(account, "server", "login.icq.com");
106 /* Secure server */
107 if(purple_strequal(tmp, "slogin.oscar.aol.com"))
108 purple_account_set_string(account, "server", "slogin.icq.com");
112 static void
113 migrate_xmpp_encryption(PurpleAccount *account)
115 /* When this is removed, nuke the "old_ssl" and "require_tls" settings */
116 if (g_str_equal(purple_account_get_protocol_id(account), "prpl-jabber")) {
117 const char *sec = purple_account_get_string(account, "connection_security", "");
119 if (g_str_equal("", sec)) {
120 const char *val = "require_tls";
121 if (purple_account_get_bool(account, "old_ssl", FALSE))
122 val = "old_ssl";
123 else if (!purple_account_get_bool(account, "require_tls", TRUE))
124 val = "opportunistic_tls";
126 purple_account_set_string(account, "connection_security", val);
131 static void
132 parse_settings(PurpleXmlNode *node, PurpleAccount *account)
134 const char *ui;
135 PurpleXmlNode *child;
137 /* Get the UI string, if these are UI settings */
138 ui = purple_xmlnode_get_attrib(node, "ui");
140 /* Read settings, one by one */
141 for (child = purple_xmlnode_get_child(node, "setting"); child != NULL;
142 child = purple_xmlnode_get_next_twin(child))
144 const char *name, *str_type;
145 PurplePrefType type;
146 char *data;
148 name = purple_xmlnode_get_attrib(child, "name");
149 if (name == NULL)
150 /* Ignore this setting */
151 continue;
153 str_type = purple_xmlnode_get_attrib(child, "type");
154 if (str_type == NULL)
155 /* Ignore this setting */
156 continue;
158 if (purple_strequal(str_type, "string"))
159 type = PURPLE_PREF_STRING;
160 else if (purple_strequal(str_type, "int"))
161 type = PURPLE_PREF_INT;
162 else if (purple_strequal(str_type, "bool"))
163 type = PURPLE_PREF_BOOLEAN;
164 else
165 /* Ignore this setting */
166 continue;
168 data = purple_xmlnode_get_data(child);
169 if (data == NULL)
170 /* Ignore this setting */
171 continue;
173 if (ui == NULL)
175 if (type == PURPLE_PREF_STRING)
176 purple_account_set_string(account, name, data);
177 else if (type == PURPLE_PREF_INT)
178 purple_account_set_int(account, name, atoi(data));
179 else if (type == PURPLE_PREF_BOOLEAN)
180 purple_account_set_bool(account, name,
181 (*data == '0' ? FALSE : TRUE));
182 } else {
183 if (type == PURPLE_PREF_STRING)
184 purple_account_set_ui_string(account, ui, name, data);
185 else if (type == PURPLE_PREF_INT)
186 purple_account_set_ui_int(account, ui, name, atoi(data));
187 else if (type == PURPLE_PREF_BOOLEAN)
188 purple_account_set_ui_bool(account, ui, name,
189 (*data == '0' ? FALSE : TRUE));
192 g_free(data);
195 /* we do this here because we need access to account settings to determine
196 * if we can/should migrate an ICQ account's server setting */
197 migrate_icq_server(account);
198 /* we do this here because we need to do it before the user views the
199 * Edit Account dialog. */
200 migrate_xmpp_encryption(account);
203 static GList *
204 parse_status_attrs(PurpleXmlNode *node, PurpleStatus *status)
206 GList *list = NULL;
207 PurpleXmlNode *child;
208 GValue *attr_value;
210 for (child = purple_xmlnode_get_child(node, "attribute"); child != NULL;
211 child = purple_xmlnode_get_next_twin(child))
213 const char *id = purple_xmlnode_get_attrib(child, "id");
214 const char *value = purple_xmlnode_get_attrib(child, "value");
216 if (!id || !*id || !value || !*value)
217 continue;
219 attr_value = purple_status_get_attr_value(status, id);
220 if (!attr_value)
221 continue;
223 list = g_list_append(list, (char *)id);
225 switch (G_VALUE_TYPE(attr_value))
227 case G_TYPE_STRING:
228 list = g_list_append(list, (char *)value);
229 break;
230 case G_TYPE_INT:
231 case G_TYPE_BOOLEAN:
233 int v;
234 if (sscanf(value, "%d", &v) == 1)
235 list = g_list_append(list, GINT_TO_POINTER(v));
236 else
237 list = g_list_remove(list, id);
238 break;
240 default:
241 break;
245 return list;
248 static void
249 parse_status(PurpleXmlNode *node, PurpleAccount *account)
251 gboolean active = FALSE;
252 const char *data;
253 const char *type;
254 PurpleXmlNode *child;
255 GList *attrs = NULL;
257 /* Get the active/inactive state */
258 data = purple_xmlnode_get_attrib(node, "active");
259 if (data == NULL)
260 return;
261 if (g_ascii_strcasecmp(data, "true") == 0)
262 active = TRUE;
263 else if (g_ascii_strcasecmp(data, "false") == 0)
264 active = FALSE;
265 else
266 return;
268 /* Get the type of the status */
269 type = purple_xmlnode_get_attrib(node, "type");
270 if (type == NULL)
271 return;
273 /* Read attributes into a GList */
274 child = purple_xmlnode_get_child(node, "attributes");
275 if (child != NULL)
277 attrs = parse_status_attrs(child,
278 purple_account_get_status(account, type));
281 purple_account_set_status_list(account, type, active, attrs);
283 g_list_free(attrs);
286 static void
287 parse_statuses(PurpleXmlNode *node, PurpleAccount *account)
289 PurpleXmlNode *child;
291 for (child = purple_xmlnode_get_child(node, "status"); child != NULL;
292 child = purple_xmlnode_get_next_twin(child))
294 parse_status(child, account);
298 static void
299 parse_proxy_info(PurpleXmlNode *node, PurpleAccount *account)
301 PurpleProxyInfo *proxy_info;
302 PurpleXmlNode *child;
303 char *data;
305 proxy_info = purple_proxy_info_new();
307 /* Use the global proxy settings, by default */
308 purple_proxy_info_set_proxy_type(proxy_info, PURPLE_PROXY_USE_GLOBAL);
310 /* Read proxy type */
311 child = purple_xmlnode_get_child(node, "type");
312 if ((child != NULL) && ((data = purple_xmlnode_get_data(child)) != NULL))
314 if (purple_strequal(data, "global"))
315 purple_proxy_info_set_proxy_type(proxy_info, PURPLE_PROXY_USE_GLOBAL);
316 else if (purple_strequal(data, "none"))
317 purple_proxy_info_set_proxy_type(proxy_info, PURPLE_PROXY_NONE);
318 else if (purple_strequal(data, "http"))
319 purple_proxy_info_set_proxy_type(proxy_info, PURPLE_PROXY_HTTP);
320 else if (purple_strequal(data, "socks4"))
321 purple_proxy_info_set_proxy_type(proxy_info, PURPLE_PROXY_SOCKS4);
322 else if (purple_strequal(data, "socks5"))
323 purple_proxy_info_set_proxy_type(proxy_info, PURPLE_PROXY_SOCKS5);
324 else if (purple_strequal(data, "tor"))
325 purple_proxy_info_set_proxy_type(proxy_info, PURPLE_PROXY_TOR);
326 else if (purple_strequal(data, "envvar"))
327 purple_proxy_info_set_proxy_type(proxy_info, PURPLE_PROXY_USE_ENVVAR);
328 else
330 purple_debug_error("accounts", "Invalid proxy type found when "
331 "loading account information for %s\n",
332 purple_account_get_username(account));
334 g_free(data);
337 /* Read proxy host */
338 child = purple_xmlnode_get_child(node, "host");
339 if ((child != NULL) && ((data = purple_xmlnode_get_data(child)) != NULL))
341 purple_proxy_info_set_host(proxy_info, data);
342 g_free(data);
345 /* Read proxy port */
346 child = purple_xmlnode_get_child(node, "port");
347 if ((child != NULL) && ((data = purple_xmlnode_get_data(child)) != NULL))
349 purple_proxy_info_set_port(proxy_info, atoi(data));
350 g_free(data);
353 /* Read proxy username */
354 child = purple_xmlnode_get_child(node, "username");
355 if ((child != NULL) && ((data = purple_xmlnode_get_data(child)) != NULL))
357 purple_proxy_info_set_username(proxy_info, data);
358 g_free(data);
361 /* Read proxy password */
362 child = purple_xmlnode_get_child(node, "password");
363 if ((child != NULL) && ((data = purple_xmlnode_get_data(child)) != NULL))
365 purple_proxy_info_set_password(proxy_info, data);
366 g_free(data);
369 /* If there are no values set then proxy_info NULL */
370 if ((purple_proxy_info_get_proxy_type(proxy_info) == PURPLE_PROXY_USE_GLOBAL) &&
371 (purple_proxy_info_get_host(proxy_info) == NULL) &&
372 (purple_proxy_info_get_port(proxy_info) == 0) &&
373 (purple_proxy_info_get_username(proxy_info) == NULL) &&
374 (purple_proxy_info_get_password(proxy_info) == NULL))
376 purple_proxy_info_destroy(proxy_info);
377 return;
380 purple_account_set_proxy_info(account, proxy_info);
383 static void
384 parse_current_error(PurpleXmlNode *node, PurpleAccount *account)
386 guint type;
387 char *type_str = NULL, *description = NULL;
388 PurpleXmlNode *child;
389 PurpleConnectionErrorInfo *current_error = NULL;
391 child = purple_xmlnode_get_child(node, "type");
392 if (child == NULL || (type_str = purple_xmlnode_get_data(child)) == NULL)
393 return;
394 type = atoi(type_str);
395 g_free(type_str);
397 if (type > PURPLE_CONNECTION_ERROR_OTHER_ERROR)
399 purple_debug_error("accounts",
400 "Invalid PurpleConnectionError value %d found when "
401 "loading account information for %s\n",
402 type, purple_account_get_username(account));
403 type = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
406 child = purple_xmlnode_get_child(node, "description");
407 if (child)
408 description = purple_xmlnode_get_data(child);
409 if (description == NULL)
410 description = g_strdup("");
412 current_error = g_new0(PurpleConnectionErrorInfo, 1);
413 current_error->type = type;
414 current_error->description = description;
416 _purple_account_set_current_error(account, current_error);
419 static PurpleAccount *
420 parse_account(PurpleXmlNode *node)
422 PurpleAccount *ret;
423 PurpleXmlNode *child;
424 char *protocol_id = NULL;
425 char *name = NULL;
426 char *data;
428 child = purple_xmlnode_get_child(node, "protocol");
429 if (child != NULL)
430 protocol_id = purple_xmlnode_get_data(child);
432 child = purple_xmlnode_get_child(node, "name");
433 if (child != NULL)
434 name = purple_xmlnode_get_data(child);
435 if (name == NULL)
437 /* Do we really need to do this? */
438 child = purple_xmlnode_get_child(node, "username");
439 if (child != NULL)
440 name = purple_xmlnode_get_data(child);
443 if ((protocol_id == NULL) || (name == NULL))
445 g_free(protocol_id);
446 g_free(name);
447 return NULL;
450 ret = purple_account_new(name, protocol_id);
451 g_free(name);
452 g_free(protocol_id);
454 /* Read the alias */
455 child = purple_xmlnode_get_child(node, "alias");
456 if ((child != NULL) && ((data = purple_xmlnode_get_data(child)) != NULL))
458 if (*data != '\0')
459 purple_account_set_private_alias(ret, data);
460 g_free(data);
463 /* Read the statuses */
464 child = purple_xmlnode_get_child(node, "statuses");
465 if (child != NULL)
467 parse_statuses(child, ret);
470 /* Read the userinfo */
471 child = purple_xmlnode_get_child(node, "userinfo");
472 if ((child != NULL) && ((data = purple_xmlnode_get_data(child)) != NULL))
474 purple_account_set_user_info(ret, data);
475 g_free(data);
478 /* Read an old buddyicon */
479 child = purple_xmlnode_get_child(node, "buddyicon");
480 if ((child != NULL) && ((data = purple_xmlnode_get_data(child)) != NULL))
482 const char *dirname = purple_buddy_icons_get_cache_dir();
483 char *filename = g_build_filename(dirname, data, NULL);
484 gchar *contents;
485 gsize len;
487 if (g_file_get_contents(filename, &contents, &len, NULL))
489 purple_buddy_icons_set_account_icon(ret, (guchar *)contents, len);
492 g_free(filename);
493 g_free(data);
496 /* Read settings (both core and UI) */
497 for (child = purple_xmlnode_get_child(node, "settings"); child != NULL;
498 child = purple_xmlnode_get_next_twin(child))
500 parse_settings(child, ret);
503 /* Read proxy */
504 child = purple_xmlnode_get_child(node, "proxy");
505 if (child != NULL)
507 parse_proxy_info(child, ret);
510 /* Read current error */
511 child = purple_xmlnode_get_child(node, "current_error");
512 if (child != NULL)
514 parse_current_error(child, ret);
517 /* Read the password */
518 child = purple_xmlnode_get_child(node, "password");
519 if (child != NULL)
521 const char *keyring_id = purple_xmlnode_get_attrib(child, "keyring_id");
522 const char *mode = purple_xmlnode_get_attrib(child, "mode");
523 gboolean result;
525 data = purple_xmlnode_get_data(child);
526 result = purple_keyring_import_password(ret, keyring_id, mode, data, NULL);
528 if (result == TRUE || purple_keyring_get_inuse() == NULL) {
529 purple_account_set_remember_password(ret, TRUE);
530 } else {
531 purple_debug_error("accounts", "Failed to import password.\n");
533 purple_str_wipe(data);
536 return ret;
539 static void
540 load_accounts(void)
542 PurpleXmlNode *node, *child;
544 accounts_loaded = TRUE;
546 node = purple_util_read_xml_from_config_file("accounts.xml", _("accounts"));
548 if (node == NULL)
549 return;
551 for (child = purple_xmlnode_get_child(node, "account"); child != NULL;
552 child = purple_xmlnode_get_next_twin(child))
554 PurpleAccount *new_acct;
555 new_acct = parse_account(child);
556 purple_accounts_add(new_acct);
559 purple_xmlnode_free(node);
561 _purple_buddy_icons_account_loaded_cb();
564 void
565 purple_accounts_add(PurpleAccount *account)
567 g_return_if_fail(account != NULL);
569 if (g_list_find(accounts, account) != NULL)
570 return;
572 accounts = g_list_append(accounts, account);
574 purple_accounts_schedule_save();
576 purple_signal_emit(purple_accounts_get_handle(), "account-added", account);
579 void
580 purple_accounts_remove(PurpleAccount *account)
582 g_return_if_fail(account != NULL);
584 accounts = g_list_remove(accounts, account);
586 purple_accounts_schedule_save();
588 /* Clearing the error ensures that account-error-changed is emitted,
589 * which is the end of the guarantee that the the error's pointer is
590 * valid.
592 purple_account_clear_current_error(account);
593 purple_signal_emit(purple_accounts_get_handle(), "account-removed", account);
596 static void
597 purple_accounts_delete_set(PurpleAccount *account, GError *error, gpointer data)
599 g_object_unref(G_OBJECT(account));
602 void
603 purple_accounts_delete(PurpleAccount *account)
605 PurpleBlistNode *gnode, *cnode, *bnode;
606 GList *iter;
608 g_return_if_fail(account != NULL);
611 * Disable the account before blowing it out of the water.
612 * Conceptually it probably makes more sense to disable the
613 * account for all UIs rather than the just the current UI,
614 * but it doesn't really matter.
616 purple_account_set_enabled(account, purple_core_get_ui(), FALSE);
618 purple_notify_close_with_handle(account);
619 purple_request_close_with_handle(account);
621 purple_accounts_remove(account);
623 /* Remove this account's buddies */
624 for (gnode = purple_blist_get_root();
625 gnode != NULL;
626 gnode = purple_blist_node_get_sibling_next(gnode))
628 if (!PURPLE_IS_GROUP(gnode))
629 continue;
631 cnode = purple_blist_node_get_first_child(gnode);
632 while (cnode) {
633 PurpleBlistNode *cnode_next = purple_blist_node_get_sibling_next(cnode);
635 if(PURPLE_IS_CONTACT(cnode)) {
636 bnode = purple_blist_node_get_first_child(cnode);
637 while (bnode) {
638 PurpleBlistNode *bnode_next = purple_blist_node_get_sibling_next(bnode);
640 if (PURPLE_IS_BUDDY(bnode)) {
641 PurpleBuddy *b = (PurpleBuddy *)bnode;
643 if (purple_buddy_get_account(b) == account)
644 purple_blist_remove_buddy(b);
646 bnode = bnode_next;
648 } else if (PURPLE_IS_CHAT(cnode)) {
649 PurpleChat *c = (PurpleChat *)cnode;
651 if (purple_chat_get_account(c) == account)
652 purple_blist_remove_chat(c);
654 cnode = cnode_next;
658 /* Remove any open conversation for this account */
659 for (iter = purple_conversations_get_all(); iter; ) {
660 PurpleConversation *conv = iter->data;
661 iter = iter->next;
662 if (purple_conversation_get_account(conv) == account)
663 g_object_unref(conv);
666 /* Remove this account's pounces */
667 purple_pounce_destroy_all_by_account(account);
669 /* This will cause the deletion of an old buddy icon. */
670 purple_buddy_icons_set_account_icon(account, NULL, 0);
672 /* This is async because we do not want the
673 * account being overwritten before we are done.
675 purple_keyring_set_password(account, NULL,
676 purple_accounts_delete_set, NULL);
679 void
680 purple_accounts_reorder(PurpleAccount *account, guint new_index)
682 gint index;
683 GList *l;
685 g_return_if_fail(account != NULL);
686 g_return_if_fail(new_index <= g_list_length(accounts));
688 index = g_list_index(accounts, account);
690 if (index < 0) {
691 purple_debug_error("accounts",
692 "Unregistered account (%s) discovered during reorder!\n",
693 purple_account_get_username(account));
694 return;
697 l = g_list_nth(accounts, index);
699 if (new_index > (guint)index)
700 new_index--;
702 /* Remove the old one. */
703 accounts = g_list_delete_link(accounts, l);
705 /* Insert it where it should go. */
706 accounts = g_list_insert(accounts, account, new_index);
708 purple_accounts_schedule_save();
711 GList *
712 purple_accounts_get_all(void)
714 return accounts;
717 GList *
718 purple_accounts_get_all_active(void)
720 GList *list = NULL;
721 GList *all = purple_accounts_get_all();
723 while (all != NULL) {
724 PurpleAccount *account = all->data;
726 if (purple_account_get_enabled(account, purple_core_get_ui()))
727 list = g_list_append(list, account);
729 all = all->next;
732 return list;
735 PurpleAccount *
736 purple_accounts_find(const char *name, const char *protocol_id)
738 PurpleAccount *account = NULL;
739 GList *l;
740 char *who;
742 g_return_val_if_fail(name != NULL, NULL);
743 g_return_val_if_fail(protocol_id != NULL, NULL);
745 for (l = purple_accounts_get_all(); l != NULL; l = l->next) {
746 account = (PurpleAccount *)l->data;
748 if (!purple_strequal(purple_account_get_protocol_id(account), protocol_id))
749 continue;
751 who = g_strdup(purple_normalize(account, name));
752 if (purple_strequal(purple_normalize(account, purple_account_get_username(account)), who)) {
753 g_free(who);
754 return account;
756 g_free(who);
759 return NULL;
762 void
763 purple_accounts_restore_current_statuses()
765 GList *l;
766 PurpleAccount *account;
768 /* If we're not connected to the Internet right now, we bail on this */
769 if (!purple_network_is_available())
771 purple_debug_warning("accounts", "Network not connected; skipping reconnect\n");
772 return;
775 for (l = purple_accounts_get_all(); l != NULL; l = l->next)
777 account = (PurpleAccount *)l->data;
779 if (purple_account_get_enabled(account, purple_core_get_ui()) &&
780 (purple_presence_is_online(purple_account_get_presence(account))))
782 purple_account_connect(account);
787 static PurpleAccountUiOps *
788 purple_account_ui_ops_copy(PurpleAccountUiOps *ops)
790 PurpleAccountUiOps *ops_new;
792 g_return_val_if_fail(ops != NULL, NULL);
794 ops_new = g_new(PurpleAccountUiOps, 1);
795 *ops_new = *ops;
797 return ops_new;
800 GType
801 purple_account_ui_ops_get_type(void)
803 static GType type = 0;
805 if (type == 0) {
806 type = g_boxed_type_register_static("PurpleAccountUiOps",
807 (GBoxedCopyFunc)purple_account_ui_ops_copy,
808 (GBoxedFreeFunc)g_free);
811 return type;
814 void
815 purple_accounts_set_ui_ops(PurpleAccountUiOps *ops)
817 account_ui_ops = ops;
820 PurpleAccountUiOps *
821 purple_accounts_get_ui_ops(void)
823 return account_ui_ops;
826 void *
827 purple_accounts_get_handle(void)
829 static int handle;
831 return &handle;
834 static void
835 signed_on_cb(PurpleConnection *gc,
836 gpointer unused)
838 PurpleAccount *account = purple_connection_get_account(gc);
839 purple_account_clear_current_error(account);
841 purple_signal_emit(purple_accounts_get_handle(), "account-signed-on",
842 account);
845 static void
846 signed_off_cb(PurpleConnection *gc,
847 gpointer unused)
849 PurpleAccount *account = purple_connection_get_account(gc);
851 purple_signal_emit(purple_accounts_get_handle(), "account-signed-off",
852 account);
855 static void
856 connection_error_cb(PurpleConnection *gc,
857 PurpleConnectionError type,
858 const gchar *description,
859 gpointer unused)
861 PurpleAccount *account;
862 PurpleConnectionErrorInfo *err;
864 account = purple_connection_get_account(gc);
866 g_return_if_fail(account != NULL);
868 err = g_new0(PurpleConnectionErrorInfo, 1);
870 err->type = type;
871 err->description = g_strdup(description);
873 _purple_account_set_current_error(account, err);
875 purple_signal_emit(purple_accounts_get_handle(), "account-connection-error",
876 account, type, description);
879 static void
880 password_migration_cb(PurpleAccount *account)
882 /* account may be NULL (means: all) */
884 purple_accounts_schedule_save();
887 void
888 purple_accounts_init(void)
890 void *handle = purple_accounts_get_handle();
891 void *conn_handle = purple_connections_get_handle();
893 purple_signal_register(handle, "account-connecting",
894 purple_marshal_VOID__POINTER, G_TYPE_NONE, 1,
895 PURPLE_TYPE_ACCOUNT);
897 purple_signal_register(handle, "account-disabled",
898 purple_marshal_VOID__POINTER, G_TYPE_NONE, 1,
899 PURPLE_TYPE_ACCOUNT);
901 purple_signal_register(handle, "account-enabled",
902 purple_marshal_VOID__POINTER, G_TYPE_NONE, 1,
903 PURPLE_TYPE_ACCOUNT);
905 purple_signal_register(handle, "account-setting-info",
906 purple_marshal_VOID__POINTER_POINTER, G_TYPE_NONE, 2,
907 PURPLE_TYPE_ACCOUNT, G_TYPE_STRING);
909 purple_signal_register(handle, "account-set-info",
910 purple_marshal_VOID__POINTER_POINTER, G_TYPE_NONE, 2,
911 PURPLE_TYPE_ACCOUNT, G_TYPE_STRING);
913 purple_signal_register(handle, "account-created",
914 purple_marshal_VOID__POINTER, G_TYPE_NONE, 1,
915 PURPLE_TYPE_ACCOUNT);
917 purple_signal_register(handle, "account-destroying",
918 purple_marshal_VOID__POINTER, G_TYPE_NONE, 1,
919 PURPLE_TYPE_ACCOUNT);
921 purple_signal_register(handle, "account-added",
922 purple_marshal_VOID__POINTER, G_TYPE_NONE, 1,
923 PURPLE_TYPE_ACCOUNT);
925 purple_signal_register(handle, "account-removed",
926 purple_marshal_VOID__POINTER, G_TYPE_NONE, 1,
927 PURPLE_TYPE_ACCOUNT);
929 purple_signal_register(handle, "account-status-changing",
930 purple_marshal_VOID__POINTER_POINTER_POINTER,
931 G_TYPE_NONE, 3, PURPLE_TYPE_ACCOUNT,
932 PURPLE_TYPE_STATUS, PURPLE_TYPE_STATUS);
934 purple_signal_register(handle, "account-status-changed",
935 purple_marshal_VOID__POINTER_POINTER_POINTER,
936 G_TYPE_NONE, 3, PURPLE_TYPE_ACCOUNT,
937 PURPLE_TYPE_STATUS, PURPLE_TYPE_STATUS);
939 purple_signal_register(handle, "account-actions-changed",
940 purple_marshal_VOID__POINTER, G_TYPE_NONE, 1,
941 PURPLE_TYPE_ACCOUNT);
943 purple_signal_register(handle, "account-alias-changed",
944 purple_marshal_VOID__POINTER_POINTER, G_TYPE_NONE, 2,
945 PURPLE_TYPE_ACCOUNT, G_TYPE_STRING);
947 purple_signal_register(handle, "account-authorization-requested",
948 purple_marshal_INT__POINTER_POINTER_POINTER,
949 G_TYPE_INT, 4, PURPLE_TYPE_ACCOUNT, G_TYPE_STRING,
950 G_TYPE_STRING, G_TYPE_STRING);
952 purple_signal_register(handle, "account-authorization-denied",
953 purple_marshal_VOID__POINTER_POINTER, G_TYPE_NONE, 3,
954 PURPLE_TYPE_ACCOUNT, G_TYPE_STRING, G_TYPE_STRING);
956 purple_signal_register(handle, "account-authorization-granted",
957 purple_marshal_VOID__POINTER_POINTER, G_TYPE_NONE, 3,
958 PURPLE_TYPE_ACCOUNT, G_TYPE_STRING, G_TYPE_STRING);
960 purple_signal_register(handle, "account-error-changed",
961 purple_marshal_VOID__POINTER_POINTER_POINTER,
962 G_TYPE_NONE, 3, PURPLE_TYPE_ACCOUNT,
963 PURPLE_TYPE_CONNECTION_ERROR_INFO,
964 PURPLE_TYPE_CONNECTION_ERROR_INFO);
966 purple_signal_register(handle, "account-signed-on",
967 purple_marshal_VOID__POINTER, G_TYPE_NONE, 1,
968 PURPLE_TYPE_ACCOUNT);
970 purple_signal_register(handle, "account-signed-off",
971 purple_marshal_VOID__POINTER, G_TYPE_NONE, 1,
972 PURPLE_TYPE_ACCOUNT);
974 purple_signal_register(handle, "account-connection-error",
975 purple_marshal_VOID__POINTER_INT_POINTER,
976 G_TYPE_NONE, 3, PURPLE_TYPE_ACCOUNT,
977 PURPLE_TYPE_CONNECTION_ERROR, G_TYPE_STRING);
979 purple_signal_connect(conn_handle, "signed-on", handle,
980 PURPLE_CALLBACK(signed_on_cb), NULL);
981 purple_signal_connect(conn_handle, "signed-off", handle,
982 PURPLE_CALLBACK(signed_off_cb), NULL);
983 purple_signal_connect(conn_handle, "connection-error", handle,
984 PURPLE_CALLBACK(connection_error_cb), NULL);
985 purple_signal_connect(purple_keyring_get_handle(), "password-migration", handle,
986 PURPLE_CALLBACK(password_migration_cb), NULL);
988 load_accounts();
992 void
993 purple_accounts_uninit(void)
995 gpointer handle = purple_accounts_get_handle();
996 if (save_timer != 0)
998 g_source_remove(save_timer);
999 save_timer = 0;
1000 sync_accounts();
1003 for (; accounts; accounts = g_list_delete_link(accounts, accounts))
1004 g_object_unref(G_OBJECT(accounts->data));
1006 purple_signals_disconnect_by_handle(handle);
1007 purple_signals_unregister_by_instance(handle);