Updated Bengali translation, a month and a half after it was submitted. Fixes #12141.
[pidgin-git.git] / libpurple / account.c
blobd69326f2de3fb856c02301a7ea5c6a614b7087cc
1 /**
2 * @file account.c Account API
3 * @ingroup core
4 */
6 /* purple
8 * Purple 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
26 #include "internal.h"
27 #include "account.h"
28 #include "core.h"
29 #include "dbus-maybe.h"
30 #include "debug.h"
31 #include "network.h"
32 #include "notify.h"
33 #include "pounce.h"
34 #include "prefs.h"
35 #include "privacy.h"
36 #include "prpl.h"
37 #include "request.h"
38 #include "server.h"
39 #include "signals.h"
40 #include "status.h"
41 #include "util.h"
42 #include "xmlnode.h"
44 typedef struct
46 PurpleConnectionErrorInfo *current_error;
47 } PurpleAccountPrivate;
49 #define PURPLE_ACCOUNT_GET_PRIVATE(account) \
50 ((PurpleAccountPrivate *) (account->priv))
52 /* TODO: Should use PurpleValue instead of this? What about "ui"? */
53 typedef struct
55 PurplePrefType type;
57 char *ui;
59 union
61 int integer;
62 char *string;
63 gboolean boolean;
65 } value;
67 } PurpleAccountSetting;
69 typedef struct
71 PurpleAccountRequestType type;
72 PurpleAccount *account;
73 void *ui_handle;
74 char *user;
75 gpointer userdata;
76 PurpleAccountRequestAuthorizationCb auth_cb;
77 PurpleAccountRequestAuthorizationCb deny_cb;
78 guint ref;
79 } PurpleAccountRequestInfo;
81 static PurpleAccountUiOps *account_ui_ops = NULL;
83 static GList *accounts = NULL;
84 static guint save_timer = 0;
85 static gboolean accounts_loaded = FALSE;
87 static GList *handles = NULL;
89 static void set_current_error(PurpleAccount *account,
90 PurpleConnectionErrorInfo *new_err);
92 /*********************************************************************
93 * Writing to disk *
94 *********************************************************************/
96 static void
97 setting_to_xmlnode(gpointer key, gpointer value, gpointer user_data)
99 const char *name;
100 PurpleAccountSetting *setting;
101 xmlnode *node, *child;
102 char buf[21];
104 name = (const char *)key;
105 setting = (PurpleAccountSetting *)value;
106 node = (xmlnode *)user_data;
108 child = xmlnode_new_child(node, "setting");
109 xmlnode_set_attrib(child, "name", name);
111 if (setting->type == PURPLE_PREF_INT) {
112 xmlnode_set_attrib(child, "type", "int");
113 g_snprintf(buf, sizeof(buf), "%d", setting->value.integer);
114 xmlnode_insert_data(child, buf, -1);
116 else if (setting->type == PURPLE_PREF_STRING && setting->value.string != NULL) {
117 xmlnode_set_attrib(child, "type", "string");
118 xmlnode_insert_data(child, setting->value.string, -1);
120 else if (setting->type == PURPLE_PREF_BOOLEAN) {
121 xmlnode_set_attrib(child, "type", "bool");
122 g_snprintf(buf, sizeof(buf), "%d", setting->value.boolean);
123 xmlnode_insert_data(child, buf, -1);
127 static void
128 ui_setting_to_xmlnode(gpointer key, gpointer value, gpointer user_data)
130 const char *ui;
131 GHashTable *table;
132 xmlnode *node, *child;
134 ui = (const char *)key;
135 table = (GHashTable *)value;
136 node = (xmlnode *)user_data;
138 if (g_hash_table_size(table) > 0)
140 child = xmlnode_new_child(node, "settings");
141 xmlnode_set_attrib(child, "ui", ui);
142 g_hash_table_foreach(table, setting_to_xmlnode, child);
146 static xmlnode *
147 status_attr_to_xmlnode(const PurpleStatus *status, const PurpleStatusType *type, const PurpleStatusAttr *attr)
149 xmlnode *node;
150 const char *id;
151 char *value = NULL;
152 PurpleStatusAttr *default_attr;
153 PurpleValue *default_value;
154 PurpleType attr_type;
155 PurpleValue *attr_value;
157 id = purple_status_attr_get_id(attr);
158 g_return_val_if_fail(id, NULL);
160 attr_value = purple_status_get_attr_value(status, id);
161 g_return_val_if_fail(attr_value, NULL);
162 attr_type = purple_value_get_type(attr_value);
165 * If attr_value is a different type than it should be
166 * then don't write it to the file.
168 default_attr = purple_status_type_get_attr(type, id);
169 default_value = purple_status_attr_get_value(default_attr);
170 if (attr_type != purple_value_get_type(default_value))
171 return NULL;
174 * If attr_value is the same as the default for this status
175 * then there is no need to write it to the file.
177 if (attr_type == PURPLE_TYPE_STRING)
179 const char *string_value = purple_value_get_string(attr_value);
180 const char *default_string_value = purple_value_get_string(default_value);
181 if (purple_strequal(string_value, default_string_value))
182 return NULL;
183 value = g_strdup(purple_value_get_string(attr_value));
185 else if (attr_type == PURPLE_TYPE_INT)
187 int int_value = purple_value_get_int(attr_value);
188 if (int_value == purple_value_get_int(default_value))
189 return NULL;
190 value = g_strdup_printf("%d", int_value);
192 else if (attr_type == PURPLE_TYPE_BOOLEAN)
194 gboolean boolean_value = purple_value_get_boolean(attr_value);
195 if (boolean_value == purple_value_get_boolean(default_value))
196 return NULL;
197 value = g_strdup(boolean_value ?
198 "true" : "false");
200 else
202 return NULL;
205 g_return_val_if_fail(value, NULL);
207 node = xmlnode_new("attribute");
209 xmlnode_set_attrib(node, "id", id);
210 xmlnode_set_attrib(node, "value", value);
212 g_free(value);
214 return node;
217 static xmlnode *
218 status_attrs_to_xmlnode(const PurpleStatus *status)
220 PurpleStatusType *type = purple_status_get_type(status);
221 xmlnode *node, *child;
222 GList *attrs, *attr;
224 node = xmlnode_new("attributes");
226 attrs = purple_status_type_get_attrs(type);
227 for (attr = attrs; attr != NULL; attr = attr->next)
229 child = status_attr_to_xmlnode(status, type, (const PurpleStatusAttr *)attr->data);
230 if (child)
231 xmlnode_insert_child(node, child);
234 return node;
237 static xmlnode *
238 status_to_xmlnode(const PurpleStatus *status)
240 xmlnode *node, *child;
242 node = xmlnode_new("status");
243 xmlnode_set_attrib(node, "type", purple_status_get_id(status));
244 if (purple_status_get_name(status) != NULL)
245 xmlnode_set_attrib(node, "name", purple_status_get_name(status));
246 xmlnode_set_attrib(node, "active", purple_status_is_active(status) ? "true" : "false");
248 child = status_attrs_to_xmlnode(status);
249 xmlnode_insert_child(node, child);
251 return node;
254 static xmlnode *
255 statuses_to_xmlnode(const PurplePresence *presence)
257 xmlnode *node, *child;
258 GList *statuses;
259 PurpleStatus *status;
261 node = xmlnode_new("statuses");
263 statuses = purple_presence_get_statuses(presence);
264 for (; statuses != NULL; statuses = statuses->next)
266 status = statuses->data;
267 if (purple_status_type_is_saveable(purple_status_get_type(status)))
269 child = status_to_xmlnode(status);
270 xmlnode_insert_child(node, child);
274 return node;
277 static xmlnode *
278 proxy_settings_to_xmlnode(PurpleProxyInfo *proxy_info)
280 xmlnode *node, *child;
281 PurpleProxyType proxy_type;
282 const char *value;
283 int int_value;
284 char buf[21];
286 proxy_type = purple_proxy_info_get_type(proxy_info);
288 node = xmlnode_new("proxy");
290 child = xmlnode_new_child(node, "type");
291 xmlnode_insert_data(child,
292 (proxy_type == PURPLE_PROXY_USE_GLOBAL ? "global" :
293 proxy_type == PURPLE_PROXY_NONE ? "none" :
294 proxy_type == PURPLE_PROXY_HTTP ? "http" :
295 proxy_type == PURPLE_PROXY_SOCKS4 ? "socks4" :
296 proxy_type == PURPLE_PROXY_SOCKS5 ? "socks5" :
297 proxy_type == PURPLE_PROXY_USE_ENVVAR ? "envvar" : "unknown"), -1);
299 if ((value = purple_proxy_info_get_host(proxy_info)) != NULL)
301 child = xmlnode_new_child(node, "host");
302 xmlnode_insert_data(child, value, -1);
305 if ((int_value = purple_proxy_info_get_port(proxy_info)) != 0)
307 g_snprintf(buf, sizeof(buf), "%d", int_value);
308 child = xmlnode_new_child(node, "port");
309 xmlnode_insert_data(child, buf, -1);
312 if ((value = purple_proxy_info_get_username(proxy_info)) != NULL)
314 child = xmlnode_new_child(node, "username");
315 xmlnode_insert_data(child, value, -1);
318 if ((value = purple_proxy_info_get_password(proxy_info)) != NULL)
320 child = xmlnode_new_child(node, "password");
321 xmlnode_insert_data(child, value, -1);
324 return node;
327 static xmlnode *
328 current_error_to_xmlnode(PurpleConnectionErrorInfo *err)
330 xmlnode *node, *child;
331 char type_str[3];
333 node = xmlnode_new("current_error");
335 if(err == NULL)
336 return node;
338 /* It doesn't make sense to have transient errors persist across a
339 * restart.
341 if(!purple_connection_error_is_fatal (err->type))
342 return node;
344 child = xmlnode_new_child(node, "type");
345 g_snprintf(type_str, sizeof(type_str), "%u", err->type);
346 xmlnode_insert_data(child, type_str, -1);
348 child = xmlnode_new_child(node, "description");
349 if(err->description) {
350 char *utf8ized = purple_utf8_try_convert(err->description);
351 if(utf8ized == NULL)
352 utf8ized = purple_utf8_salvage(err->description);
353 xmlnode_insert_data(child, utf8ized, -1);
354 g_free(utf8ized);
357 return node;
360 static xmlnode *
361 account_to_xmlnode(PurpleAccount *account)
363 PurpleAccountPrivate *priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
365 xmlnode *node, *child;
366 const char *tmp;
367 PurplePresence *presence;
368 PurpleProxyInfo *proxy_info;
370 node = xmlnode_new("account");
372 child = xmlnode_new_child(node, "protocol");
373 xmlnode_insert_data(child, purple_account_get_protocol_id(account), -1);
375 child = xmlnode_new_child(node, "name");
376 xmlnode_insert_data(child, purple_account_get_username(account), -1);
378 if (purple_account_get_remember_password(account) &&
379 ((tmp = purple_account_get_password(account)) != NULL))
381 child = xmlnode_new_child(node, "password");
382 xmlnode_insert_data(child, tmp, -1);
385 if ((tmp = purple_account_get_alias(account)) != NULL)
387 child = xmlnode_new_child(node, "alias");
388 xmlnode_insert_data(child, tmp, -1);
391 if ((presence = purple_account_get_presence(account)) != NULL)
393 child = statuses_to_xmlnode(presence);
394 xmlnode_insert_child(node, child);
397 if ((tmp = purple_account_get_user_info(account)) != NULL)
399 /* TODO: Do we need to call purple_str_strip_char(tmp, '\r') here? */
400 child = xmlnode_new_child(node, "userinfo");
401 xmlnode_insert_data(child, tmp, -1);
404 if (g_hash_table_size(account->settings) > 0)
406 child = xmlnode_new_child(node, "settings");
407 g_hash_table_foreach(account->settings, setting_to_xmlnode, child);
410 if (g_hash_table_size(account->ui_settings) > 0)
412 g_hash_table_foreach(account->ui_settings, ui_setting_to_xmlnode, node);
415 if ((proxy_info = purple_account_get_proxy_info(account)) != NULL)
417 child = proxy_settings_to_xmlnode(proxy_info);
418 xmlnode_insert_child(node, child);
421 child = current_error_to_xmlnode(priv->current_error);
422 xmlnode_insert_child(node, child);
424 return node;
427 static xmlnode *
428 accounts_to_xmlnode(void)
430 xmlnode *node, *child;
431 GList *cur;
433 node = xmlnode_new("account");
434 xmlnode_set_attrib(node, "version", "1.0");
436 for (cur = purple_accounts_get_all(); cur != NULL; cur = cur->next)
438 child = account_to_xmlnode(cur->data);
439 xmlnode_insert_child(node, child);
442 return node;
445 static void
446 sync_accounts(void)
448 xmlnode *node;
449 char *data;
451 if (!accounts_loaded)
453 purple_debug_error("account", "Attempted to save accounts before "
454 "they were read!\n");
455 return;
458 node = accounts_to_xmlnode();
459 data = xmlnode_to_formatted_str(node, NULL);
460 purple_util_write_data_to_file("accounts.xml", data, -1);
461 g_free(data);
462 xmlnode_free(node);
465 static gboolean
466 save_cb(gpointer data)
468 sync_accounts();
469 save_timer = 0;
470 return FALSE;
473 static void
474 schedule_accounts_save(void)
476 if (save_timer == 0)
477 save_timer = purple_timeout_add_seconds(5, save_cb, NULL);
481 /*********************************************************************
482 * Reading from disk *
483 *********************************************************************/
484 static void
485 migrate_yahoo_japan(PurpleAccount *account)
487 /* detect a Yahoo! JAPAN account that existed prior to 2.6.0 and convert it
488 * to use the new prpl-yahoojp. Also remove the account-specific settings
489 * we no longer need */
491 if(purple_strequal(purple_account_get_protocol_id(account), "prpl-yahoo")) {
492 if(purple_account_get_bool(account, "yahoojp", FALSE)) {
493 const char *serverjp = purple_account_get_string(account, "serverjp", NULL);
494 const char *xferjp_host = purple_account_get_string(account, "xferjp_host", NULL);
496 g_return_if_fail(serverjp != NULL);
497 g_return_if_fail(xferjp_host != NULL);
499 purple_account_set_string(account, "server", serverjp);
500 purple_account_set_string(account, "xfer_host", xferjp_host);
502 purple_account_set_protocol_id(account, "prpl-yahoojp");
505 /* these should always be nuked */
506 purple_account_remove_setting(account, "yahoojp");
507 purple_account_remove_setting(account, "serverjp");
508 purple_account_remove_setting(account, "xferjp_host");
512 return;
515 static void
516 parse_settings(xmlnode *node, PurpleAccount *account)
518 const char *ui;
519 xmlnode *child;
521 /* Get the UI string, if these are UI settings */
522 ui = xmlnode_get_attrib(node, "ui");
524 /* Read settings, one by one */
525 for (child = xmlnode_get_child(node, "setting"); child != NULL;
526 child = xmlnode_get_next_twin(child))
528 const char *name, *str_type;
529 PurplePrefType type;
530 char *data;
532 name = xmlnode_get_attrib(child, "name");
533 if (name == NULL)
534 /* Ignore this setting */
535 continue;
537 str_type = xmlnode_get_attrib(child, "type");
538 if (str_type == NULL)
539 /* Ignore this setting */
540 continue;
542 if (purple_strequal(str_type, "string"))
543 type = PURPLE_PREF_STRING;
544 else if (purple_strequal(str_type, "int"))
545 type = PURPLE_PREF_INT;
546 else if (purple_strequal(str_type, "bool"))
547 type = PURPLE_PREF_BOOLEAN;
548 else
549 /* Ignore this setting */
550 continue;
552 data = xmlnode_get_data(child);
553 if (data == NULL)
554 /* Ignore this setting */
555 continue;
557 if (ui == NULL)
559 if (type == PURPLE_PREF_STRING)
560 purple_account_set_string(account, name, data);
561 else if (type == PURPLE_PREF_INT)
562 purple_account_set_int(account, name, atoi(data));
563 else if (type == PURPLE_PREF_BOOLEAN)
564 purple_account_set_bool(account, name,
565 (*data == '0' ? FALSE : TRUE));
566 } else {
567 if (type == PURPLE_PREF_STRING)
568 purple_account_set_ui_string(account, ui, name, data);
569 else if (type == PURPLE_PREF_INT)
570 purple_account_set_ui_int(account, ui, name, atoi(data));
571 else if (type == PURPLE_PREF_BOOLEAN)
572 purple_account_set_ui_bool(account, ui, name,
573 (*data == '0' ? FALSE : TRUE));
576 g_free(data);
579 /* we do this here because we need access to account settings to determine
580 * if we can/should migrate an old Yahoo! JAPAN account */
581 migrate_yahoo_japan(account);
584 static GList *
585 parse_status_attrs(xmlnode *node, PurpleStatus *status)
587 GList *list = NULL;
588 xmlnode *child;
589 PurpleValue *attr_value;
591 for (child = xmlnode_get_child(node, "attribute"); child != NULL;
592 child = xmlnode_get_next_twin(child))
594 const char *id = xmlnode_get_attrib(child, "id");
595 const char *value = xmlnode_get_attrib(child, "value");
597 if (!id || !*id || !value || !*value)
598 continue;
600 attr_value = purple_status_get_attr_value(status, id);
601 if (!attr_value)
602 continue;
604 list = g_list_append(list, (char *)id);
606 switch (purple_value_get_type(attr_value))
608 case PURPLE_TYPE_STRING:
609 list = g_list_append(list, (char *)value);
610 break;
611 case PURPLE_TYPE_INT:
612 case PURPLE_TYPE_BOOLEAN:
614 int v;
615 if (sscanf(value, "%d", &v) == 1)
616 list = g_list_append(list, GINT_TO_POINTER(v));
617 else
618 list = g_list_remove(list, id);
619 break;
621 default:
622 break;
626 return list;
629 static void
630 parse_status(xmlnode *node, PurpleAccount *account)
632 gboolean active = FALSE;
633 const char *data;
634 const char *type;
635 xmlnode *child;
636 GList *attrs = NULL;
638 /* Get the active/inactive state */
639 data = xmlnode_get_attrib(node, "active");
640 if (data == NULL)
641 return;
642 if (g_ascii_strcasecmp(data, "true") == 0)
643 active = TRUE;
644 else if (g_ascii_strcasecmp(data, "false") == 0)
645 active = FALSE;
646 else
647 return;
649 /* Get the type of the status */
650 type = xmlnode_get_attrib(node, "type");
651 if (type == NULL)
652 return;
654 /* Read attributes into a GList */
655 child = xmlnode_get_child(node, "attributes");
656 if (child != NULL)
658 attrs = parse_status_attrs(child,
659 purple_account_get_status(account, type));
662 purple_account_set_status_list(account, type, active, attrs);
664 g_list_free(attrs);
667 static void
668 parse_statuses(xmlnode *node, PurpleAccount *account)
670 xmlnode *child;
672 for (child = xmlnode_get_child(node, "status"); child != NULL;
673 child = xmlnode_get_next_twin(child))
675 parse_status(child, account);
679 static void
680 parse_proxy_info(xmlnode *node, PurpleAccount *account)
682 PurpleProxyInfo *proxy_info;
683 xmlnode *child;
684 char *data;
686 proxy_info = purple_proxy_info_new();
688 /* Use the global proxy settings, by default */
689 purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_USE_GLOBAL);
691 /* Read proxy type */
692 child = xmlnode_get_child(node, "type");
693 if ((child != NULL) && ((data = xmlnode_get_data(child)) != NULL))
695 if (purple_strequal(data, "global"))
696 purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_USE_GLOBAL);
697 else if (purple_strequal(data, "none"))
698 purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_NONE);
699 else if (purple_strequal(data, "http"))
700 purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_HTTP);
701 else if (purple_strequal(data, "socks4"))
702 purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_SOCKS4);
703 else if (purple_strequal(data, "socks5"))
704 purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_SOCKS5);
705 else if (purple_strequal(data, "envvar"))
706 purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_USE_ENVVAR);
707 else
709 purple_debug_error("account", "Invalid proxy type found when "
710 "loading account information for %s\n",
711 purple_account_get_username(account));
713 g_free(data);
716 /* Read proxy host */
717 child = xmlnode_get_child(node, "host");
718 if ((child != NULL) && ((data = xmlnode_get_data(child)) != NULL))
720 purple_proxy_info_set_host(proxy_info, data);
721 g_free(data);
724 /* Read proxy port */
725 child = xmlnode_get_child(node, "port");
726 if ((child != NULL) && ((data = xmlnode_get_data(child)) != NULL))
728 purple_proxy_info_set_port(proxy_info, atoi(data));
729 g_free(data);
732 /* Read proxy username */
733 child = xmlnode_get_child(node, "username");
734 if ((child != NULL) && ((data = xmlnode_get_data(child)) != NULL))
736 purple_proxy_info_set_username(proxy_info, data);
737 g_free(data);
740 /* Read proxy password */
741 child = xmlnode_get_child(node, "password");
742 if ((child != NULL) && ((data = xmlnode_get_data(child)) != NULL))
744 purple_proxy_info_set_password(proxy_info, data);
745 g_free(data);
748 /* If there are no values set then proxy_info NULL */
749 if ((purple_proxy_info_get_type(proxy_info) == PURPLE_PROXY_USE_GLOBAL) &&
750 (purple_proxy_info_get_host(proxy_info) == NULL) &&
751 (purple_proxy_info_get_port(proxy_info) == 0) &&
752 (purple_proxy_info_get_username(proxy_info) == NULL) &&
753 (purple_proxy_info_get_password(proxy_info) == NULL))
755 purple_proxy_info_destroy(proxy_info);
756 return;
759 purple_account_set_proxy_info(account, proxy_info);
762 static void
763 parse_current_error(xmlnode *node, PurpleAccount *account)
765 guint type;
766 char *type_str = NULL, *description = NULL;
767 xmlnode *child;
768 PurpleConnectionErrorInfo *current_error = NULL;
770 child = xmlnode_get_child(node, "type");
771 if (child == NULL || (type_str = xmlnode_get_data(child)) == NULL)
772 return;
773 type = atoi(type_str);
774 g_free(type_str);
776 if (type > PURPLE_CONNECTION_ERROR_OTHER_ERROR)
778 purple_debug_error("account",
779 "Invalid PurpleConnectionError value %d found when "
780 "loading account information for %s\n",
781 type, purple_account_get_username(account));
782 type = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
785 child = xmlnode_get_child(node, "description");
786 if (child)
787 description = xmlnode_get_data(child);
788 if (description == NULL)
789 description = g_strdup("");
791 current_error = g_new0(PurpleConnectionErrorInfo, 1);
792 PURPLE_DBUS_REGISTER_POINTER(current_error, PurpleConnectionErrorInfo);
793 current_error->type = type;
794 current_error->description = description;
796 set_current_error(account, current_error);
799 static PurpleAccount *
800 parse_account(xmlnode *node)
802 PurpleAccount *ret;
803 xmlnode *child;
804 char *protocol_id = NULL;
805 char *name = NULL;
806 char *data;
808 child = xmlnode_get_child(node, "protocol");
809 if (child != NULL)
810 protocol_id = xmlnode_get_data(child);
812 child = xmlnode_get_child(node, "name");
813 if (child != NULL)
814 name = xmlnode_get_data(child);
815 if (name == NULL)
817 /* Do we really need to do this? */
818 child = xmlnode_get_child(node, "username");
819 if (child != NULL)
820 name = xmlnode_get_data(child);
823 if ((protocol_id == NULL) || (name == NULL))
825 g_free(protocol_id);
826 g_free(name);
827 return NULL;
830 ret = purple_account_new(name, _purple_oscar_convert(name, protocol_id)); /* XXX: */
831 g_free(name);
832 g_free(protocol_id);
834 /* Read the password */
835 child = xmlnode_get_child(node, "password");
836 if ((child != NULL) && ((data = xmlnode_get_data(child)) != NULL))
838 purple_account_set_remember_password(ret, TRUE);
839 purple_account_set_password(ret, data);
840 g_free(data);
843 /* Read the alias */
844 child = xmlnode_get_child(node, "alias");
845 if ((child != NULL) && ((data = xmlnode_get_data(child)) != NULL))
847 if (*data != '\0')
848 purple_account_set_alias(ret, data);
849 g_free(data);
852 /* Read the statuses */
853 child = xmlnode_get_child(node, "statuses");
854 if (child != NULL)
856 parse_statuses(child, ret);
859 /* Read the userinfo */
860 child = xmlnode_get_child(node, "userinfo");
861 if ((child != NULL) && ((data = xmlnode_get_data(child)) != NULL))
863 purple_account_set_user_info(ret, data);
864 g_free(data);
867 /* Read an old buddyicon */
868 child = xmlnode_get_child(node, "buddyicon");
869 if ((child != NULL) && ((data = xmlnode_get_data(child)) != NULL))
871 const char *dirname = purple_buddy_icons_get_cache_dir();
872 char *filename = g_build_filename(dirname, data, NULL);
873 gchar *contents;
874 gsize len;
876 if (g_file_get_contents(filename, &contents, &len, NULL))
878 purple_buddy_icons_set_account_icon(ret, (guchar *)contents, len);
880 else
882 /* Try to see if the icon got left behind in the old cache. */
883 g_free(filename);
884 filename = g_build_filename(g_get_home_dir(), ".gaim", "icons", data, NULL);
885 if (g_file_get_contents(filename, &contents, &len, NULL)) {
886 purple_buddy_icons_set_account_icon(ret, (guchar*)contents, len);
890 g_free(filename);
891 g_free(data);
894 /* Read settings (both core and UI) */
895 for (child = xmlnode_get_child(node, "settings"); child != NULL;
896 child = xmlnode_get_next_twin(child))
898 parse_settings(child, ret);
901 /* Read proxy */
902 child = xmlnode_get_child(node, "proxy");
903 if (child != NULL)
905 parse_proxy_info(child, ret);
908 /* Read current error */
909 child = xmlnode_get_child(node, "current_error");
910 if (child != NULL)
912 parse_current_error(child, ret);
915 return ret;
918 static void
919 load_accounts(void)
921 xmlnode *node, *child;
923 accounts_loaded = TRUE;
925 node = purple_util_read_xml_from_file("accounts.xml", _("accounts"));
927 if (node == NULL)
928 return;
930 for (child = xmlnode_get_child(node, "account"); child != NULL;
931 child = xmlnode_get_next_twin(child))
933 PurpleAccount *new_acct;
934 new_acct = parse_account(child);
935 purple_accounts_add(new_acct);
938 xmlnode_free(node);
940 _purple_buddy_icons_account_loaded_cb();
944 static void
945 delete_setting(void *data)
947 PurpleAccountSetting *setting = (PurpleAccountSetting *)data;
949 g_free(setting->ui);
951 if (setting->type == PURPLE_PREF_STRING)
952 g_free(setting->value.string);
954 g_free(setting);
957 PurpleAccount *
958 purple_account_new(const char *username, const char *protocol_id)
960 PurpleAccount *account = NULL;
961 PurpleAccountPrivate *priv = NULL;
962 PurplePlugin *prpl = NULL;
963 PurplePluginProtocolInfo *prpl_info = NULL;
964 PurpleStatusType *status_type;
966 g_return_val_if_fail(username != NULL, NULL);
967 g_return_val_if_fail(protocol_id != NULL, NULL);
969 account = purple_accounts_find(username, protocol_id);
971 if (account != NULL)
972 return account;
974 account = g_new0(PurpleAccount, 1);
975 PURPLE_DBUS_REGISTER_POINTER(account, PurpleAccount);
976 priv = g_new0(PurpleAccountPrivate, 1);
977 account->priv = priv;
979 purple_account_set_username(account, username);
981 purple_account_set_protocol_id(account, protocol_id);
983 account->settings = g_hash_table_new_full(g_str_hash, g_str_equal,
984 g_free, delete_setting);
985 account->ui_settings = g_hash_table_new_full(g_str_hash, g_str_equal,
986 g_free, (GDestroyNotify)g_hash_table_destroy);
987 account->system_log = NULL;
988 /* 0 is not a valid privacy setting */
989 account->perm_deny = PURPLE_PRIVACY_ALLOW_ALL;
991 purple_signal_emit(purple_accounts_get_handle(), "account-created", account);
993 prpl = purple_find_prpl(protocol_id);
995 if (prpl == NULL)
996 return account;
998 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
999 if (prpl_info != NULL && prpl_info->status_types != NULL)
1000 purple_account_set_status_types(account, prpl_info->status_types(account));
1002 account->presence = purple_presence_new_for_account(account);
1004 status_type = purple_account_get_status_type_with_primitive(account, PURPLE_STATUS_AVAILABLE);
1005 if (status_type != NULL)
1006 purple_presence_set_status_active(account->presence,
1007 purple_status_type_get_id(status_type),
1008 TRUE);
1009 else
1010 purple_presence_set_status_active(account->presence,
1011 "offline",
1012 TRUE);
1014 return account;
1017 void
1018 purple_account_destroy(PurpleAccount *account)
1020 PurpleAccountPrivate *priv = NULL;
1021 GList *l;
1023 g_return_if_fail(account != NULL);
1025 purple_debug_info("account", "Destroying account %p\n", account);
1026 purple_signal_emit(purple_accounts_get_handle(), "account-destroying", account);
1028 for (l = purple_get_conversations(); l != NULL; l = l->next)
1030 PurpleConversation *conv = (PurpleConversation *)l->data;
1032 if (purple_conversation_get_account(conv) == account)
1033 purple_conversation_set_account(conv, NULL);
1036 g_free(account->username);
1037 g_free(account->alias);
1038 g_free(account->password);
1039 g_free(account->user_info);
1040 g_free(account->buddy_icon_path);
1041 g_free(account->protocol_id);
1043 g_hash_table_destroy(account->settings);
1044 g_hash_table_destroy(account->ui_settings);
1046 purple_account_set_status_types(account, NULL);
1048 purple_presence_destroy(account->presence);
1050 if(account->system_log)
1051 purple_log_free(account->system_log);
1053 while (account->deny) {
1054 g_free(account->deny->data);
1055 account->deny = g_slist_delete_link(account->deny, account->deny);
1058 while (account->permit) {
1059 g_free(account->permit->data);
1060 account->permit = g_slist_delete_link(account->permit, account->permit);
1063 priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
1064 PURPLE_DBUS_UNREGISTER_POINTER(priv->current_error);
1065 if (priv->current_error) {
1066 g_free(priv->current_error->description);
1067 g_free(priv->current_error);
1069 g_free(priv);
1071 PURPLE_DBUS_UNREGISTER_POINTER(account);
1072 g_free(account);
1075 void
1076 purple_account_set_register_callback(PurpleAccount *account, PurpleAccountRegistrationCb cb, void *user_data)
1078 g_return_if_fail(account != NULL);
1080 account->registration_cb = cb;
1081 account->registration_cb_user_data = user_data;
1084 void
1085 purple_account_register(PurpleAccount *account)
1087 g_return_if_fail(account != NULL);
1089 purple_debug_info("account", "Registering account %s\n",
1090 purple_account_get_username(account));
1092 _purple_connection_new(account, TRUE, purple_account_get_password(account));
1095 void
1096 purple_account_unregister(PurpleAccount *account, PurpleAccountUnregistrationCb cb, void *user_data)
1098 g_return_if_fail(account != NULL);
1100 purple_debug_info("account", "Unregistering account %s\n",
1101 purple_account_get_username(account));
1103 _purple_connection_new_unregister(account, purple_account_get_password(account), cb, user_data);
1106 static void
1107 request_password_ok_cb(PurpleAccount *account, PurpleRequestFields *fields)
1109 const char *entry;
1110 gboolean remember;
1112 entry = purple_request_fields_get_string(fields, "password");
1113 remember = purple_request_fields_get_bool(fields, "remember");
1115 if (!entry || !*entry)
1117 purple_notify_error(account, NULL, _("Password is required to sign on."), NULL);
1118 return;
1121 if(remember)
1122 purple_account_set_remember_password(account, TRUE);
1124 purple_account_set_password(account, entry);
1126 _purple_connection_new(account, FALSE, entry);
1129 static void
1130 request_password_cancel_cb(PurpleAccount *account, PurpleRequestFields *fields)
1132 /* Disable the account as the user has canceled connecting */
1133 purple_account_set_enabled(account, purple_core_get_ui(), FALSE);
1137 void
1138 purple_account_request_password(PurpleAccount *account, GCallback ok_cb,
1139 GCallback cancel_cb, void *user_data)
1141 gchar *primary;
1142 const gchar *username;
1143 PurpleRequestFieldGroup *group;
1144 PurpleRequestField *field;
1145 PurpleRequestFields *fields;
1147 /* Close any previous password request windows */
1148 purple_request_close_with_handle(account);
1150 username = purple_account_get_username(account);
1151 primary = g_strdup_printf(_("Enter password for %s (%s)"), username,
1152 purple_account_get_protocol_name(account));
1154 fields = purple_request_fields_new();
1155 group = purple_request_field_group_new(NULL);
1156 purple_request_fields_add_group(fields, group);
1158 field = purple_request_field_string_new("password", _("Enter Password"), NULL, FALSE);
1159 purple_request_field_string_set_masked(field, TRUE);
1160 purple_request_field_set_required(field, TRUE);
1161 purple_request_field_group_add_field(group, field);
1163 field = purple_request_field_bool_new("remember", _("Save password"), FALSE);
1164 purple_request_field_group_add_field(group, field);
1166 purple_request_fields(account,
1167 NULL,
1168 primary,
1169 NULL,
1170 fields,
1171 _("OK"), ok_cb,
1172 _("Cancel"), cancel_cb,
1173 account, NULL, NULL,
1174 user_data);
1175 g_free(primary);
1178 void
1179 purple_account_connect(PurpleAccount *account)
1181 PurplePlugin *prpl;
1182 const char *password, *username;
1183 PurplePluginProtocolInfo *prpl_info;
1185 g_return_if_fail(account != NULL);
1187 username = purple_account_get_username(account);
1189 if (!purple_account_get_enabled(account, purple_core_get_ui())) {
1190 purple_debug_info("account",
1191 "Account %s not enabled, not connecting.\n",
1192 username);
1193 return;
1196 prpl = purple_find_prpl(purple_account_get_protocol_id(account));
1197 if (prpl == NULL) {
1198 gchar *message;
1200 message = g_strdup_printf(_("Missing protocol plugin for %s"), username);
1201 purple_notify_error(account, _("Connection Error"), message, NULL);
1202 g_free(message);
1203 return;
1206 purple_debug_info("account", "Connecting to account %s.\n", username);
1208 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
1209 password = purple_account_get_password(account);
1210 if ((password == NULL) &&
1211 !(prpl_info->options & OPT_PROTO_NO_PASSWORD) &&
1212 !(prpl_info->options & OPT_PROTO_PASSWORD_OPTIONAL))
1213 purple_account_request_password(account, G_CALLBACK(request_password_ok_cb), G_CALLBACK(request_password_cancel_cb), account);
1214 else
1215 _purple_connection_new(account, FALSE, password);
1218 void
1219 purple_account_disconnect(PurpleAccount *account)
1221 PurpleConnection *gc;
1222 const char *username;
1224 g_return_if_fail(account != NULL);
1225 g_return_if_fail(!purple_account_is_disconnected(account));
1227 username = purple_account_get_username(account);
1228 purple_debug_info("account", "Disconnecting account %s (%p)\n",
1229 username ? username : "(null)", account);
1231 account->disconnecting = TRUE;
1233 gc = purple_account_get_connection(account);
1234 _purple_connection_destroy(gc);
1235 if (!purple_account_get_remember_password(account))
1236 purple_account_set_password(account, NULL);
1237 purple_account_set_connection(account, NULL);
1239 account->disconnecting = FALSE;
1242 void
1243 purple_account_notify_added(PurpleAccount *account, const char *remote_user,
1244 const char *id, const char *alias,
1245 const char *message)
1247 PurpleAccountUiOps *ui_ops;
1249 g_return_if_fail(account != NULL);
1250 g_return_if_fail(remote_user != NULL);
1252 ui_ops = purple_accounts_get_ui_ops();
1254 if (ui_ops != NULL && ui_ops->notify_added != NULL)
1255 ui_ops->notify_added(account, remote_user, id, alias, message);
1258 void
1259 purple_account_request_add(PurpleAccount *account, const char *remote_user,
1260 const char *id, const char *alias,
1261 const char *message)
1263 PurpleAccountUiOps *ui_ops;
1265 g_return_if_fail(account != NULL);
1266 g_return_if_fail(remote_user != NULL);
1268 ui_ops = purple_accounts_get_ui_ops();
1270 if (ui_ops != NULL && ui_ops->request_add != NULL)
1271 ui_ops->request_add(account, remote_user, id, alias, message);
1274 static PurpleAccountRequestInfo *
1275 purple_account_request_info_unref(PurpleAccountRequestInfo *info)
1277 if (--info->ref)
1278 return info;
1280 /* TODO: This will leak info->user_data, but there is no callback to just clean that up */
1281 g_free(info->user);
1282 g_free(info);
1283 return NULL;
1286 static void
1287 purple_account_request_close_info(PurpleAccountRequestInfo *info)
1289 PurpleAccountUiOps *ops;
1291 ops = purple_accounts_get_ui_ops();
1293 if (ops != NULL && ops->close_account_request != NULL)
1294 ops->close_account_request(info->ui_handle);
1296 purple_account_request_info_unref(info);
1299 void
1300 purple_account_request_close_with_account(PurpleAccount *account)
1302 GList *l, *l_next;
1304 g_return_if_fail(account != NULL);
1306 for (l = handles; l != NULL; l = l_next) {
1307 PurpleAccountRequestInfo *info = l->data;
1309 l_next = l->next;
1311 if (info->account == account) {
1312 handles = g_list_remove(handles, info);
1313 purple_account_request_close_info(info);
1318 void
1319 purple_account_request_close(void *ui_handle)
1321 GList *l, *l_next;
1323 g_return_if_fail(ui_handle != NULL);
1325 for (l = handles; l != NULL; l = l_next) {
1326 PurpleAccountRequestInfo *info = l->data;
1328 l_next = l->next;
1330 if (info->ui_handle == ui_handle) {
1331 handles = g_list_remove(handles, info);
1332 purple_account_request_close_info(info);
1337 static void
1338 request_auth_cb(void *data)
1340 PurpleAccountRequestInfo *info = data;
1342 handles = g_list_remove(handles, info);
1344 if (info->auth_cb != NULL)
1345 info->auth_cb(info->userdata);
1347 purple_signal_emit(purple_accounts_get_handle(),
1348 "account-authorization-granted", info->account, info->user);
1350 purple_account_request_info_unref(info);
1353 static void
1354 request_deny_cb(void *data)
1356 PurpleAccountRequestInfo *info = data;
1358 handles = g_list_remove(handles, info);
1360 if (info->deny_cb != NULL)
1361 info->deny_cb(info->userdata);
1363 purple_signal_emit(purple_accounts_get_handle(),
1364 "account-authorization-denied", info->account, info->user);
1366 purple_account_request_info_unref(info);
1369 void *
1370 purple_account_request_authorization(PurpleAccount *account, const char *remote_user,
1371 const char *id, const char *alias, const char *message, gboolean on_list,
1372 PurpleAccountRequestAuthorizationCb auth_cb, PurpleAccountRequestAuthorizationCb deny_cb, void *user_data)
1374 PurpleAccountUiOps *ui_ops;
1375 PurpleAccountRequestInfo *info;
1376 int plugin_return;
1378 g_return_val_if_fail(account != NULL, NULL);
1379 g_return_val_if_fail(remote_user != NULL, NULL);
1381 ui_ops = purple_accounts_get_ui_ops();
1383 plugin_return = GPOINTER_TO_INT(
1384 purple_signal_emit_return_1(purple_accounts_get_handle(),
1385 "account-authorization-requested", account, remote_user));
1387 if (plugin_return > 0) {
1388 if (auth_cb != NULL)
1389 auth_cb(user_data);
1390 return NULL;
1391 } else if (plugin_return < 0) {
1392 if (deny_cb != NULL)
1393 deny_cb(user_data);
1394 return NULL;
1397 if (ui_ops != NULL && ui_ops->request_authorize != NULL) {
1398 info = g_new0(PurpleAccountRequestInfo, 1);
1399 info->type = PURPLE_ACCOUNT_REQUEST_AUTHORIZATION;
1400 info->account = account;
1401 info->auth_cb = auth_cb;
1402 info->deny_cb = deny_cb;
1403 info->userdata = user_data;
1404 info->user = g_strdup(remote_user);
1405 info->ref = 2; /* We hold an extra ref to make sure info remains valid
1406 if any of the callbacks are called synchronously. We
1407 unref it after the function call */
1409 info->ui_handle = ui_ops->request_authorize(account, remote_user, id, alias, message,
1410 on_list, request_auth_cb, request_deny_cb, info);
1412 info = purple_account_request_info_unref(info);
1413 if (info) {
1414 handles = g_list_append(handles, info);
1415 return info->ui_handle;
1419 return NULL;
1422 static void
1423 change_password_cb(PurpleAccount *account, PurpleRequestFields *fields)
1425 const char *orig_pass, *new_pass_1, *new_pass_2;
1427 orig_pass = purple_request_fields_get_string(fields, "password");
1428 new_pass_1 = purple_request_fields_get_string(fields, "new_password_1");
1429 new_pass_2 = purple_request_fields_get_string(fields, "new_password_2");
1431 if (g_utf8_collate(new_pass_1, new_pass_2))
1433 purple_notify_error(account, NULL,
1434 _("New passwords do not match."), NULL);
1436 return;
1439 if ((purple_request_fields_is_field_required(fields, "password") &&
1440 (orig_pass == NULL || *orig_pass == '\0')) ||
1441 (purple_request_fields_is_field_required(fields, "new_password_1") &&
1442 (new_pass_1 == NULL || *new_pass_1 == '\0')) ||
1443 (purple_request_fields_is_field_required(fields, "new_password_2") &&
1444 (new_pass_2 == NULL || *new_pass_2 == '\0')))
1446 purple_notify_error(account, NULL,
1447 _("Fill out all fields completely."), NULL);
1448 return;
1451 purple_account_change_password(account, orig_pass, new_pass_1);
1454 void
1455 purple_account_request_change_password(PurpleAccount *account)
1457 PurpleRequestFields *fields;
1458 PurpleRequestFieldGroup *group;
1459 PurpleRequestField *field;
1460 PurpleConnection *gc;
1461 PurplePlugin *prpl = NULL;
1462 PurplePluginProtocolInfo *prpl_info = NULL;
1463 char primary[256];
1465 g_return_if_fail(account != NULL);
1466 g_return_if_fail(purple_account_is_connected(account));
1468 gc = purple_account_get_connection(account);
1469 if (gc != NULL)
1470 prpl = purple_connection_get_prpl(gc);
1471 if (prpl != NULL)
1472 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
1474 fields = purple_request_fields_new();
1476 group = purple_request_field_group_new(NULL);
1477 purple_request_fields_add_group(fields, group);
1479 field = purple_request_field_string_new("password", _("Original password"),
1480 NULL, FALSE);
1481 purple_request_field_string_set_masked(field, TRUE);
1482 if (!(prpl_info && (prpl_info->options | OPT_PROTO_PASSWORD_OPTIONAL)))
1483 purple_request_field_set_required(field, TRUE);
1484 purple_request_field_group_add_field(group, field);
1486 field = purple_request_field_string_new("new_password_1",
1487 _("New password"),
1488 NULL, FALSE);
1489 purple_request_field_string_set_masked(field, TRUE);
1490 if (!(prpl_info && (prpl_info->options | OPT_PROTO_PASSWORD_OPTIONAL)))
1491 purple_request_field_set_required(field, TRUE);
1492 purple_request_field_group_add_field(group, field);
1494 field = purple_request_field_string_new("new_password_2",
1495 _("New password (again)"),
1496 NULL, FALSE);
1497 purple_request_field_string_set_masked(field, TRUE);
1498 if (!(prpl_info && (prpl_info->options | OPT_PROTO_PASSWORD_OPTIONAL)))
1499 purple_request_field_set_required(field, TRUE);
1500 purple_request_field_group_add_field(group, field);
1502 g_snprintf(primary, sizeof(primary), _("Change password for %s"),
1503 purple_account_get_username(account));
1505 /* I'm sticking this somewhere in the code: bologna */
1507 purple_request_fields(purple_account_get_connection(account),
1508 NULL,
1509 primary,
1510 _("Please enter your current password and your "
1511 "new password."),
1512 fields,
1513 _("OK"), G_CALLBACK(change_password_cb),
1514 _("Cancel"), NULL,
1515 account, NULL, NULL,
1516 account);
1519 static void
1520 set_user_info_cb(PurpleAccount *account, const char *user_info)
1522 PurpleConnection *gc;
1524 purple_account_set_user_info(account, user_info);
1525 gc = purple_account_get_connection(account);
1526 serv_set_info(gc, user_info);
1529 void
1530 purple_account_request_change_user_info(PurpleAccount *account)
1532 PurpleConnection *gc;
1533 char primary[256];
1535 g_return_if_fail(account != NULL);
1536 g_return_if_fail(purple_account_is_connected(account));
1538 gc = purple_account_get_connection(account);
1540 g_snprintf(primary, sizeof(primary),
1541 _("Change user information for %s"),
1542 purple_account_get_username(account));
1544 purple_request_input(gc, _("Set User Info"), primary, NULL,
1545 purple_account_get_user_info(account),
1546 TRUE, FALSE, ((gc != NULL) &&
1547 (gc->flags & PURPLE_CONNECTION_HTML) ? "html" : NULL),
1548 _("Save"), G_CALLBACK(set_user_info_cb),
1549 _("Cancel"), NULL,
1550 account, NULL, NULL,
1551 account);
1554 void
1555 purple_account_set_username(PurpleAccount *account, const char *username)
1557 PurpleBlistUiOps *blist_ops;
1559 g_return_if_fail(account != NULL);
1561 g_free(account->username);
1562 account->username = g_strdup(username);
1564 schedule_accounts_save();
1566 /* if the name changes, we should re-write the buddy list
1567 * to disk with the new name */
1568 blist_ops = purple_blist_get_ui_ops();
1569 if (blist_ops != NULL && blist_ops->save_account != NULL)
1570 blist_ops->save_account(account);
1573 void
1574 purple_account_set_password(PurpleAccount *account, const char *password)
1576 g_return_if_fail(account != NULL);
1578 g_free(account->password);
1579 account->password = g_strdup(password);
1581 schedule_accounts_save();
1584 void
1585 purple_account_set_alias(PurpleAccount *account, const char *alias)
1587 g_return_if_fail(account != NULL);
1590 * Do nothing if alias and account->alias are both NULL. Or if
1591 * they're the exact same string.
1593 if (alias == account->alias)
1594 return;
1596 if ((!alias && account->alias) || (alias && !account->alias) ||
1597 g_utf8_collate(account->alias, alias))
1599 char *old = account->alias;
1601 account->alias = g_strdup(alias);
1602 purple_signal_emit(purple_accounts_get_handle(), "account-alias-changed",
1603 account, old);
1604 g_free(old);
1606 schedule_accounts_save();
1610 void
1611 purple_account_set_user_info(PurpleAccount *account, const char *user_info)
1613 g_return_if_fail(account != NULL);
1615 g_free(account->user_info);
1616 account->user_info = g_strdup(user_info);
1618 schedule_accounts_save();
1621 void purple_account_set_buddy_icon_path(PurpleAccount *account, const char *path)
1623 g_return_if_fail(account != NULL);
1625 g_free(account->buddy_icon_path);
1626 account->buddy_icon_path = g_strdup(path);
1628 schedule_accounts_save();
1631 void
1632 purple_account_set_protocol_id(PurpleAccount *account, const char *protocol_id)
1634 g_return_if_fail(account != NULL);
1635 g_return_if_fail(protocol_id != NULL);
1637 g_free(account->protocol_id);
1638 account->protocol_id = g_strdup(protocol_id);
1640 schedule_accounts_save();
1643 void
1644 purple_account_set_connection(PurpleAccount *account, PurpleConnection *gc)
1646 g_return_if_fail(account != NULL);
1648 account->gc = gc;
1651 void
1652 purple_account_set_remember_password(PurpleAccount *account, gboolean value)
1654 g_return_if_fail(account != NULL);
1656 account->remember_pass = value;
1658 schedule_accounts_save();
1661 void
1662 purple_account_set_check_mail(PurpleAccount *account, gboolean value)
1664 g_return_if_fail(account != NULL);
1666 purple_account_set_bool(account, "check-mail", value);
1669 void
1670 purple_account_set_enabled(PurpleAccount *account, const char *ui,
1671 gboolean value)
1673 PurpleConnection *gc;
1674 gboolean was_enabled = FALSE;
1676 g_return_if_fail(account != NULL);
1677 g_return_if_fail(ui != NULL);
1679 was_enabled = purple_account_get_enabled(account, ui);
1681 purple_account_set_ui_bool(account, ui, "auto-login", value);
1682 gc = purple_account_get_connection(account);
1684 if(was_enabled && !value)
1685 purple_signal_emit(purple_accounts_get_handle(), "account-disabled", account);
1686 else if(!was_enabled && value)
1687 purple_signal_emit(purple_accounts_get_handle(), "account-enabled", account);
1689 if ((gc != NULL) && (gc->wants_to_die == TRUE))
1690 return;
1692 if (value && purple_presence_is_online(account->presence))
1693 purple_account_connect(account);
1694 else if (!value && !purple_account_is_disconnected(account))
1695 purple_account_disconnect(account);
1698 void
1699 purple_account_set_proxy_info(PurpleAccount *account, PurpleProxyInfo *info)
1701 g_return_if_fail(account != NULL);
1703 if (account->proxy_info != NULL)
1704 purple_proxy_info_destroy(account->proxy_info);
1706 account->proxy_info = info;
1708 schedule_accounts_save();
1711 void
1712 purple_account_set_privacy_type(PurpleAccount *account, PurplePrivacyType privacy_type)
1714 g_return_if_fail(account != NULL);
1716 account->perm_deny = privacy_type;
1719 void
1720 purple_account_set_status_types(PurpleAccount *account, GList *status_types)
1722 g_return_if_fail(account != NULL);
1724 /* Out with the old... */
1725 if (account->status_types != NULL)
1727 g_list_foreach(account->status_types, (GFunc)purple_status_type_destroy, NULL);
1728 g_list_free(account->status_types);
1731 /* In with the new... */
1732 account->status_types = status_types;
1735 void
1736 purple_account_set_status(PurpleAccount *account, const char *status_id,
1737 gboolean active, ...)
1739 GList *attrs = NULL;
1740 const gchar *id;
1741 gpointer data;
1742 va_list args;
1744 va_start(args, active);
1745 while ((id = va_arg(args, const char *)) != NULL)
1747 attrs = g_list_append(attrs, (char *)id);
1748 data = va_arg(args, void *);
1749 attrs = g_list_append(attrs, data);
1751 purple_account_set_status_list(account, status_id, active, attrs);
1752 g_list_free(attrs);
1753 va_end(args);
1756 void
1757 purple_account_set_status_list(PurpleAccount *account, const char *status_id,
1758 gboolean active, GList *attrs)
1760 PurpleStatus *status;
1762 g_return_if_fail(account != NULL);
1763 g_return_if_fail(status_id != NULL);
1765 status = purple_account_get_status(account, status_id);
1766 if (status == NULL)
1768 purple_debug_error("account",
1769 "Invalid status ID '%s' for account %s (%s)\n",
1770 status_id, purple_account_get_username(account),
1771 purple_account_get_protocol_id(account));
1772 return;
1775 if (active || purple_status_is_independent(status))
1776 purple_status_set_active_with_attrs_list(status, active, attrs);
1779 * Our current statuses are saved to accounts.xml (so that when we
1780 * reconnect, we go back to the previous status).
1782 schedule_accounts_save();
1785 struct public_alias_closure
1787 PurpleAccount *account;
1788 gpointer failure_cb;
1791 static gboolean
1792 set_public_alias_unsupported(gpointer data)
1794 struct public_alias_closure *closure = data;
1795 PurpleSetPublicAliasFailureCallback failure_cb = closure->failure_cb;
1797 failure_cb(closure->account,
1798 _("This protocol does not support setting a public alias."));
1799 g_free(closure);
1801 return FALSE;
1804 void
1805 purple_account_set_public_alias(PurpleAccount *account,
1806 const char *alias, PurpleSetPublicAliasSuccessCallback success_cb,
1807 PurpleSetPublicAliasFailureCallback failure_cb)
1809 PurpleConnection *gc;
1810 PurplePlugin *prpl = NULL;
1811 PurplePluginProtocolInfo *prpl_info = NULL;
1813 g_return_if_fail(account != NULL);
1814 g_return_if_fail(purple_account_is_connected(account));
1816 gc = purple_account_get_connection(account);
1817 prpl = purple_connection_get_prpl(gc);
1818 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
1820 if (PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, set_public_alias))
1821 prpl_info->set_public_alias(gc, alias, success_cb, failure_cb);
1822 else if (failure_cb) {
1823 struct public_alias_closure *closure =
1824 g_new0(struct public_alias_closure, 1);
1825 closure->account = account;
1826 closure->failure_cb = failure_cb;
1827 purple_timeout_add(0, set_public_alias_unsupported, closure);
1831 static gboolean
1832 get_public_alias_unsupported(gpointer data)
1834 struct public_alias_closure *closure = data;
1835 PurpleGetPublicAliasFailureCallback failure_cb = closure->failure_cb;
1837 failure_cb(closure->account,
1838 _("This protocol does not support fetching the public alias."));
1839 g_free(closure);
1841 return FALSE;
1844 void
1845 purple_account_get_public_alias(PurpleAccount *account,
1846 PurpleGetPublicAliasSuccessCallback success_cb,
1847 PurpleGetPublicAliasFailureCallback failure_cb)
1849 PurpleConnection *gc;
1850 PurplePlugin *prpl = NULL;
1851 PurplePluginProtocolInfo *prpl_info = NULL;
1853 g_return_if_fail(account != NULL);
1854 g_return_if_fail(purple_account_is_connected(account));
1856 gc = purple_account_get_connection(account);
1857 prpl = purple_connection_get_prpl(gc);
1858 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
1860 if (PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, get_public_alias))
1861 prpl_info->get_public_alias(gc, success_cb, failure_cb);
1862 else if (failure_cb) {
1863 struct public_alias_closure *closure =
1864 g_new0(struct public_alias_closure, 1);
1865 closure->account = account;
1866 closure->failure_cb = failure_cb;
1867 purple_timeout_add(0, get_public_alias_unsupported, closure);
1871 void
1872 purple_account_clear_settings(PurpleAccount *account)
1874 g_return_if_fail(account != NULL);
1876 g_hash_table_destroy(account->settings);
1878 account->settings = g_hash_table_new_full(g_str_hash, g_str_equal,
1879 g_free, delete_setting);
1882 void
1883 purple_account_remove_setting(PurpleAccount *account, const char *setting)
1885 g_return_if_fail(account != NULL);
1886 g_return_if_fail(setting != NULL);
1888 g_hash_table_remove(account->settings, setting);
1891 void
1892 purple_account_set_int(PurpleAccount *account, const char *name, int value)
1894 PurpleAccountSetting *setting;
1896 g_return_if_fail(account != NULL);
1897 g_return_if_fail(name != NULL);
1899 setting = g_new0(PurpleAccountSetting, 1);
1901 setting->type = PURPLE_PREF_INT;
1902 setting->value.integer = value;
1904 g_hash_table_insert(account->settings, g_strdup(name), setting);
1906 schedule_accounts_save();
1909 void
1910 purple_account_set_string(PurpleAccount *account, const char *name,
1911 const char *value)
1913 PurpleAccountSetting *setting;
1915 g_return_if_fail(account != NULL);
1916 g_return_if_fail(name != NULL);
1918 setting = g_new0(PurpleAccountSetting, 1);
1920 setting->type = PURPLE_PREF_STRING;
1921 setting->value.string = g_strdup(value);
1923 g_hash_table_insert(account->settings, g_strdup(name), setting);
1925 schedule_accounts_save();
1928 void
1929 purple_account_set_bool(PurpleAccount *account, const char *name, gboolean value)
1931 PurpleAccountSetting *setting;
1933 g_return_if_fail(account != NULL);
1934 g_return_if_fail(name != NULL);
1936 setting = g_new0(PurpleAccountSetting, 1);
1938 setting->type = PURPLE_PREF_BOOLEAN;
1939 setting->value.boolean = value;
1941 g_hash_table_insert(account->settings, g_strdup(name), setting);
1943 schedule_accounts_save();
1946 static GHashTable *
1947 get_ui_settings_table(PurpleAccount *account, const char *ui)
1949 GHashTable *table;
1951 table = g_hash_table_lookup(account->ui_settings, ui);
1953 if (table == NULL) {
1954 table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
1955 delete_setting);
1956 g_hash_table_insert(account->ui_settings, g_strdup(ui), table);
1959 return table;
1962 void
1963 purple_account_set_ui_int(PurpleAccount *account, const char *ui,
1964 const char *name, int value)
1966 PurpleAccountSetting *setting;
1967 GHashTable *table;
1969 g_return_if_fail(account != NULL);
1970 g_return_if_fail(ui != NULL);
1971 g_return_if_fail(name != NULL);
1973 setting = g_new0(PurpleAccountSetting, 1);
1975 setting->type = PURPLE_PREF_INT;
1976 setting->ui = g_strdup(ui);
1977 setting->value.integer = value;
1979 table = get_ui_settings_table(account, ui);
1981 g_hash_table_insert(table, g_strdup(name), setting);
1983 schedule_accounts_save();
1986 void
1987 purple_account_set_ui_string(PurpleAccount *account, const char *ui,
1988 const char *name, const char *value)
1990 PurpleAccountSetting *setting;
1991 GHashTable *table;
1993 g_return_if_fail(account != NULL);
1994 g_return_if_fail(ui != NULL);
1995 g_return_if_fail(name != NULL);
1997 setting = g_new0(PurpleAccountSetting, 1);
1999 setting->type = PURPLE_PREF_STRING;
2000 setting->ui = g_strdup(ui);
2001 setting->value.string = g_strdup(value);
2003 table = get_ui_settings_table(account, ui);
2005 g_hash_table_insert(table, g_strdup(name), setting);
2007 schedule_accounts_save();
2010 void
2011 purple_account_set_ui_bool(PurpleAccount *account, const char *ui,
2012 const char *name, gboolean value)
2014 PurpleAccountSetting *setting;
2015 GHashTable *table;
2017 g_return_if_fail(account != NULL);
2018 g_return_if_fail(ui != NULL);
2019 g_return_if_fail(name != NULL);
2021 setting = g_new0(PurpleAccountSetting, 1);
2023 setting->type = PURPLE_PREF_BOOLEAN;
2024 setting->ui = g_strdup(ui);
2025 setting->value.boolean = value;
2027 table = get_ui_settings_table(account, ui);
2029 g_hash_table_insert(table, g_strdup(name), setting);
2031 schedule_accounts_save();
2034 static PurpleConnectionState
2035 purple_account_get_state(const PurpleAccount *account)
2037 PurpleConnection *gc;
2039 g_return_val_if_fail(account != NULL, PURPLE_DISCONNECTED);
2041 gc = purple_account_get_connection(account);
2042 if (!gc)
2043 return PURPLE_DISCONNECTED;
2045 return purple_connection_get_state(gc);
2048 gboolean
2049 purple_account_is_connected(const PurpleAccount *account)
2051 return (purple_account_get_state(account) == PURPLE_CONNECTED);
2054 gboolean
2055 purple_account_is_connecting(const PurpleAccount *account)
2057 return (purple_account_get_state(account) == PURPLE_CONNECTING);
2060 gboolean
2061 purple_account_is_disconnected(const PurpleAccount *account)
2063 return (purple_account_get_state(account) == PURPLE_DISCONNECTED);
2066 const char *
2067 purple_account_get_username(const PurpleAccount *account)
2069 g_return_val_if_fail(account != NULL, NULL);
2071 return account->username;
2074 const char *
2075 purple_account_get_password(const PurpleAccount *account)
2077 g_return_val_if_fail(account != NULL, NULL);
2079 return account->password;
2082 const char *
2083 purple_account_get_alias(const PurpleAccount *account)
2085 g_return_val_if_fail(account != NULL, NULL);
2087 return account->alias;
2090 const char *
2091 purple_account_get_user_info(const PurpleAccount *account)
2093 g_return_val_if_fail(account != NULL, NULL);
2095 return account->user_info;
2098 const char *
2099 purple_account_get_buddy_icon_path(const PurpleAccount *account)
2101 g_return_val_if_fail(account != NULL, NULL);
2103 return account->buddy_icon_path;
2106 const char *
2107 purple_account_get_protocol_id(const PurpleAccount *account)
2109 g_return_val_if_fail(account != NULL, NULL);
2110 return account->protocol_id;
2113 const char *
2114 purple_account_get_protocol_name(const PurpleAccount *account)
2116 PurplePlugin *p;
2118 g_return_val_if_fail(account != NULL, NULL);
2120 p = purple_find_prpl(purple_account_get_protocol_id(account));
2122 return ((p && p->info->name) ? _(p->info->name) : _("Unknown"));
2125 PurpleConnection *
2126 purple_account_get_connection(const PurpleAccount *account)
2128 g_return_val_if_fail(account != NULL, NULL);
2130 return account->gc;
2133 const gchar *
2134 purple_account_get_name_for_display(const PurpleAccount *account)
2136 PurpleBuddy *self = NULL;
2137 PurpleConnection *gc = NULL;
2138 const gchar *name = NULL, *username = NULL, *displayname = NULL;
2140 name = purple_account_get_alias(account);
2142 if (name) {
2143 return name;
2146 username = purple_account_get_username(account);
2147 self = purple_find_buddy((PurpleAccount *)account, username);
2149 if (self) {
2150 const gchar *calias= purple_buddy_get_contact_alias(self);
2152 /* We don't want to return the buddy name if the buddy/contact
2153 * doesn't have an alias set. */
2154 if (!purple_strequal(username, calias)) {
2155 return calias;
2159 gc = purple_account_get_connection(account);
2160 displayname = purple_connection_get_display_name(gc);
2162 if (displayname) {
2163 return displayname;
2166 return username;
2169 gboolean
2170 purple_account_get_remember_password(const PurpleAccount *account)
2172 g_return_val_if_fail(account != NULL, FALSE);
2174 return account->remember_pass;
2177 gboolean
2178 purple_account_get_check_mail(const PurpleAccount *account)
2180 g_return_val_if_fail(account != NULL, FALSE);
2182 return purple_account_get_bool(account, "check-mail", FALSE);
2185 gboolean
2186 purple_account_get_enabled(const PurpleAccount *account, const char *ui)
2188 g_return_val_if_fail(account != NULL, FALSE);
2189 g_return_val_if_fail(ui != NULL, FALSE);
2191 return purple_account_get_ui_bool(account, ui, "auto-login", FALSE);
2194 PurpleProxyInfo *
2195 purple_account_get_proxy_info(const PurpleAccount *account)
2197 g_return_val_if_fail(account != NULL, NULL);
2199 return account->proxy_info;
2202 PurplePrivacyType
2203 purple_account_get_privacy_type(const PurpleAccount *account)
2205 g_return_val_if_fail(account != NULL, PURPLE_PRIVACY_ALLOW_ALL);
2207 return account->perm_deny;
2210 PurpleStatus *
2211 purple_account_get_active_status(const PurpleAccount *account)
2213 g_return_val_if_fail(account != NULL, NULL);
2215 return purple_presence_get_active_status(account->presence);
2218 PurpleStatus *
2219 purple_account_get_status(const PurpleAccount *account, const char *status_id)
2221 g_return_val_if_fail(account != NULL, NULL);
2222 g_return_val_if_fail(status_id != NULL, NULL);
2224 return purple_presence_get_status(account->presence, status_id);
2227 PurpleStatusType *
2228 purple_account_get_status_type(const PurpleAccount *account, const char *id)
2230 GList *l;
2232 g_return_val_if_fail(account != NULL, NULL);
2233 g_return_val_if_fail(id != NULL, NULL);
2235 for (l = purple_account_get_status_types(account); l != NULL; l = l->next)
2237 PurpleStatusType *status_type = (PurpleStatusType *)l->data;
2239 if (purple_strequal(purple_status_type_get_id(status_type), id))
2240 return status_type;
2243 return NULL;
2246 PurpleStatusType *
2247 purple_account_get_status_type_with_primitive(const PurpleAccount *account, PurpleStatusPrimitive primitive)
2249 GList *l;
2251 g_return_val_if_fail(account != NULL, NULL);
2253 for (l = purple_account_get_status_types(account); l != NULL; l = l->next)
2255 PurpleStatusType *status_type = (PurpleStatusType *)l->data;
2257 if (purple_status_type_get_primitive(status_type) == primitive)
2258 return status_type;
2261 return NULL;
2264 PurplePresence *
2265 purple_account_get_presence(const PurpleAccount *account)
2267 g_return_val_if_fail(account != NULL, NULL);
2269 return account->presence;
2272 gboolean
2273 purple_account_is_status_active(const PurpleAccount *account,
2274 const char *status_id)
2276 g_return_val_if_fail(account != NULL, FALSE);
2277 g_return_val_if_fail(status_id != NULL, FALSE);
2279 return purple_presence_is_status_active(account->presence, status_id);
2282 GList *
2283 purple_account_get_status_types(const PurpleAccount *account)
2285 g_return_val_if_fail(account != NULL, NULL);
2287 return account->status_types;
2291 purple_account_get_int(const PurpleAccount *account, const char *name,
2292 int default_value)
2294 PurpleAccountSetting *setting;
2296 g_return_val_if_fail(account != NULL, default_value);
2297 g_return_val_if_fail(name != NULL, default_value);
2299 setting = g_hash_table_lookup(account->settings, name);
2301 if (setting == NULL)
2302 return default_value;
2304 g_return_val_if_fail(setting->type == PURPLE_PREF_INT, default_value);
2306 return setting->value.integer;
2309 const char *
2310 purple_account_get_string(const PurpleAccount *account, const char *name,
2311 const char *default_value)
2313 PurpleAccountSetting *setting;
2315 g_return_val_if_fail(account != NULL, default_value);
2316 g_return_val_if_fail(name != NULL, default_value);
2318 setting = g_hash_table_lookup(account->settings, name);
2320 if (setting == NULL)
2321 return default_value;
2323 g_return_val_if_fail(setting->type == PURPLE_PREF_STRING, default_value);
2325 return setting->value.string;
2328 gboolean
2329 purple_account_get_bool(const PurpleAccount *account, const char *name,
2330 gboolean default_value)
2332 PurpleAccountSetting *setting;
2334 g_return_val_if_fail(account != NULL, default_value);
2335 g_return_val_if_fail(name != NULL, default_value);
2337 setting = g_hash_table_lookup(account->settings, name);
2339 if (setting == NULL)
2340 return default_value;
2342 g_return_val_if_fail(setting->type == PURPLE_PREF_BOOLEAN, default_value);
2344 return setting->value.boolean;
2348 purple_account_get_ui_int(const PurpleAccount *account, const char *ui,
2349 const char *name, int default_value)
2351 PurpleAccountSetting *setting;
2352 GHashTable *table;
2354 g_return_val_if_fail(account != NULL, default_value);
2355 g_return_val_if_fail(ui != NULL, default_value);
2356 g_return_val_if_fail(name != NULL, default_value);
2358 if ((table = g_hash_table_lookup(account->ui_settings, ui)) == NULL)
2359 return default_value;
2361 if ((setting = g_hash_table_lookup(table, name)) == NULL)
2362 return default_value;
2364 g_return_val_if_fail(setting->type == PURPLE_PREF_INT, default_value);
2366 return setting->value.integer;
2369 const char *
2370 purple_account_get_ui_string(const PurpleAccount *account, const char *ui,
2371 const char *name, const char *default_value)
2373 PurpleAccountSetting *setting;
2374 GHashTable *table;
2376 g_return_val_if_fail(account != NULL, default_value);
2377 g_return_val_if_fail(ui != NULL, default_value);
2378 g_return_val_if_fail(name != NULL, default_value);
2380 if ((table = g_hash_table_lookup(account->ui_settings, ui)) == NULL)
2381 return default_value;
2383 if ((setting = g_hash_table_lookup(table, name)) == NULL)
2384 return default_value;
2386 g_return_val_if_fail(setting->type == PURPLE_PREF_STRING, default_value);
2388 return setting->value.string;
2391 gboolean
2392 purple_account_get_ui_bool(const PurpleAccount *account, const char *ui,
2393 const char *name, gboolean default_value)
2395 PurpleAccountSetting *setting;
2396 GHashTable *table;
2398 g_return_val_if_fail(account != NULL, default_value);
2399 g_return_val_if_fail(ui != NULL, default_value);
2400 g_return_val_if_fail(name != NULL, default_value);
2402 if ((table = g_hash_table_lookup(account->ui_settings, ui)) == NULL)
2403 return default_value;
2405 if ((setting = g_hash_table_lookup(table, name)) == NULL)
2406 return default_value;
2408 g_return_val_if_fail(setting->type == PURPLE_PREF_BOOLEAN, default_value);
2410 return setting->value.boolean;
2413 PurpleLog *
2414 purple_account_get_log(PurpleAccount *account, gboolean create)
2416 g_return_val_if_fail(account != NULL, NULL);
2418 if(!account->system_log && create){
2419 PurplePresence *presence;
2420 int login_time;
2422 presence = purple_account_get_presence(account);
2423 login_time = purple_presence_get_login_time(presence);
2425 account->system_log = purple_log_new(PURPLE_LOG_SYSTEM,
2426 purple_account_get_username(account), account, NULL,
2427 (login_time != 0) ? login_time : time(NULL), NULL);
2430 return account->system_log;
2433 void
2434 purple_account_destroy_log(PurpleAccount *account)
2436 g_return_if_fail(account != NULL);
2438 if(account->system_log){
2439 purple_log_free(account->system_log);
2440 account->system_log = NULL;
2444 void
2445 purple_account_add_buddy(PurpleAccount *account, PurpleBuddy *buddy)
2447 PurplePluginProtocolInfo *prpl_info = NULL;
2448 PurpleConnection *gc;
2449 PurplePlugin *prpl = NULL;
2451 g_return_if_fail(account != NULL);
2452 g_return_if_fail(buddy != NULL);
2454 gc = purple_account_get_connection(account);
2455 if (gc != NULL)
2456 prpl = purple_connection_get_prpl(gc);
2458 if (prpl != NULL)
2459 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
2461 if (prpl_info != NULL && prpl_info->add_buddy != NULL)
2462 prpl_info->add_buddy(gc, buddy, purple_buddy_get_group(buddy));
2465 void
2466 purple_account_add_buddies(PurpleAccount *account, GList *buddies)
2468 PurplePluginProtocolInfo *prpl_info = NULL;
2469 PurpleConnection *gc = purple_account_get_connection(account);
2470 PurplePlugin *prpl = NULL;
2472 if (gc != NULL)
2473 prpl = purple_connection_get_prpl(gc);
2475 if (prpl != NULL)
2476 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
2478 if (prpl_info) {
2479 GList *cur, *groups = NULL;
2481 /* Make a list of what group each buddy is in */
2482 for (cur = buddies; cur != NULL; cur = cur->next) {
2483 PurpleBuddy *buddy = cur->data;
2484 groups = g_list_append(groups, purple_buddy_get_group(buddy));
2487 if (prpl_info->add_buddies != NULL)
2488 prpl_info->add_buddies(gc, buddies, groups);
2489 else if (prpl_info->add_buddy != NULL) {
2490 GList *curb = buddies, *curg = groups;
2492 while ((curb != NULL) && (curg != NULL)) {
2493 prpl_info->add_buddy(gc, curb->data, curg->data);
2494 curb = curb->next;
2495 curg = curg->next;
2499 g_list_free(groups);
2503 void
2504 purple_account_remove_buddy(PurpleAccount *account, PurpleBuddy *buddy,
2505 PurpleGroup *group)
2507 PurplePluginProtocolInfo *prpl_info = NULL;
2508 PurpleConnection *gc = purple_account_get_connection(account);
2509 PurplePlugin *prpl = NULL;
2511 if (gc != NULL)
2512 prpl = purple_connection_get_prpl(gc);
2514 if (prpl != NULL)
2515 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
2517 if (prpl_info && prpl_info->remove_buddy)
2518 prpl_info->remove_buddy(gc, buddy, group);
2521 void
2522 purple_account_remove_buddies(PurpleAccount *account, GList *buddies, GList *groups)
2524 PurplePluginProtocolInfo *prpl_info = NULL;
2525 PurpleConnection *gc = purple_account_get_connection(account);
2526 PurplePlugin *prpl = NULL;
2528 if (gc != NULL)
2529 prpl = purple_connection_get_prpl(gc);
2531 if (prpl != NULL)
2532 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
2534 if (prpl_info) {
2535 if (prpl_info->remove_buddies)
2536 prpl_info->remove_buddies(gc, buddies, groups);
2537 else {
2538 GList *curb = buddies;
2539 GList *curg = groups;
2540 while ((curb != NULL) && (curg != NULL)) {
2541 purple_account_remove_buddy(account, curb->data, curg->data);
2542 curb = curb->next;
2543 curg = curg->next;
2549 void
2550 purple_account_remove_group(PurpleAccount *account, PurpleGroup *group)
2552 PurplePluginProtocolInfo *prpl_info = NULL;
2553 PurpleConnection *gc = purple_account_get_connection(account);
2554 PurplePlugin *prpl = NULL;
2556 if (gc != NULL)
2557 prpl = purple_connection_get_prpl(gc);
2559 if (prpl != NULL)
2560 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
2562 if (prpl_info && prpl_info->remove_group)
2563 prpl_info->remove_group(gc, group);
2566 void
2567 purple_account_change_password(PurpleAccount *account, const char *orig_pw,
2568 const char *new_pw)
2570 PurplePluginProtocolInfo *prpl_info = NULL;
2571 PurpleConnection *gc = purple_account_get_connection(account);
2572 PurplePlugin *prpl = NULL;
2574 purple_account_set_password(account, new_pw);
2576 if (gc != NULL)
2577 prpl = purple_connection_get_prpl(gc);
2579 if (prpl != NULL)
2580 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
2582 if (prpl_info && prpl_info->change_passwd)
2583 prpl_info->change_passwd(gc, orig_pw, new_pw);
2586 gboolean purple_account_supports_offline_message(PurpleAccount *account, PurpleBuddy *buddy)
2588 PurpleConnection *gc;
2589 PurplePluginProtocolInfo *prpl_info = NULL;
2590 PurplePlugin *prpl = NULL;
2592 g_return_val_if_fail(account, FALSE);
2593 g_return_val_if_fail(buddy, FALSE);
2595 gc = purple_account_get_connection(account);
2596 if (gc == NULL)
2597 return FALSE;
2599 prpl = purple_connection_get_prpl(gc);
2601 if (prpl != NULL)
2602 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
2604 if (!prpl_info || !prpl_info->offline_message)
2605 return FALSE;
2606 return prpl_info->offline_message(buddy);
2609 static void
2610 signed_on_cb(PurpleConnection *gc,
2611 gpointer unused)
2613 PurpleAccount *account = purple_connection_get_account(gc);
2614 purple_account_clear_current_error(account);
2616 purple_signal_emit(purple_accounts_get_handle(), "account-signed-on",
2617 account);
2620 static void
2621 signed_off_cb(PurpleConnection *gc,
2622 gpointer unused)
2624 PurpleAccount *account = purple_connection_get_account(gc);
2626 purple_signal_emit(purple_accounts_get_handle(), "account-signed-off",
2627 account);
2630 static void
2631 set_current_error(PurpleAccount *account, PurpleConnectionErrorInfo *new_err)
2633 PurpleAccountPrivate *priv;
2634 PurpleConnectionErrorInfo *old_err;
2636 g_return_if_fail(account != NULL);
2638 priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
2639 old_err = priv->current_error;
2641 if(new_err == old_err)
2642 return;
2644 priv->current_error = new_err;
2646 purple_signal_emit(purple_accounts_get_handle(),
2647 "account-error-changed",
2648 account, old_err, new_err);
2649 schedule_accounts_save();
2651 if(old_err)
2652 g_free(old_err->description);
2654 PURPLE_DBUS_UNREGISTER_POINTER(old_err);
2655 g_free(old_err);
2658 static void
2659 connection_error_cb(PurpleConnection *gc,
2660 PurpleConnectionError type,
2661 const gchar *description,
2662 gpointer unused)
2664 PurpleAccount *account;
2665 PurpleConnectionErrorInfo *err;
2667 account = purple_connection_get_account(gc);
2669 g_return_if_fail(account != NULL);
2671 err = g_new0(PurpleConnectionErrorInfo, 1);
2672 PURPLE_DBUS_REGISTER_POINTER(err, PurpleConnectionErrorInfo);
2674 err->type = type;
2675 err->description = g_strdup(description);
2677 set_current_error(account, err);
2679 purple_signal_emit(purple_accounts_get_handle(), "account-connection-error",
2680 account, type, description);
2683 const PurpleConnectionErrorInfo *
2684 purple_account_get_current_error(PurpleAccount *account)
2686 PurpleAccountPrivate *priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
2687 return priv->current_error;
2690 void
2691 purple_account_clear_current_error(PurpleAccount *account)
2693 set_current_error(account, NULL);
2696 void
2697 purple_accounts_add(PurpleAccount *account)
2699 g_return_if_fail(account != NULL);
2701 if (g_list_find(accounts, account) != NULL)
2702 return;
2704 accounts = g_list_append(accounts, account);
2706 schedule_accounts_save();
2708 purple_signal_emit(purple_accounts_get_handle(), "account-added", account);
2711 void
2712 purple_accounts_remove(PurpleAccount *account)
2714 g_return_if_fail(account != NULL);
2716 accounts = g_list_remove(accounts, account);
2718 schedule_accounts_save();
2720 /* Clearing the error ensures that account-error-changed is emitted,
2721 * which is the end of the guarantee that the the error's pointer is
2722 * valid.
2724 purple_account_clear_current_error(account);
2725 purple_signal_emit(purple_accounts_get_handle(), "account-removed", account);
2728 void
2729 purple_accounts_delete(PurpleAccount *account)
2731 PurpleBlistNode *gnode, *cnode, *bnode;
2732 GList *iter;
2734 g_return_if_fail(account != NULL);
2737 * Disable the account before blowing it out of the water.
2738 * Conceptually it probably makes more sense to disable the
2739 * account for all UIs rather than the just the current UI,
2740 * but it doesn't really matter.
2742 purple_account_set_enabled(account, purple_core_get_ui(), FALSE);
2744 purple_notify_close_with_handle(account);
2745 purple_request_close_with_handle(account);
2747 purple_accounts_remove(account);
2749 /* Remove this account's buddies */
2750 for (gnode = purple_blist_get_root();
2751 gnode != NULL;
2752 gnode = purple_blist_node_get_sibling_next(gnode))
2754 if (!PURPLE_BLIST_NODE_IS_GROUP(gnode))
2755 continue;
2757 cnode = purple_blist_node_get_first_child(gnode);
2758 while (cnode) {
2759 PurpleBlistNode *cnode_next = purple_blist_node_get_sibling_next(cnode);
2761 if(PURPLE_BLIST_NODE_IS_CONTACT(cnode)) {
2762 bnode = purple_blist_node_get_first_child(cnode);
2763 while (bnode) {
2764 PurpleBlistNode *bnode_next = purple_blist_node_get_sibling_next(bnode);
2766 if (PURPLE_BLIST_NODE_IS_BUDDY(bnode)) {
2767 PurpleBuddy *b = (PurpleBuddy *)bnode;
2769 if (purple_buddy_get_account(b) == account)
2770 purple_blist_remove_buddy(b);
2772 bnode = bnode_next;
2774 } else if (PURPLE_BLIST_NODE_IS_CHAT(cnode)) {
2775 PurpleChat *c = (PurpleChat *)cnode;
2777 if (purple_chat_get_account(c) == account)
2778 purple_blist_remove_chat(c);
2780 cnode = cnode_next;
2784 /* Remove any open conversation for this account */
2785 for (iter = purple_get_conversations(); iter; ) {
2786 PurpleConversation *conv = iter->data;
2787 iter = iter->next;
2788 if (purple_conversation_get_account(conv) == account)
2789 purple_conversation_destroy(conv);
2792 /* Remove this account's pounces */
2793 purple_pounce_destroy_all_by_account(account);
2795 /* This will cause the deletion of an old buddy icon. */
2796 purple_buddy_icons_set_account_icon(account, NULL, 0);
2798 purple_account_destroy(account);
2801 void
2802 purple_accounts_reorder(PurpleAccount *account, gint new_index)
2804 gint index;
2805 GList *l;
2807 g_return_if_fail(account != NULL);
2808 g_return_if_fail(new_index <= g_list_length(accounts));
2810 index = g_list_index(accounts, account);
2812 if (index == -1) {
2813 purple_debug_error("account",
2814 "Unregistered account (%s) discovered during reorder!\n",
2815 purple_account_get_username(account));
2816 return;
2819 l = g_list_nth(accounts, index);
2821 if (new_index > index)
2822 new_index--;
2824 /* Remove the old one. */
2825 accounts = g_list_delete_link(accounts, l);
2827 /* Insert it where it should go. */
2828 accounts = g_list_insert(accounts, account, new_index);
2830 schedule_accounts_save();
2833 GList *
2834 purple_accounts_get_all(void)
2836 return accounts;
2839 GList *
2840 purple_accounts_get_all_active(void)
2842 GList *list = NULL;
2843 GList *all = purple_accounts_get_all();
2845 while (all != NULL) {
2846 PurpleAccount *account = all->data;
2848 if (purple_account_get_enabled(account, purple_core_get_ui()))
2849 list = g_list_append(list, account);
2851 all = all->next;
2854 return list;
2857 PurpleAccount *
2858 purple_accounts_find(const char *name, const char *protocol_id)
2860 PurpleAccount *account = NULL;
2861 GList *l;
2862 char *who;
2864 g_return_val_if_fail(name != NULL, NULL);
2865 g_return_val_if_fail(protocol_id != NULL, NULL);
2867 for (l = purple_accounts_get_all(); l != NULL; l = l->next) {
2868 account = (PurpleAccount *)l->data;
2869 if (!purple_strequal(account->protocol_id, protocol_id))
2870 continue;
2872 who = g_strdup(purple_normalize(account, name));
2873 if (purple_strequal(purple_normalize(account, purple_account_get_username(account)), who)) {
2874 g_free(who);
2875 return account;
2877 g_free(who);
2880 return NULL;
2883 void
2884 purple_accounts_restore_current_statuses()
2886 GList *l;
2887 PurpleAccount *account;
2889 /* If we're not connected to the Internet right now, we bail on this */
2890 if (!purple_network_is_available())
2892 purple_debug_warning("account", "Network not connected; skipping reconnect\n");
2893 return;
2896 for (l = purple_accounts_get_all(); l != NULL; l = l->next)
2898 account = (PurpleAccount *)l->data;
2899 if (purple_account_get_enabled(account, purple_core_get_ui()) &&
2900 (purple_presence_is_online(account->presence)))
2902 purple_account_connect(account);
2907 void
2908 purple_accounts_set_ui_ops(PurpleAccountUiOps *ops)
2910 account_ui_ops = ops;
2913 PurpleAccountUiOps *
2914 purple_accounts_get_ui_ops(void)
2916 return account_ui_ops;
2919 void *
2920 purple_accounts_get_handle(void)
2922 static int handle;
2924 return &handle;
2927 void
2928 purple_accounts_init(void)
2930 void *handle = purple_accounts_get_handle();
2931 void *conn_handle = purple_connections_get_handle();
2933 purple_signal_register(handle, "account-connecting",
2934 purple_marshal_VOID__POINTER, NULL, 1,
2935 purple_value_new(PURPLE_TYPE_SUBTYPE,
2936 PURPLE_SUBTYPE_ACCOUNT));
2938 purple_signal_register(handle, "account-disabled",
2939 purple_marshal_VOID__POINTER, NULL, 1,
2940 purple_value_new(PURPLE_TYPE_SUBTYPE,
2941 PURPLE_SUBTYPE_ACCOUNT));
2943 purple_signal_register(handle, "account-enabled",
2944 purple_marshal_VOID__POINTER, NULL, 1,
2945 purple_value_new(PURPLE_TYPE_SUBTYPE,
2946 PURPLE_SUBTYPE_ACCOUNT));
2948 purple_signal_register(handle, "account-setting-info",
2949 purple_marshal_VOID__POINTER_POINTER, NULL, 2,
2950 purple_value_new(PURPLE_TYPE_SUBTYPE,
2951 PURPLE_SUBTYPE_ACCOUNT),
2952 purple_value_new(PURPLE_TYPE_STRING));
2954 purple_signal_register(handle, "account-set-info",
2955 purple_marshal_VOID__POINTER_POINTER, NULL, 2,
2956 purple_value_new(PURPLE_TYPE_SUBTYPE,
2957 PURPLE_SUBTYPE_ACCOUNT),
2958 purple_value_new(PURPLE_TYPE_STRING));
2960 purple_signal_register(handle, "account-created",
2961 purple_marshal_VOID__POINTER, NULL, 1,
2962 purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_ACCOUNT));
2964 purple_signal_register(handle, "account-destroying",
2965 purple_marshal_VOID__POINTER, NULL, 1,
2966 purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_ACCOUNT));
2968 purple_signal_register(handle, "account-added",
2969 purple_marshal_VOID__POINTER, NULL, 1,
2970 purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_ACCOUNT));
2972 purple_signal_register(handle, "account-removed",
2973 purple_marshal_VOID__POINTER, NULL, 1,
2974 purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_ACCOUNT));
2976 purple_signal_register(handle, "account-status-changed",
2977 purple_marshal_VOID__POINTER_POINTER_POINTER, NULL, 3,
2978 purple_value_new(PURPLE_TYPE_SUBTYPE,
2979 PURPLE_SUBTYPE_ACCOUNT),
2980 purple_value_new(PURPLE_TYPE_SUBTYPE,
2981 PURPLE_SUBTYPE_STATUS),
2982 purple_value_new(PURPLE_TYPE_SUBTYPE,
2983 PURPLE_SUBTYPE_STATUS));
2985 purple_signal_register(handle, "account-actions-changed",
2986 purple_marshal_VOID__POINTER, NULL, 1,
2987 purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_ACCOUNT));
2989 purple_signal_register(handle, "account-alias-changed",
2990 purple_marshal_VOID__POINTER_POINTER, NULL, 2,
2991 purple_value_new(PURPLE_TYPE_SUBTYPE,
2992 PURPLE_SUBTYPE_ACCOUNT),
2993 purple_value_new(PURPLE_TYPE_STRING));
2995 purple_signal_register(handle, "account-authorization-requested",
2996 purple_marshal_INT__POINTER_POINTER,
2997 purple_value_new(PURPLE_TYPE_INT), 2,
2998 purple_value_new(PURPLE_TYPE_SUBTYPE,
2999 PURPLE_SUBTYPE_ACCOUNT),
3000 purple_value_new(PURPLE_TYPE_STRING));
3002 purple_signal_register(handle, "account-authorization-denied",
3003 purple_marshal_VOID__POINTER_POINTER, NULL, 2,
3004 purple_value_new(PURPLE_TYPE_SUBTYPE,
3005 PURPLE_SUBTYPE_ACCOUNT),
3006 purple_value_new(PURPLE_TYPE_STRING));
3008 purple_signal_register(handle, "account-authorization-granted",
3009 purple_marshal_VOID__POINTER_POINTER, NULL, 2,
3010 purple_value_new(PURPLE_TYPE_SUBTYPE,
3011 PURPLE_SUBTYPE_ACCOUNT),
3012 purple_value_new(PURPLE_TYPE_STRING));
3014 purple_signal_register(handle, "account-error-changed",
3015 purple_marshal_VOID__POINTER_POINTER_POINTER,
3016 NULL, 3,
3017 purple_value_new(PURPLE_TYPE_SUBTYPE,
3018 PURPLE_SUBTYPE_ACCOUNT),
3019 purple_value_new(PURPLE_TYPE_POINTER),
3020 purple_value_new(PURPLE_TYPE_POINTER));
3022 purple_signal_register(handle, "account-signed-on",
3023 purple_marshal_VOID__POINTER, NULL, 1,
3024 purple_value_new(PURPLE_TYPE_SUBTYPE,
3025 PURPLE_SUBTYPE_ACCOUNT));
3027 purple_signal_register(handle, "account-signed-off",
3028 purple_marshal_VOID__POINTER, NULL, 1,
3029 purple_value_new(PURPLE_TYPE_SUBTYPE,
3030 PURPLE_SUBTYPE_ACCOUNT));
3032 purple_signal_register(handle, "account-connection-error",
3033 purple_marshal_VOID__POINTER_INT_POINTER, NULL, 3,
3034 purple_value_new(PURPLE_TYPE_SUBTYPE,
3035 PURPLE_SUBTYPE_ACCOUNT),
3036 purple_value_new(PURPLE_TYPE_ENUM),
3037 purple_value_new(PURPLE_TYPE_STRING));
3039 purple_signal_connect(conn_handle, "signed-on", handle,
3040 PURPLE_CALLBACK(signed_on_cb), NULL);
3041 purple_signal_connect(conn_handle, "signed-off", handle,
3042 PURPLE_CALLBACK(signed_off_cb), NULL);
3043 purple_signal_connect(conn_handle, "connection-error", handle,
3044 PURPLE_CALLBACK(connection_error_cb), NULL);
3046 load_accounts();
3050 void
3051 purple_accounts_uninit(void)
3053 gpointer handle = purple_accounts_get_handle();
3054 if (save_timer != 0)
3056 purple_timeout_remove(save_timer);
3057 save_timer = 0;
3058 sync_accounts();
3061 for (; accounts; accounts = g_list_delete_link(accounts, accounts))
3062 purple_account_destroy(accounts->data);
3064 purple_signals_disconnect_by_handle(handle);
3065 purple_signals_unregister_by_instance(handle);