mark PurpleImageClass as private
[pidgin-git.git] / libpurple / account.c
blob23fb7f7ffdba759f7073b0d30416453d18a279a6
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 "glibcompat.h"
24 #include "accounts.h"
25 #include "core.h"
26 #include "debug.h"
27 #include "network.h"
28 #include "notify.h"
29 #include "pounce.h"
30 #include "prefs.h"
31 #include "request.h"
32 #include "server.h"
33 #include "signals.h"
34 #include "util.h"
36 /**
37 * PurpleAccount:
39 * Structure representing an account.
41 struct _PurpleAccount
43 GObject gparent;
46 typedef struct
48 char *username; /* The username. */
49 char *alias; /* How you appear to yourself. */
50 char *password; /* The account password. */
51 char *user_info; /* User information. */
53 char *buddy_icon_path; /* The buddy icon's non-cached path. */
55 gboolean remember_pass; /* Remember the password. */
58 * TODO: After a GObject representing a protocol is ready, use it
59 * here instead of the protocol ID.
61 char *protocol_id; /* The ID of the protocol. */
63 PurpleConnection *gc; /* The connection handle. */
64 gboolean disconnecting; /* The account is currently disconnecting */
66 GHashTable *settings; /* Protocol-specific settings. */
67 GHashTable *ui_settings; /* UI-specific settings. */
69 PurpleProxyInfo *proxy_info; /* Proxy information. This will be set */
70 /* to NULL when the account inherits */
71 /* proxy settings from global prefs. */
74 * TODO: Instead of linked lists for permit and deny, use a data
75 * structure that allows fast lookups AND decent performance when
76 * iterating through all items. Fast lookups should help performance
77 * for protocols like MSN, where all your buddies exist in your permit
78 * list therefore the permit list is large. Possibly GTree or
79 * GHashTable.
81 GSList *permit; /* Permit list. */
82 GSList *deny; /* Deny list. */
83 PurpleAccountPrivacyType privacy_type; /* The permit/deny setting. */
85 GList *status_types; /* Status types. */
87 PurplePresence *presence; /* Presence. */
88 PurpleLog *system_log; /* The system log */
90 PurpleAccountRegistrationCb registration_cb;
91 void *registration_cb_user_data;
93 PurpleConnectionErrorInfo *current_error; /* Errors */
94 } PurpleAccountPrivate;
96 typedef struct
98 char *ui;
99 GValue value;
101 } PurpleAccountSetting;
103 typedef struct
105 PurpleAccountRequestType type;
106 PurpleAccount *account;
107 void *ui_handle;
108 char *user;
109 gpointer userdata;
110 PurpleAccountRequestAuthorizationCb auth_cb;
111 PurpleAccountRequestAuthorizationCb deny_cb;
112 guint ref;
113 } PurpleAccountRequestInfo;
115 typedef struct
117 PurpleCallback cb;
118 gpointer data;
119 } PurpleCallbackBundle;
121 /* GObject Property enums */
122 enum
124 PROP_0,
125 PROP_USERNAME,
126 PROP_PRIVATE_ALIAS,
127 PROP_ENABLED,
128 PROP_CONNECTION,
129 PROP_PROTOCOL_ID,
130 PROP_USER_INFO,
131 PROP_BUDDY_ICON_PATH,
132 PROP_REMEMBER_PASSWORD,
133 PROP_CHECK_MAIL,
134 PROP_LAST
137 static GParamSpec *properties[PROP_LAST];
138 static GList *handles = NULL;
140 G_DEFINE_TYPE_WITH_PRIVATE(PurpleAccount, purple_account, G_TYPE_OBJECT);
142 /******************************************************************************
143 * Helpers
144 *****************************************************************************/
145 static void
146 purple_account_register_got_password_cb(PurpleAccount *account,
147 const gchar *password, GError *error, gpointer data)
149 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
151 _purple_connection_new(account, TRUE, password);
154 void
155 purple_account_register(PurpleAccount *account)
157 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
159 purple_debug_info("account", "Registering account %s\n",
160 purple_account_get_username(account));
162 purple_keyring_get_password(account,
163 purple_account_register_got_password_cb, NULL);
166 static void
167 purple_account_unregister_got_password_cb(PurpleAccount *account,
168 const gchar *password, GError *error, gpointer data)
170 PurpleCallbackBundle *cbb = data;
171 PurpleAccountUnregistrationCb cb;
173 cb = (PurpleAccountUnregistrationCb)cbb->cb;
174 _purple_connection_new_unregister(account, password, cb, cbb->data);
176 g_free(cbb);
179 struct register_completed_closure
181 PurpleAccount *account;
182 gboolean succeeded;
185 static gboolean
186 purple_account_register_completed_cb(gpointer data)
188 struct register_completed_closure *closure = data;
189 PurpleAccountPrivate *priv;
191 priv = purple_account_get_instance_private(closure->account);
193 if (priv->registration_cb)
194 (priv->registration_cb)(closure->account, closure->succeeded,
195 priv->registration_cb_user_data);
197 g_object_unref(closure->account);
198 g_free(closure);
200 return FALSE;
203 static void
204 request_password_ok_cb(PurpleAccount *account, PurpleRequestFields *fields)
206 const char *entry;
207 gboolean remember;
209 entry = purple_request_fields_get_string(fields, "password");
210 remember = purple_request_fields_get_bool(fields, "remember");
212 if (!entry || !*entry)
214 purple_notify_error(account, NULL,
215 _("Password is required to sign on."), NULL,
216 purple_request_cpar_from_account(account));
217 return;
220 purple_account_set_remember_password(account, remember);
222 purple_account_set_password(account, entry, NULL, NULL);
223 _purple_connection_new(account, FALSE, entry);
226 static void
227 request_password_cancel_cb(PurpleAccount *account, PurpleRequestFields *fields)
229 /* Disable the account as the user has cancelled connecting */
230 purple_account_set_enabled(account, purple_core_get_ui(), FALSE);
234 static void
235 purple_account_connect_got_password_cb(PurpleAccount *account,
236 const gchar *password, GError *error, gpointer data)
238 PurpleProtocol *protocol = data;
240 if ((password == NULL || *password == '\0') &&
241 !(purple_protocol_get_options(protocol) & OPT_PROTO_NO_PASSWORD) &&
242 !(purple_protocol_get_options(protocol) & OPT_PROTO_PASSWORD_OPTIONAL))
243 purple_account_request_password(account,
244 G_CALLBACK(request_password_ok_cb),
245 G_CALLBACK(request_password_cancel_cb), account);
246 else
247 _purple_connection_new(account, FALSE, password);
250 static PurpleAccountRequestInfo *
251 purple_account_request_info_unref(PurpleAccountRequestInfo *info)
253 if (--info->ref)
254 return info;
256 /* TODO: This will leak info->user_data, but there is no callback to just clean that up */
257 g_free(info->user);
258 g_free(info);
259 return NULL;
262 static void
263 purple_account_request_close_info(PurpleAccountRequestInfo *info)
265 PurpleAccountUiOps *ops;
267 ops = purple_accounts_get_ui_ops();
269 if (ops != NULL && ops->close_account_request != NULL)
270 ops->close_account_request(info->ui_handle);
272 purple_account_request_info_unref(info);
275 static void
276 request_auth_cb(const char *message, void *data)
278 PurpleAccountRequestInfo *info = data;
280 handles = g_list_remove(handles, info);
282 if (info->auth_cb != NULL)
283 info->auth_cb(message, info->userdata);
285 purple_signal_emit(purple_accounts_get_handle(),
286 "account-authorization-granted", info->account, info->user, message);
288 purple_account_request_info_unref(info);
291 static void
292 request_deny_cb(const char *message, void *data)
294 PurpleAccountRequestInfo *info = data;
296 handles = g_list_remove(handles, info);
298 if (info->deny_cb != NULL)
299 info->deny_cb(message, info->userdata);
301 purple_signal_emit(purple_accounts_get_handle(),
302 "account-authorization-denied", info->account, info->user, message);
304 purple_account_request_info_unref(info);
307 static void
308 change_password_cb(PurpleAccount *account, PurpleRequestFields *fields)
310 const char *orig_pass, *new_pass_1, *new_pass_2;
312 orig_pass = purple_request_fields_get_string(fields, "password");
313 new_pass_1 = purple_request_fields_get_string(fields, "new_password_1");
314 new_pass_2 = purple_request_fields_get_string(fields, "new_password_2");
316 if (g_utf8_collate(new_pass_1, new_pass_2))
318 purple_notify_error(account, NULL,
319 _("New passwords do not match."), NULL,
320 purple_request_cpar_from_account(account));
322 return;
325 if ((purple_request_fields_is_field_required(fields, "password") &&
326 (orig_pass == NULL || *orig_pass == '\0')) ||
327 (purple_request_fields_is_field_required(fields, "new_password_1") &&
328 (new_pass_1 == NULL || *new_pass_1 == '\0')) ||
329 (purple_request_fields_is_field_required(fields, "new_password_2") &&
330 (new_pass_2 == NULL || *new_pass_2 == '\0')))
332 purple_notify_error(account, NULL,
333 _("Fill out all fields completely."), NULL,
334 purple_request_cpar_from_account(account));
335 return;
338 purple_account_change_password(account, orig_pass, new_pass_1);
341 static void
342 set_user_info_cb(PurpleAccount *account, const char *user_info)
344 PurpleConnection *gc;
346 purple_account_set_user_info(account, user_info);
347 gc = purple_account_get_connection(account);
348 purple_serv_set_info(gc, user_info);
351 struct public_alias_closure
353 PurpleAccount *account;
354 gpointer failure_cb;
357 static gboolean
358 set_public_alias_unsupported(gpointer data)
360 struct public_alias_closure *closure = data;
361 PurpleSetPublicAliasFailureCallback failure_cb = closure->failure_cb;
363 failure_cb(closure->account,
364 _("This protocol does not support setting a public alias."));
366 g_object_unref(closure->account);
367 g_free(closure);
369 return FALSE;
372 static gboolean
373 get_public_alias_unsupported(gpointer data)
375 struct public_alias_closure *closure = data;
376 PurpleGetPublicAliasFailureCallback failure_cb = closure->failure_cb;
378 failure_cb(closure->account,
379 _("This protocol does not support fetching the public alias."));
381 g_object_unref(closure->account);
382 g_free(closure);
384 return FALSE;
387 static void
388 delete_setting(void *data)
390 PurpleAccountSetting *setting = (PurpleAccountSetting *)data;
392 g_free(setting->ui);
393 g_value_unset(&setting->value);
395 g_free(setting);
398 static GHashTable *
399 get_ui_settings_table(PurpleAccount *account, const char *ui)
401 GHashTable *table;
402 PurpleAccountPrivate *priv = purple_account_get_instance_private(account);
404 table = g_hash_table_lookup(priv->ui_settings, ui);
406 if (table == NULL) {
407 table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
408 delete_setting);
409 g_hash_table_insert(priv->ui_settings, g_strdup(ui), table);
412 return table;
415 static PurpleConnectionState
416 purple_account_get_state(PurpleAccount *account)
418 PurpleConnection *gc;
420 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), PURPLE_CONNECTION_DISCONNECTED);
422 gc = purple_account_get_connection(account);
423 if (!gc)
424 return PURPLE_CONNECTION_DISCONNECTED;
426 return purple_connection_get_state(gc);
429 static void
430 purple_account_get_password_got(PurpleAccount *account,
431 const gchar *password, GError *error, gpointer data)
433 PurpleCallbackBundle *cbb = data;
434 PurpleKeyringReadCallback cb;
435 PurpleAccountPrivate *priv = purple_account_get_instance_private(account);
437 purple_debug_info("account",
438 "Read password for account %s from async keyring.\n",
439 purple_account_get_username(account));
441 purple_str_wipe(priv->password);
442 priv->password = g_strdup(password);
444 cb = (PurpleKeyringReadCallback)cbb->cb;
445 if (cb != NULL)
446 cb(account, password, error, cbb->data);
448 g_free(cbb);
452 * This makes sure your permit list contains all buddies from your
453 * buddy list and ONLY buddies from your buddy list.
455 static void
456 add_all_buddies_to_permit_list(PurpleAccount *account, gboolean local)
458 GSList *list;
459 PurpleAccountPrivate *priv = purple_account_get_instance_private(account);
461 /* Remove anyone in the permit list who is not in the buddylist */
462 for (list = priv->permit; list != NULL; ) {
463 char *person = list->data;
464 list = list->next;
465 if (!purple_blist_find_buddy(account, person))
466 purple_account_privacy_permit_remove(account, person, local);
469 /* Now make sure everyone in the buddylist is in the permit list */
470 list = purple_blist_find_buddies(account, NULL);
471 while (list != NULL)
473 PurpleBuddy *buddy = list->data;
474 const gchar *name = purple_buddy_get_name(buddy);
476 if (!g_slist_find_custom(priv->permit, name, (GCompareFunc)g_utf8_collate))
477 purple_account_privacy_permit_add(account, name, local);
478 list = g_slist_delete_link(list, list);
482 void
483 _purple_account_set_current_error(PurpleAccount *account,
484 PurpleConnectionErrorInfo *new_err)
486 PurpleConnectionErrorInfo *old_err;
487 PurpleAccountPrivate *priv;
489 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
490 priv = purple_account_get_instance_private(account);
492 old_err = priv->current_error;
494 if(new_err == old_err)
495 return;
497 priv->current_error = new_err;
499 purple_signal_emit(purple_accounts_get_handle(),
500 "account-error-changed",
501 account, old_err, new_err);
502 purple_accounts_schedule_save();
504 if(old_err)
505 g_free(old_err->description);
507 g_free(old_err);
510 /******************************************************************************
511 * XmlNode Helpers
512 *****************************************************************************/
513 static PurpleXmlNode *
514 status_attribute_to_xmlnode(PurpleStatus *status, PurpleStatusType *type,
515 PurpleStatusAttribute *attr)
517 PurpleXmlNode *node;
518 const char *id;
519 char *value = NULL;
520 PurpleStatusAttribute *default_attr;
521 GValue *default_value;
522 GType attr_type;
523 GValue *attr_value;
525 id = purple_status_attribute_get_id(attr);
526 g_return_val_if_fail(id, NULL);
528 attr_value = purple_status_get_attr_value(status, id);
529 g_return_val_if_fail(attr_value, NULL);
530 attr_type = G_VALUE_TYPE(attr_value);
533 * If attr_value is a different type than it should be
534 * then don't write it to the file.
536 default_attr = purple_status_type_get_attr(type, id);
537 default_value = purple_status_attribute_get_value(default_attr);
538 if (attr_type != G_VALUE_TYPE(default_value))
539 return NULL;
542 * If attr_value is the same as the default for this status
543 * then there is no need to write it to the file.
545 if (attr_type == G_TYPE_STRING)
547 const char *string_value = g_value_get_string(attr_value);
548 const char *default_string_value = g_value_get_string(default_value);
549 if (purple_strequal(string_value, default_string_value))
550 return NULL;
551 value = g_value_dup_string(attr_value);
553 else if (attr_type == G_TYPE_INT)
555 int int_value = g_value_get_int(attr_value);
556 if (int_value == g_value_get_int(default_value))
557 return NULL;
558 value = g_strdup_printf("%d", int_value);
560 else if (attr_type == G_TYPE_BOOLEAN)
562 gboolean boolean_value = g_value_get_boolean(attr_value);
563 if (boolean_value == g_value_get_boolean(default_value))
564 return NULL;
565 value = g_strdup(boolean_value ?
566 "true" : "false");
568 else
570 return NULL;
573 g_return_val_if_fail(value, NULL);
575 node = purple_xmlnode_new("attribute");
577 purple_xmlnode_set_attrib(node, "id", id);
578 purple_xmlnode_set_attrib(node, "value", value);
580 g_free(value);
582 return node;
585 static PurpleXmlNode *
586 status_attrs_to_xmlnode(PurpleStatus *status)
588 PurpleStatusType *type = purple_status_get_status_type(status);
589 PurpleXmlNode *node, *child;
590 GList *attrs, *attr;
592 node = purple_xmlnode_new("attributes");
594 attrs = purple_status_type_get_attrs(type);
595 for (attr = attrs; attr != NULL; attr = attr->next)
597 child = status_attribute_to_xmlnode(status, type, (PurpleStatusAttribute *)attr->data);
598 if (child)
599 purple_xmlnode_insert_child(node, child);
602 return node;
605 static PurpleXmlNode *
606 status_to_xmlnode(PurpleStatus *status)
608 PurpleXmlNode *node, *child;
610 node = purple_xmlnode_new("status");
611 purple_xmlnode_set_attrib(node, "type", purple_status_get_id(status));
612 if (purple_status_get_name(status) != NULL)
613 purple_xmlnode_set_attrib(node, "name", purple_status_get_name(status));
614 purple_xmlnode_set_attrib(node, "active", purple_status_is_active(status) ? "true" : "false");
616 child = status_attrs_to_xmlnode(status);
617 purple_xmlnode_insert_child(node, child);
619 return node;
622 static PurpleXmlNode *
623 statuses_to_xmlnode(PurplePresence *presence)
625 PurpleXmlNode *node, *child;
626 GList *statuses;
627 PurpleStatus *status;
629 node = purple_xmlnode_new("statuses");
631 statuses = purple_presence_get_statuses(presence);
632 for (; statuses != NULL; statuses = statuses->next)
634 status = statuses->data;
635 if (purple_status_type_is_saveable(purple_status_get_status_type(status)))
637 child = status_to_xmlnode(status);
638 purple_xmlnode_insert_child(node, child);
642 return node;
645 static PurpleXmlNode *
646 proxy_settings_to_xmlnode(const PurpleProxyInfo *proxy_info)
648 PurpleXmlNode *node, *child;
649 PurpleProxyType proxy_type;
650 const char *value;
651 int int_value;
652 char buf[21];
654 proxy_type = purple_proxy_info_get_proxy_type(proxy_info);
656 node = purple_xmlnode_new("proxy");
658 child = purple_xmlnode_new_child(node, "type");
659 purple_xmlnode_insert_data(child,
660 (proxy_type == PURPLE_PROXY_USE_GLOBAL ? "global" :
661 proxy_type == PURPLE_PROXY_NONE ? "none" :
662 proxy_type == PURPLE_PROXY_HTTP ? "http" :
663 proxy_type == PURPLE_PROXY_SOCKS4 ? "socks4" :
664 proxy_type == PURPLE_PROXY_SOCKS5 ? "socks5" :
665 proxy_type == PURPLE_PROXY_TOR ? "tor" :
666 proxy_type == PURPLE_PROXY_USE_ENVVAR ? "envvar" : "unknown"), -1);
668 if ((value = purple_proxy_info_get_host(proxy_info)) != NULL)
670 child = purple_xmlnode_new_child(node, "host");
671 purple_xmlnode_insert_data(child, value, -1);
674 if ((int_value = purple_proxy_info_get_port(proxy_info)) != 0)
676 g_snprintf(buf, sizeof(buf), "%d", int_value);
677 child = purple_xmlnode_new_child(node, "port");
678 purple_xmlnode_insert_data(child, buf, -1);
681 if ((value = purple_proxy_info_get_username(proxy_info)) != NULL)
683 child = purple_xmlnode_new_child(node, "username");
684 purple_xmlnode_insert_data(child, value, -1);
687 if ((value = purple_proxy_info_get_password(proxy_info)) != NULL)
689 child = purple_xmlnode_new_child(node, "password");
690 purple_xmlnode_insert_data(child, value, -1);
693 return node;
696 static PurpleXmlNode *
697 current_error_to_xmlnode(PurpleConnectionErrorInfo *err)
699 PurpleXmlNode *node, *child;
700 char type_str[3];
702 node = purple_xmlnode_new("current_error");
704 if(err == NULL)
705 return node;
707 /* It doesn't make sense to have transient errors persist across a
708 * restart.
710 if(!purple_connection_error_is_fatal (err->type))
711 return node;
713 child = purple_xmlnode_new_child(node, "type");
714 g_snprintf(type_str, sizeof(type_str), "%u", err->type);
715 purple_xmlnode_insert_data(child, type_str, -1);
717 child = purple_xmlnode_new_child(node, "description");
718 if(err->description) {
719 char *utf8ized = purple_utf8_try_convert(err->description);
720 if(utf8ized == NULL)
721 utf8ized = purple_utf8_salvage(err->description);
722 purple_xmlnode_insert_data(child, utf8ized, -1);
723 g_free(utf8ized);
726 return node;
729 static void
730 setting_to_xmlnode(gpointer key, gpointer value, gpointer user_data)
732 const char *name;
733 PurpleAccountSetting *setting;
734 PurpleXmlNode *node, *child;
735 char buf[21];
737 name = (const char *)key;
738 setting = (PurpleAccountSetting *)value;
739 node = (PurpleXmlNode *)user_data;
741 child = purple_xmlnode_new_child(node, "setting");
742 purple_xmlnode_set_attrib(child, "name", name);
744 if (G_VALUE_HOLDS_INT(&setting->value)) {
745 purple_xmlnode_set_attrib(child, "type", "int");
746 g_snprintf(buf, sizeof(buf), "%d", g_value_get_int(&setting->value));
747 purple_xmlnode_insert_data(child, buf, -1);
749 else if (G_VALUE_HOLDS_STRING(&setting->value) && g_value_get_string(&setting->value) != NULL) {
750 purple_xmlnode_set_attrib(child, "type", "string");
751 purple_xmlnode_insert_data(child, g_value_get_string(&setting->value), -1);
753 else if (G_VALUE_HOLDS_BOOLEAN(&setting->value)) {
754 purple_xmlnode_set_attrib(child, "type", "bool");
755 g_snprintf(buf, sizeof(buf), "%d", g_value_get_boolean(&setting->value));
756 purple_xmlnode_insert_data(child, buf, -1);
760 static void
761 ui_setting_to_xmlnode(gpointer key, gpointer value, gpointer user_data)
763 const char *ui;
764 GHashTable *table;
765 PurpleXmlNode *node, *child;
767 ui = (const char *)key;
768 table = (GHashTable *)value;
769 node = (PurpleXmlNode *)user_data;
771 if (g_hash_table_size(table) > 0)
773 child = purple_xmlnode_new_child(node, "settings");
774 purple_xmlnode_set_attrib(child, "ui", ui);
775 g_hash_table_foreach(table, setting_to_xmlnode, child);
779 PurpleXmlNode *
780 _purple_account_to_xmlnode(PurpleAccount *account)
782 PurpleXmlNode *node, *child;
783 const char *tmp;
784 PurplePresence *presence;
785 const PurpleProxyInfo *proxy_info;
786 PurpleAccountPrivate *priv = purple_account_get_instance_private(account);
788 node = purple_xmlnode_new("account");
790 child = purple_xmlnode_new_child(node, "protocol");
791 purple_xmlnode_insert_data(child, purple_account_get_protocol_id(account), -1);
793 child = purple_xmlnode_new_child(node, "name");
794 purple_xmlnode_insert_data(child, purple_account_get_username(account), -1);
796 if (purple_account_get_remember_password(account))
798 const char *keyring_id = NULL;
799 const char *mode = NULL;
800 char *data = NULL;
801 GError *error = NULL;
802 GDestroyNotify destroy = NULL;
803 gboolean exported = purple_keyring_export_password(account,
804 &keyring_id, &mode, &data, &error, &destroy);
806 if (error != NULL) {
807 purple_debug_error("account",
808 "Failed to export password for account %s: %s.\n",
809 purple_account_get_username(account),
810 error->message);
811 } else if (exported) {
812 child = purple_xmlnode_new_child(node, "password");
813 if (keyring_id != NULL)
814 purple_xmlnode_set_attrib(child, "keyring_id", keyring_id);
815 if (mode != NULL)
816 purple_xmlnode_set_attrib(child, "mode", mode);
817 if (data != NULL)
818 purple_xmlnode_insert_data(child, data, -1);
820 if (destroy != NULL)
821 destroy(data);
825 if ((tmp = purple_account_get_private_alias(account)) != NULL)
827 child = purple_xmlnode_new_child(node, "alias");
828 purple_xmlnode_insert_data(child, tmp, -1);
831 if ((presence = purple_account_get_presence(account)) != NULL)
833 child = statuses_to_xmlnode(presence);
834 purple_xmlnode_insert_child(node, child);
837 if ((tmp = purple_account_get_user_info(account)) != NULL)
839 /* TODO: Do we need to call purple_str_strip_char(tmp, '\r') here? */
840 child = purple_xmlnode_new_child(node, "user-info");
841 purple_xmlnode_insert_data(child, tmp, -1);
844 if (g_hash_table_size(priv->settings) > 0)
846 child = purple_xmlnode_new_child(node, "settings");
847 g_hash_table_foreach(priv->settings, setting_to_xmlnode, child);
850 if (g_hash_table_size(priv->ui_settings) > 0)
852 g_hash_table_foreach(priv->ui_settings, ui_setting_to_xmlnode, node);
855 if ((proxy_info = purple_account_get_proxy_info(account)) != NULL)
857 child = proxy_settings_to_xmlnode(proxy_info);
858 purple_xmlnode_insert_child(node, child);
861 child = current_error_to_xmlnode(priv->current_error);
862 purple_xmlnode_insert_child(node, child);
864 return node;
867 /******************************************************************************
868 * GObject Implementation
869 *****************************************************************************/
870 static void
871 purple_account_set_property(GObject *obj, guint param_id, const GValue *value,
872 GParamSpec *pspec)
874 PurpleAccount *account = PURPLE_ACCOUNT(obj);
876 switch (param_id) {
877 case PROP_USERNAME:
878 purple_account_set_username(account, g_value_get_string(value));
879 break;
880 case PROP_PRIVATE_ALIAS:
881 purple_account_set_private_alias(account, g_value_get_string(value));
882 break;
883 case PROP_ENABLED:
884 purple_account_set_enabled(account, purple_core_get_ui(),
885 g_value_get_boolean(value));
886 break;
887 case PROP_CONNECTION:
888 purple_account_set_connection(account, g_value_get_object(value));
889 break;
890 case PROP_PROTOCOL_ID:
891 purple_account_set_protocol_id(account, g_value_get_string(value));
892 break;
893 case PROP_USER_INFO:
894 purple_account_set_user_info(account, g_value_get_string(value));
895 break;
896 case PROP_BUDDY_ICON_PATH:
897 purple_account_set_buddy_icon_path(account,
898 g_value_get_string(value));
899 break;
900 case PROP_REMEMBER_PASSWORD:
901 purple_account_set_remember_password(account,
902 g_value_get_boolean(value));
903 break;
904 case PROP_CHECK_MAIL:
905 purple_account_set_check_mail(account, g_value_get_boolean(value));
906 break;
907 default:
908 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
909 break;
913 static void
914 purple_account_get_property(GObject *obj, guint param_id, GValue *value,
915 GParamSpec *pspec)
917 PurpleAccount *account = PURPLE_ACCOUNT(obj);
919 switch (param_id) {
920 case PROP_USERNAME:
921 g_value_set_string(value, purple_account_get_username(account));
922 break;
923 case PROP_PRIVATE_ALIAS:
924 g_value_set_string(value, purple_account_get_private_alias(account));
925 break;
926 case PROP_ENABLED:
927 g_value_set_boolean(value, purple_account_get_enabled(account,
928 purple_core_get_ui()));
929 break;
930 case PROP_CONNECTION:
931 g_value_set_object(value, purple_account_get_connection(account));
932 break;
933 case PROP_PROTOCOL_ID:
934 g_value_set_string(value, purple_account_get_protocol_id(account));
935 break;
936 case PROP_USER_INFO:
937 g_value_set_string(value, purple_account_get_user_info(account));
938 break;
939 case PROP_BUDDY_ICON_PATH:
940 g_value_set_string(value,
941 purple_account_get_buddy_icon_path(account));
942 break;
943 case PROP_REMEMBER_PASSWORD:
944 g_value_set_boolean(value,
945 purple_account_get_remember_password(account));
946 break;
947 case PROP_CHECK_MAIL:
948 g_value_set_boolean(value, purple_account_get_check_mail(account));
949 break;
950 default:
951 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
952 break;
956 static void
957 purple_account_init(PurpleAccount *account)
959 PurpleAccountPrivate *priv = purple_account_get_instance_private(account);
961 priv->settings = g_hash_table_new_full(g_str_hash, g_str_equal,
962 g_free, delete_setting);
963 priv->ui_settings = g_hash_table_new_full(g_str_hash, g_str_equal,
964 g_free, (GDestroyNotify)g_hash_table_destroy);
965 priv->system_log = NULL;
967 priv->privacy_type = PURPLE_ACCOUNT_PRIVACY_ALLOW_ALL;
970 static void
971 purple_account_constructed(GObject *object)
973 PurpleAccount *account = PURPLE_ACCOUNT(object);
974 PurpleAccountPrivate *priv = purple_account_get_instance_private(account);
975 gchar *username, *protocol_id;
976 PurpleProtocol *protocol = NULL;
977 PurpleStatusType *status_type;
979 G_OBJECT_CLASS(purple_account_parent_class)->constructed(object);
981 g_object_get(object,
982 "username", &username,
983 "protocol-id", &protocol_id,
984 NULL);
986 purple_signal_emit(purple_accounts_get_handle(), "account-created",
987 account);
989 protocol = purple_protocols_find(protocol_id);
990 if (protocol == NULL) {
991 g_free(username);
992 g_free(protocol_id);
993 return;
996 purple_account_set_status_types(account,
997 purple_protocol_class_status_types(protocol, account));
999 priv->presence = PURPLE_PRESENCE(purple_account_presence_new(account));
1001 status_type = purple_account_get_status_type_with_primitive(account,
1002 PURPLE_STATUS_AVAILABLE);
1003 if (status_type != NULL)
1004 purple_presence_set_status_active(priv->presence,
1005 purple_status_type_get_id(status_type),
1006 TRUE);
1007 else
1008 purple_presence_set_status_active(priv->presence,
1009 "offline",
1010 TRUE);
1012 g_free(username);
1013 g_free(protocol_id);
1016 static void
1017 purple_account_dispose(GObject *object)
1019 PurpleAccount *account = PURPLE_ACCOUNT(object);
1020 PurpleAccountPrivate *priv = purple_account_get_instance_private(account);
1022 if (!purple_account_is_disconnected(account))
1023 purple_account_disconnect(account);
1025 if (priv->presence) {
1026 g_object_unref(priv->presence);
1027 priv->presence = NULL;
1030 G_OBJECT_CLASS(purple_account_parent_class)->dispose(object);
1033 static void
1034 purple_account_finalize(GObject *object)
1036 GList *l;
1037 PurpleAccount *account = PURPLE_ACCOUNT(object);
1038 PurpleAccountPrivate *priv = purple_account_get_instance_private(account);
1040 purple_debug_info("account", "Destroying account %p\n", account);
1041 purple_signal_emit(purple_accounts_get_handle(), "account-destroying",
1042 account);
1044 for (l = purple_conversations_get_all(); l != NULL; l = l->next)
1046 PurpleConversation *conv = (PurpleConversation *)l->data;
1048 if (purple_conversation_get_account(conv) == account)
1049 purple_conversation_set_account(conv, NULL);
1052 purple_account_set_status_types(account, NULL);
1054 if (priv->proxy_info)
1055 purple_proxy_info_destroy(priv->proxy_info);
1057 if(priv->system_log)
1058 purple_log_free(priv->system_log);
1060 if (priv->current_error) {
1061 g_free(priv->current_error->description);
1062 g_free(priv->current_error);
1065 g_free(priv->username);
1066 g_free(priv->alias);
1067 purple_str_wipe(priv->password);
1068 g_free(priv->user_info);
1069 g_free(priv->buddy_icon_path);
1070 g_free(priv->protocol_id);
1072 g_hash_table_destroy(priv->settings);
1073 g_hash_table_destroy(priv->ui_settings);
1075 while (priv->deny) {
1076 g_free(priv->deny->data);
1077 priv->deny = g_slist_delete_link(priv->deny, priv->deny);
1080 while (priv->permit) {
1081 g_free(priv->permit->data);
1082 priv->permit = g_slist_delete_link(priv->permit, priv->permit);
1085 G_OBJECT_CLASS(purple_account_parent_class)->finalize(object);
1088 static void
1089 purple_account_class_init(PurpleAccountClass *klass)
1091 GObjectClass *obj_class = G_OBJECT_CLASS(klass);
1093 obj_class->dispose = purple_account_dispose;
1094 obj_class->finalize = purple_account_finalize;
1095 obj_class->constructed = purple_account_constructed;
1097 /* Setup properties */
1098 obj_class->get_property = purple_account_get_property;
1099 obj_class->set_property = purple_account_set_property;
1101 properties[PROP_USERNAME] = g_param_spec_string("username", "Username",
1102 "The username for the account.", NULL,
1103 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
1105 properties[PROP_PRIVATE_ALIAS] = g_param_spec_string("private-alias",
1106 "Private Alias",
1107 "The private alias for the account.", NULL,
1108 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1110 properties[PROP_USER_INFO] = g_param_spec_string("user-info",
1111 "User information",
1112 "Detailed user information for the account.", NULL,
1113 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1115 properties[PROP_BUDDY_ICON_PATH] = g_param_spec_string("buddy-icon-path",
1116 "Buddy icon path",
1117 "Path to the buddyicon for the account.", NULL,
1118 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1120 properties[PROP_ENABLED] = g_param_spec_boolean("enabled", "Enabled",
1121 "Whether the account is enabled or not.", FALSE,
1122 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1124 properties[PROP_REMEMBER_PASSWORD] = g_param_spec_boolean(
1125 "remember-password", "Remember password",
1126 "Whether to remember and store the password for this account.",
1127 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1129 properties[PROP_CHECK_MAIL] = g_param_spec_boolean("check-mail",
1130 "Check mail",
1131 "Whether to check mails for this account.", FALSE,
1132 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1134 properties[PROP_CONNECTION] = g_param_spec_object("connection",
1135 "Connection",
1136 "The connection for the account.", PURPLE_TYPE_CONNECTION,
1137 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1139 properties[PROP_PROTOCOL_ID] = g_param_spec_string("protocol-id",
1140 "Protocol ID",
1141 "ID of the protocol that is responsible for the account.", NULL,
1142 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
1143 G_PARAM_STATIC_STRINGS);
1145 g_object_class_install_properties(obj_class, PROP_LAST, properties);
1148 /******************************************************************************
1149 * Public API
1150 *****************************************************************************/
1151 PurpleAccount *
1152 purple_account_new(const char *username, const char *protocol_id)
1154 PurpleAccount *account;
1156 g_return_val_if_fail(username != NULL, NULL);
1157 g_return_val_if_fail(protocol_id != NULL, NULL);
1159 account = purple_accounts_find(username, protocol_id);
1161 if (account != NULL)
1162 return account;
1164 account = g_object_new(PURPLE_TYPE_ACCOUNT,
1165 "username", username,
1166 "protocol-id", protocol_id,
1167 NULL);
1169 return account;
1172 void
1173 purple_account_connect(PurpleAccount *account)
1175 const char *username;
1176 PurpleProtocol *protocol;
1177 PurpleAccountPrivate *priv;
1179 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
1181 username = purple_account_get_username(account);
1183 if (!purple_account_get_enabled(account, purple_core_get_ui())) {
1184 purple_debug_info("account",
1185 "Account %s not enabled, not connecting.\n",
1186 username);
1187 return;
1190 protocol = purple_protocols_find(purple_account_get_protocol_id(account));
1191 if (protocol == NULL) {
1192 gchar *message;
1194 message = g_strdup_printf(_("Missing protocol for %s"), username);
1195 purple_notify_error(account, _("Connection Error"), message,
1196 NULL, purple_request_cpar_from_account(account));
1197 g_free(message);
1198 return;
1201 priv = purple_account_get_instance_private(account);
1203 purple_debug_info("account", "Connecting to account %s.\n", username);
1205 if (priv->password != NULL) {
1206 purple_account_connect_got_password_cb(account,
1207 priv->password, NULL, protocol);
1208 } else {
1209 purple_keyring_get_password(account,
1210 purple_account_connect_got_password_cb, protocol);
1214 void
1215 purple_account_set_register_callback(PurpleAccount *account, PurpleAccountRegistrationCb cb, void *user_data)
1217 PurpleAccountPrivate *priv;
1219 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
1221 priv = purple_account_get_instance_private(account);
1223 priv->registration_cb = cb;
1224 priv->registration_cb_user_data = user_data;
1227 void
1228 purple_account_register_completed(PurpleAccount *account, gboolean succeeded)
1230 struct register_completed_closure *closure;
1232 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
1234 closure = g_new0(struct register_completed_closure, 1);
1235 closure->account = g_object_ref(account);
1236 closure->succeeded = succeeded;
1238 g_timeout_add(0, purple_account_register_completed_cb, closure);
1241 void
1242 purple_account_unregister(PurpleAccount *account, PurpleAccountUnregistrationCb cb, void *user_data)
1244 PurpleCallbackBundle *cbb;
1246 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
1248 purple_debug_info("account", "Unregistering account %s\n",
1249 purple_account_get_username(account));
1251 cbb = g_new0(PurpleCallbackBundle, 1);
1252 cbb->cb = PURPLE_CALLBACK(cb);
1253 cbb->data = user_data;
1255 purple_keyring_get_password(account,
1256 purple_account_unregister_got_password_cb, cbb);
1259 void
1260 purple_account_disconnect(PurpleAccount *account)
1262 PurpleConnection *gc;
1263 PurpleAccountPrivate *priv;
1264 const char *username;
1266 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
1267 g_return_if_fail(!purple_account_is_disconnecting(account));
1268 g_return_if_fail(!purple_account_is_disconnected(account));
1270 priv = purple_account_get_instance_private(account);
1272 username = purple_account_get_username(account);
1273 purple_debug_info("account", "Disconnecting account %s (%p)\n",
1274 username ? username : "(null)", account);
1276 priv->disconnecting = TRUE;
1278 gc = purple_account_get_connection(account);
1279 g_object_unref(gc);
1280 purple_account_set_connection(account, NULL);
1282 priv->disconnecting = FALSE;
1285 gboolean
1286 purple_account_is_disconnecting(PurpleAccount *account)
1288 PurpleAccountPrivate *priv;
1290 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), TRUE);
1292 priv = purple_account_get_instance_private(account);
1293 return priv->disconnecting;
1296 void
1297 purple_account_notify_added(PurpleAccount *account, const char *remote_user,
1298 const char *id, const char *alias,
1299 const char *message)
1301 PurpleAccountUiOps *ui_ops;
1303 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
1304 g_return_if_fail(remote_user != NULL);
1306 ui_ops = purple_accounts_get_ui_ops();
1308 if (ui_ops != NULL && ui_ops->notify_added != NULL)
1309 ui_ops->notify_added(account, remote_user, id, alias, message);
1312 void
1313 purple_account_request_add(PurpleAccount *account, const char *remote_user,
1314 const char *id, const char *alias,
1315 const char *message)
1317 PurpleAccountUiOps *ui_ops;
1319 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
1320 g_return_if_fail(remote_user != NULL);
1322 ui_ops = purple_accounts_get_ui_ops();
1324 if (ui_ops != NULL && ui_ops->request_add != NULL)
1325 ui_ops->request_add(account, remote_user, id, alias, message);
1328 void *
1329 purple_account_request_authorization(PurpleAccount *account, const char *remote_user,
1330 const char *id, const char *alias, const char *message, gboolean on_list,
1331 PurpleAccountRequestAuthorizationCb auth_cb, PurpleAccountRequestAuthorizationCb deny_cb, void *user_data)
1333 PurpleAccountUiOps *ui_ops;
1334 PurpleAccountRequestInfo *info;
1335 int plugin_return;
1336 char *response = NULL;
1338 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
1339 g_return_val_if_fail(remote_user != NULL, NULL);
1341 ui_ops = purple_accounts_get_ui_ops();
1343 plugin_return = GPOINTER_TO_INT(
1344 purple_signal_emit_return_1(
1345 purple_accounts_get_handle(),
1346 "account-authorization-requested",
1347 account, remote_user, message, &response
1350 switch (plugin_return)
1352 case PURPLE_ACCOUNT_RESPONSE_IGNORE:
1353 g_free(response);
1354 return NULL;
1355 case PURPLE_ACCOUNT_RESPONSE_ACCEPT:
1356 if (auth_cb != NULL)
1357 auth_cb(response, user_data);
1358 g_free(response);
1359 return NULL;
1360 case PURPLE_ACCOUNT_RESPONSE_DENY:
1361 if (deny_cb != NULL)
1362 deny_cb(response, user_data);
1363 g_free(response);
1364 return NULL;
1367 g_free(response);
1369 if (ui_ops != NULL && ui_ops->request_authorize != NULL) {
1370 info = g_new0(PurpleAccountRequestInfo, 1);
1371 info->type = PURPLE_ACCOUNT_REQUEST_AUTHORIZATION;
1372 info->account = account;
1373 info->auth_cb = auth_cb;
1374 info->deny_cb = deny_cb;
1375 info->userdata = user_data;
1376 info->user = g_strdup(remote_user);
1377 info->ref = 2; /* We hold an extra ref to make sure info remains valid
1378 if any of the callbacks are called synchronously. We
1379 unref it after the function call */
1381 info->ui_handle = ui_ops->request_authorize(account, remote_user, id, alias, message,
1382 on_list, request_auth_cb, request_deny_cb, info);
1384 info = purple_account_request_info_unref(info);
1385 if (info) {
1386 handles = g_list_append(handles, info);
1387 return info->ui_handle;
1391 return NULL;
1394 void
1395 purple_account_request_close_with_account(PurpleAccount *account)
1397 GList *l, *l_next;
1399 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
1401 for (l = handles; l != NULL; l = l_next) {
1402 PurpleAccountRequestInfo *info = l->data;
1404 l_next = l->next;
1406 if (info->account == account) {
1407 handles = g_list_remove(handles, info);
1408 purple_account_request_close_info(info);
1413 void
1414 purple_account_request_close(void *ui_handle)
1416 GList *l, *l_next;
1418 g_return_if_fail(ui_handle != NULL);
1420 for (l = handles; l != NULL; l = l_next) {
1421 PurpleAccountRequestInfo *info = l->data;
1423 l_next = l->next;
1425 if (info->ui_handle == ui_handle) {
1426 handles = g_list_remove(handles, info);
1427 purple_account_request_close_info(info);
1432 void
1433 purple_account_request_password(PurpleAccount *account, GCallback ok_cb,
1434 GCallback cancel_cb, void *user_data)
1436 gchar *primary;
1437 const gchar *username;
1438 PurpleRequestFieldGroup *group;
1439 PurpleRequestField *field;
1440 PurpleRequestFields *fields;
1442 /* Close any previous password request windows */
1443 purple_request_close_with_handle(account);
1445 username = purple_account_get_username(account);
1446 primary = g_strdup_printf(_("Enter password for %s (%s)"), username,
1447 purple_account_get_protocol_name(account));
1449 fields = purple_request_fields_new();
1450 group = purple_request_field_group_new(NULL);
1451 purple_request_fields_add_group(fields, group);
1453 field = purple_request_field_string_new("password", _("Enter Password"), NULL, FALSE);
1454 purple_request_field_string_set_masked(field, TRUE);
1455 purple_request_field_set_required(field, TRUE);
1456 purple_request_field_group_add_field(group, field);
1458 field = purple_request_field_bool_new("remember", _("Save password"), FALSE);
1459 purple_request_field_group_add_field(group, field);
1461 purple_request_fields(account, NULL, primary, NULL, fields, _("OK"),
1462 ok_cb, _("Cancel"), cancel_cb,
1463 purple_request_cpar_from_account(account), user_data);
1464 g_free(primary);
1467 void
1468 purple_account_request_change_password(PurpleAccount *account)
1470 PurpleRequestFields *fields;
1471 PurpleRequestFieldGroup *group;
1472 PurpleRequestField *field;
1473 PurpleConnection *gc;
1474 PurpleProtocol *protocol = NULL;
1475 char primary[256];
1477 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
1478 g_return_if_fail(purple_account_is_connected(account));
1480 gc = purple_account_get_connection(account);
1481 if (gc != NULL)
1482 protocol = purple_connection_get_protocol(gc);
1484 fields = purple_request_fields_new();
1486 group = purple_request_field_group_new(NULL);
1487 purple_request_fields_add_group(fields, group);
1489 field = purple_request_field_string_new("password", _("Original password"),
1490 NULL, FALSE);
1491 purple_request_field_string_set_masked(field, TRUE);
1492 if (!protocol || !(purple_protocol_get_options(protocol) & OPT_PROTO_PASSWORD_OPTIONAL))
1493 purple_request_field_set_required(field, TRUE);
1494 purple_request_field_group_add_field(group, field);
1496 field = purple_request_field_string_new("new_password_1",
1497 _("New password"),
1498 NULL, FALSE);
1499 purple_request_field_string_set_masked(field, TRUE);
1500 if (!protocol || !(purple_protocol_get_options(protocol) & OPT_PROTO_PASSWORD_OPTIONAL))
1501 purple_request_field_set_required(field, TRUE);
1502 purple_request_field_group_add_field(group, field);
1504 field = purple_request_field_string_new("new_password_2",
1505 _("New password (again)"),
1506 NULL, FALSE);
1507 purple_request_field_string_set_masked(field, TRUE);
1508 if (!protocol || !(purple_protocol_get_options(protocol) & OPT_PROTO_PASSWORD_OPTIONAL))
1509 purple_request_field_set_required(field, TRUE);
1510 purple_request_field_group_add_field(group, field);
1512 g_snprintf(primary, sizeof(primary), _("Change password for %s"),
1513 purple_account_get_username(account));
1515 /* I'm sticking this somewhere in the code: bologna */
1517 purple_request_fields(purple_account_get_connection(account), NULL,
1518 primary, _("Please enter your current password and your new "
1519 "password."), fields, _("OK"), G_CALLBACK(change_password_cb),
1520 _("Cancel"), NULL, purple_request_cpar_from_account(account),
1521 account);
1524 void
1525 purple_account_request_change_user_info(PurpleAccount *account)
1527 PurpleConnection *gc;
1528 char primary[256];
1530 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
1531 g_return_if_fail(purple_account_is_connected(account));
1533 gc = purple_account_get_connection(account);
1535 g_snprintf(primary, sizeof(primary),
1536 _("Change user information for %s"),
1537 purple_account_get_username(account));
1539 purple_request_input(gc, _("Set User Info"), primary, NULL,
1540 purple_account_get_user_info(account),
1541 TRUE, FALSE, ((gc != NULL) &&
1542 (purple_connection_get_flags(gc) & PURPLE_CONNECTION_FLAG_HTML) ? "html" : NULL),
1543 _("Save"), G_CALLBACK(set_user_info_cb),
1544 _("Cancel"), NULL,
1545 purple_request_cpar_from_account(account),
1546 account);
1549 void
1550 purple_account_set_username(PurpleAccount *account, const char *username)
1552 PurpleAccountPrivate *priv;
1554 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
1556 priv = purple_account_get_instance_private(account);
1558 g_free(priv->username);
1559 priv->username = g_strdup(username);
1561 g_object_notify_by_pspec(G_OBJECT(account), properties[PROP_USERNAME]);
1563 purple_accounts_schedule_save();
1565 /* if the name changes, we should re-write the buddy list
1566 * to disk with the new name */
1567 purple_blist_save_account(purple_blist_get_default(), account);
1570 void
1571 purple_account_set_password(PurpleAccount *account, const gchar *password,
1572 PurpleKeyringSaveCallback cb, gpointer data)
1574 PurpleAccountPrivate *priv;
1576 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
1578 priv = purple_account_get_instance_private(account);
1580 purple_str_wipe(priv->password);
1581 priv->password = g_strdup(password);
1583 purple_accounts_schedule_save();
1585 if (!purple_account_get_remember_password(account)) {
1586 purple_debug_info("account",
1587 "Password for %s set, not sent to keyring.\n",
1588 purple_account_get_username(account));
1590 if (cb != NULL)
1591 cb(account, NULL, data);
1592 } else {
1593 purple_keyring_set_password(account, password, cb, data);
1597 void
1598 purple_account_set_private_alias(PurpleAccount *account, const char *alias)
1600 PurpleAccountPrivate *priv;
1602 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
1604 priv = purple_account_get_instance_private(account);
1607 * Do nothing if alias and priv->alias are both NULL. Or if
1608 * they're the exact same string.
1610 if (alias == priv->alias)
1611 return;
1613 if ((!alias && priv->alias) || (alias && !priv->alias) ||
1614 g_utf8_collate(priv->alias, alias))
1616 char *old = priv->alias;
1618 priv->alias = g_strdup(alias);
1619 g_object_notify_by_pspec(G_OBJECT(account),
1620 properties[PROP_PRIVATE_ALIAS]);
1621 purple_signal_emit(purple_accounts_get_handle(), "account-alias-changed",
1622 account, old);
1623 g_free(old);
1625 purple_accounts_schedule_save();
1629 void
1630 purple_account_set_user_info(PurpleAccount *account, const char *user_info)
1632 PurpleAccountPrivate *priv;
1634 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
1636 priv = purple_account_get_instance_private(account);
1638 g_free(priv->user_info);
1639 priv->user_info = g_strdup(user_info);
1641 g_object_notify_by_pspec(G_OBJECT(account), properties[PROP_USER_INFO]);
1643 purple_accounts_schedule_save();
1646 void purple_account_set_buddy_icon_path(PurpleAccount *account, const char *path)
1648 PurpleAccountPrivate *priv;
1650 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
1652 priv = purple_account_get_instance_private(account);
1654 g_free(priv->buddy_icon_path);
1655 priv->buddy_icon_path = g_strdup(path);
1657 g_object_notify_by_pspec(G_OBJECT(account),
1658 properties[PROP_BUDDY_ICON_PATH]);
1660 purple_accounts_schedule_save();
1663 void
1664 purple_account_set_protocol_id(PurpleAccount *account, const char *protocol_id)
1666 PurpleAccountPrivate *priv;
1668 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
1669 g_return_if_fail(protocol_id != NULL);
1671 priv = purple_account_get_instance_private(account);
1673 g_free(priv->protocol_id);
1674 priv->protocol_id = g_strdup(protocol_id);
1676 g_object_notify_by_pspec(G_OBJECT(account), properties[PROP_PROTOCOL_ID]);
1678 purple_accounts_schedule_save();
1681 void
1682 purple_account_set_connection(PurpleAccount *account, PurpleConnection *gc)
1684 PurpleAccountPrivate *priv;
1686 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
1688 priv = purple_account_get_instance_private(account);
1689 priv->gc = gc;
1691 g_object_notify_by_pspec(G_OBJECT(account), properties[PROP_CONNECTION]);
1694 void
1695 purple_account_set_remember_password(PurpleAccount *account, gboolean value)
1697 PurpleAccountPrivate *priv;
1699 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
1701 priv = purple_account_get_instance_private(account);
1702 priv->remember_pass = value;
1704 g_object_notify_by_pspec(G_OBJECT(account),
1705 properties[PROP_REMEMBER_PASSWORD]);
1707 purple_accounts_schedule_save();
1710 void
1711 purple_account_set_check_mail(PurpleAccount *account, gboolean value)
1713 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
1715 purple_account_set_bool(account, "check-mail", value);
1717 g_object_notify_by_pspec(G_OBJECT(account), properties[PROP_CHECK_MAIL]);
1720 void
1721 purple_account_set_enabled(PurpleAccount *account, const char *ui,
1722 gboolean value)
1724 PurpleConnection *gc;
1725 PurpleAccountPrivate *priv;
1726 gboolean was_enabled = FALSE;
1728 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
1729 g_return_if_fail(ui != NULL);
1731 was_enabled = purple_account_get_enabled(account, ui);
1733 purple_account_set_ui_bool(account, ui, "auto-login", value);
1734 gc = purple_account_get_connection(account);
1736 if(was_enabled && !value)
1737 purple_signal_emit(purple_accounts_get_handle(), "account-disabled", account);
1738 else if(!was_enabled && value)
1739 purple_signal_emit(purple_accounts_get_handle(), "account-enabled", account);
1741 g_object_notify_by_pspec(G_OBJECT(account), properties[PROP_ENABLED]);
1743 if ((gc != NULL) && (_purple_connection_wants_to_die(gc)))
1744 return;
1746 priv = purple_account_get_instance_private(account);
1748 if (value && purple_presence_is_online(priv->presence))
1749 purple_account_connect(account);
1750 else if (!value && !purple_account_is_disconnected(account))
1751 purple_account_disconnect(account);
1754 void
1755 purple_account_set_proxy_info(PurpleAccount *account, PurpleProxyInfo *info)
1757 PurpleAccountPrivate *priv;
1759 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
1761 priv = purple_account_get_instance_private(account);
1763 if (priv->proxy_info != NULL)
1764 purple_proxy_info_destroy(priv->proxy_info);
1766 priv->proxy_info = info;
1768 purple_accounts_schedule_save();
1771 void
1772 purple_account_set_privacy_type(PurpleAccount *account, PurpleAccountPrivacyType privacy_type)
1774 PurpleAccountPrivate *priv;
1776 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
1778 priv = purple_account_get_instance_private(account);
1779 priv->privacy_type = privacy_type;
1782 void
1783 purple_account_set_status_types(PurpleAccount *account, GList *status_types)
1785 PurpleAccountPrivate *priv;
1787 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
1789 priv = purple_account_get_instance_private(account);
1791 /* Out with the old... */
1792 if (priv->status_types != NULL)
1794 g_list_foreach(priv->status_types, (GFunc)purple_status_type_destroy, NULL);
1795 g_list_free(priv->status_types);
1798 /* In with the new... */
1799 priv->status_types = status_types;
1802 void
1803 purple_account_set_status(PurpleAccount *account, const char *status_id,
1804 gboolean active, ...)
1806 GList *attrs = NULL;
1807 const gchar *id;
1808 gpointer data;
1809 va_list args;
1811 va_start(args, active);
1812 while ((id = va_arg(args, const char *)) != NULL)
1814 attrs = g_list_append(attrs, (char *)id);
1815 data = va_arg(args, void *);
1816 attrs = g_list_append(attrs, data);
1818 purple_account_set_status_list(account, status_id, active, attrs);
1819 g_list_free(attrs);
1820 va_end(args);
1823 void
1824 purple_account_set_status_list(PurpleAccount *account, const char *status_id,
1825 gboolean active, GList *attrs)
1827 PurpleStatus *status;
1829 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
1830 g_return_if_fail(status_id != NULL);
1832 status = purple_account_get_status(account, status_id);
1833 if (status == NULL)
1835 purple_debug_error("account",
1836 "Invalid status ID '%s' for account %s (%s)\n",
1837 status_id, purple_account_get_username(account),
1838 purple_account_get_protocol_id(account));
1839 return;
1842 if (active || purple_status_is_independent(status))
1843 purple_status_set_active_with_attrs_list(status, active, attrs);
1846 * Our current statuses are saved to accounts.xml (so that when we
1847 * reconnect, we go back to the previous status).
1849 purple_accounts_schedule_save();
1852 void
1853 purple_account_set_public_alias(PurpleAccount *account,
1854 const char *alias, PurpleSetPublicAliasSuccessCallback success_cb,
1855 PurpleSetPublicAliasFailureCallback failure_cb)
1857 PurpleConnection *gc;
1858 PurpleProtocol *protocol = NULL;
1860 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
1861 g_return_if_fail(purple_account_is_connected(account));
1863 gc = purple_account_get_connection(account);
1864 protocol = purple_connection_get_protocol(gc);
1866 if (PURPLE_PROTOCOL_IMPLEMENTS(protocol, SERVER, set_public_alias))
1867 purple_protocol_server_iface_set_public_alias(protocol, gc, alias, success_cb, failure_cb);
1868 else if (failure_cb) {
1869 struct public_alias_closure *closure =
1870 g_new0(struct public_alias_closure, 1);
1871 closure->account = g_object_ref(account);
1872 closure->failure_cb = failure_cb;
1873 g_timeout_add(0, set_public_alias_unsupported, closure);
1877 void
1878 purple_account_get_public_alias(PurpleAccount *account,
1879 PurpleGetPublicAliasSuccessCallback success_cb,
1880 PurpleGetPublicAliasFailureCallback failure_cb)
1882 PurpleConnection *gc;
1883 PurpleProtocol *protocol = NULL;
1885 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
1886 g_return_if_fail(purple_account_is_connected(account));
1888 gc = purple_account_get_connection(account);
1889 protocol = purple_connection_get_protocol(gc);
1891 if (PURPLE_PROTOCOL_IMPLEMENTS(protocol, SERVER, get_public_alias))
1892 purple_protocol_server_iface_get_public_alias(protocol, gc, success_cb, failure_cb);
1893 else if (failure_cb) {
1894 struct public_alias_closure *closure =
1895 g_new0(struct public_alias_closure, 1);
1896 closure->account = g_object_ref(account);
1897 closure->failure_cb = failure_cb;
1898 g_timeout_add(0, get_public_alias_unsupported, closure);
1902 gboolean
1903 purple_account_get_silence_suppression(PurpleAccount *account)
1905 return purple_account_get_bool(account, "silence-suppression", FALSE);
1908 void
1909 purple_account_set_silence_suppression(PurpleAccount *account, gboolean value)
1911 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
1913 purple_account_set_bool(account, "silence-suppression", value);
1916 void
1917 purple_account_clear_settings(PurpleAccount *account)
1919 PurpleAccountPrivate *priv;
1921 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
1923 priv = purple_account_get_instance_private(account);
1924 g_hash_table_destroy(priv->settings);
1926 priv->settings = g_hash_table_new_full(g_str_hash, g_str_equal,
1927 g_free, delete_setting);
1930 void
1931 purple_account_remove_setting(PurpleAccount *account, const char *setting)
1933 PurpleAccountPrivate *priv;
1935 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
1936 g_return_if_fail(setting != NULL);
1938 priv = purple_account_get_instance_private(account);
1940 g_hash_table_remove(priv->settings, setting);
1943 void
1944 purple_account_set_int(PurpleAccount *account, const char *name, int value)
1946 PurpleAccountSetting *setting;
1947 PurpleAccountPrivate *priv;
1949 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
1950 g_return_if_fail(name != NULL);
1952 priv = purple_account_get_instance_private(account);
1954 setting = g_new0(PurpleAccountSetting, 1);
1956 g_value_init(&setting->value, G_TYPE_INT);
1957 g_value_set_int(&setting->value, value);
1959 g_hash_table_insert(priv->settings, g_strdup(name), setting);
1961 purple_accounts_schedule_save();
1964 void
1965 purple_account_set_string(PurpleAccount *account, const char *name,
1966 const char *value)
1968 PurpleAccountSetting *setting;
1969 PurpleAccountPrivate *priv;
1971 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
1972 g_return_if_fail(name != NULL);
1974 priv = purple_account_get_instance_private(account);
1976 setting = g_new0(PurpleAccountSetting, 1);
1978 g_value_init(&setting->value, G_TYPE_STRING);
1979 g_value_set_string(&setting->value, value);
1981 g_hash_table_insert(priv->settings, g_strdup(name), setting);
1983 purple_accounts_schedule_save();
1986 void
1987 purple_account_set_bool(PurpleAccount *account, const char *name, gboolean value)
1989 PurpleAccountSetting *setting;
1990 PurpleAccountPrivate *priv;
1992 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
1993 g_return_if_fail(name != NULL);
1995 priv = purple_account_get_instance_private(account);
1997 setting = g_new0(PurpleAccountSetting, 1);
1999 g_value_init(&setting->value, G_TYPE_BOOLEAN);
2000 g_value_set_boolean(&setting->value, value);
2002 g_hash_table_insert(priv->settings, g_strdup(name), setting);
2004 purple_accounts_schedule_save();
2007 void
2008 purple_account_set_ui_int(PurpleAccount *account, const char *ui,
2009 const char *name, int value)
2011 PurpleAccountSetting *setting;
2012 GHashTable *table;
2014 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
2015 g_return_if_fail(ui != NULL);
2016 g_return_if_fail(name != NULL);
2018 setting = g_new0(PurpleAccountSetting, 1);
2020 setting->ui = g_strdup(ui);
2021 g_value_init(&setting->value, G_TYPE_INT);
2022 g_value_set_int(&setting->value, value);
2024 table = get_ui_settings_table(account, ui);
2026 g_hash_table_insert(table, g_strdup(name), setting);
2028 purple_accounts_schedule_save();
2031 void
2032 purple_account_set_ui_string(PurpleAccount *account, const char *ui,
2033 const char *name, const char *value)
2035 PurpleAccountSetting *setting;
2036 GHashTable *table;
2038 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
2039 g_return_if_fail(ui != NULL);
2040 g_return_if_fail(name != NULL);
2042 setting = g_new0(PurpleAccountSetting, 1);
2044 setting->ui = g_strdup(ui);
2045 g_value_init(&setting->value, G_TYPE_STRING);
2046 g_value_set_string(&setting->value, value);
2048 table = get_ui_settings_table(account, ui);
2050 g_hash_table_insert(table, g_strdup(name), setting);
2052 purple_accounts_schedule_save();
2055 void
2056 purple_account_set_ui_bool(PurpleAccount *account, const char *ui,
2057 const char *name, gboolean value)
2059 PurpleAccountSetting *setting;
2060 GHashTable *table;
2062 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
2063 g_return_if_fail(ui != NULL);
2064 g_return_if_fail(name != NULL);
2066 setting = g_new0(PurpleAccountSetting, 1);
2068 setting->ui = g_strdup(ui);
2069 g_value_init(&setting->value, G_TYPE_BOOLEAN);
2070 g_value_set_boolean(&setting->value, value);
2072 table = get_ui_settings_table(account, ui);
2074 g_hash_table_insert(table, g_strdup(name), setting);
2076 purple_accounts_schedule_save();
2079 gboolean
2080 purple_account_is_connected(PurpleAccount *account)
2082 return (purple_account_get_state(account) == PURPLE_CONNECTION_CONNECTED);
2085 gboolean
2086 purple_account_is_connecting(PurpleAccount *account)
2088 return (purple_account_get_state(account) == PURPLE_CONNECTION_CONNECTING);
2091 gboolean
2092 purple_account_is_disconnected(PurpleAccount *account)
2094 return (purple_account_get_state(account) == PURPLE_CONNECTION_DISCONNECTED);
2097 const char *
2098 purple_account_get_username(PurpleAccount *account)
2100 PurpleAccountPrivate *priv;
2102 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
2104 priv = purple_account_get_instance_private(account);
2105 return priv->username;
2108 void
2109 purple_account_get_password(PurpleAccount *account,
2110 PurpleKeyringReadCallback cb, gpointer data)
2112 PurpleAccountPrivate *priv;
2114 if (account == NULL) {
2115 cb(NULL, NULL, NULL, data);
2116 return;
2119 priv = purple_account_get_instance_private(account);
2121 if (priv->password != NULL) {
2122 purple_debug_info("account",
2123 "Reading password for account %s from cache.\n",
2124 purple_account_get_username(account));
2125 cb(account, priv->password, NULL, data);
2126 } else {
2127 PurpleCallbackBundle *cbb = g_new0(PurpleCallbackBundle, 1);
2128 cbb->cb = PURPLE_CALLBACK(cb);
2129 cbb->data = data;
2131 purple_debug_info("account",
2132 "Reading password for account %s from async keyring.\n",
2133 purple_account_get_username(account));
2134 purple_keyring_get_password(account,
2135 purple_account_get_password_got, cbb);
2139 const char *
2140 purple_account_get_private_alias(PurpleAccount *account)
2142 PurpleAccountPrivate *priv;
2144 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
2146 priv = purple_account_get_instance_private(account);
2147 return priv->alias;
2150 const char *
2151 purple_account_get_user_info(PurpleAccount *account)
2153 PurpleAccountPrivate *priv;
2155 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
2157 priv = purple_account_get_instance_private(account);
2158 return priv->user_info;
2161 const char *
2162 purple_account_get_buddy_icon_path(PurpleAccount *account)
2164 PurpleAccountPrivate *priv;
2166 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
2168 priv = purple_account_get_instance_private(account);
2169 return priv->buddy_icon_path;
2172 const char *
2173 purple_account_get_protocol_id(PurpleAccount *account)
2175 PurpleAccountPrivate *priv;
2177 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
2179 priv = purple_account_get_instance_private(account);
2180 return priv->protocol_id;
2183 const char *
2184 purple_account_get_protocol_name(PurpleAccount *account)
2186 PurpleProtocol *p;
2188 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
2190 p = purple_protocols_find(purple_account_get_protocol_id(account));
2192 return (p && purple_protocol_get_name(p) ?
2193 _(purple_protocol_get_name(p)) : _("Unknown"));
2196 PurpleConnection *
2197 purple_account_get_connection(PurpleAccount *account)
2199 PurpleAccountPrivate *priv;
2201 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
2203 priv = purple_account_get_instance_private(account);
2204 return priv->gc;
2207 const gchar *
2208 purple_account_get_name_for_display(PurpleAccount *account)
2210 PurpleBuddy *self = NULL;
2211 PurpleConnection *gc = NULL;
2212 const gchar *name = NULL, *username = NULL, *displayname = NULL;
2214 name = purple_account_get_private_alias(account);
2216 if (name) {
2217 return name;
2220 username = purple_account_get_username(account);
2221 self = purple_blist_find_buddy((PurpleAccount *)account, username);
2223 if (self) {
2224 const gchar *calias= purple_buddy_get_contact_alias(self);
2226 /* We don't want to return the buddy name if the buddy/contact
2227 * doesn't have an alias set. */
2228 if (!purple_strequal(username, calias)) {
2229 return calias;
2233 gc = purple_account_get_connection(account);
2234 displayname = purple_connection_get_display_name(gc);
2236 if (displayname) {
2237 return displayname;
2240 return username;
2243 gboolean
2244 purple_account_get_remember_password(PurpleAccount *account)
2246 PurpleAccountPrivate *priv;
2248 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), FALSE);
2250 priv = purple_account_get_instance_private(account);
2251 return priv->remember_pass;
2254 gboolean
2255 purple_account_get_check_mail(PurpleAccount *account)
2257 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), FALSE);
2259 return purple_account_get_bool(account, "check-mail", FALSE);
2262 gboolean
2263 purple_account_get_enabled(PurpleAccount *account, const char *ui)
2265 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), FALSE);
2266 g_return_val_if_fail(ui != NULL, FALSE);
2268 return purple_account_get_ui_bool(account, ui, "auto-login", FALSE);
2271 PurpleProxyInfo *
2272 purple_account_get_proxy_info(PurpleAccount *account)
2274 PurpleAccountPrivate *priv;
2276 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
2278 priv = purple_account_get_instance_private(account);
2279 return priv->proxy_info;
2282 PurpleAccountPrivacyType
2283 purple_account_get_privacy_type(PurpleAccount *account)
2285 PurpleAccountPrivate *priv;
2287 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), PURPLE_ACCOUNT_PRIVACY_ALLOW_ALL);
2289 priv = purple_account_get_instance_private(account);
2290 return priv->privacy_type;
2293 gboolean
2294 purple_account_privacy_permit_add(PurpleAccount *account, const char *who,
2295 gboolean local_only)
2297 GSList *l;
2298 char *name;
2299 PurpleBuddy *buddy;
2300 PurpleAccountPrivate *priv;
2301 PurpleAccountUiOps *ui_ops = purple_accounts_get_ui_ops();
2303 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), FALSE);
2304 g_return_val_if_fail(who != NULL, FALSE);
2306 priv = purple_account_get_instance_private(account);
2307 name = g_strdup(purple_normalize(account, who));
2309 for (l = priv->permit; l != NULL; l = l->next) {
2310 if (g_str_equal(name, l->data))
2311 /* This buddy already exists */
2312 break;
2315 if (l != NULL)
2317 /* This buddy already exists, so bail out */
2318 g_free(name);
2319 return FALSE;
2322 priv->permit = g_slist_append(priv->permit, name);
2324 if (!local_only && purple_account_is_connected(account))
2325 purple_serv_add_permit(purple_account_get_connection(account), who);
2327 if (ui_ops != NULL && ui_ops->permit_added != NULL)
2328 ui_ops->permit_added(account, who);
2330 purple_blist_save_account(purple_blist_get_default(), account);
2332 /* This lets the UI know a buddy has had its privacy setting changed */
2333 buddy = purple_blist_find_buddy(account, name);
2334 if (buddy != NULL) {
2335 purple_signal_emit(purple_blist_get_handle(),
2336 "buddy-privacy-changed", buddy);
2338 return TRUE;
2341 gboolean
2342 purple_account_privacy_permit_remove(PurpleAccount *account, const char *who,
2343 gboolean local_only)
2345 GSList *l;
2346 const char *name;
2347 PurpleBuddy *buddy;
2348 char *del;
2349 PurpleAccountPrivate *priv;
2350 PurpleAccountUiOps *ui_ops = purple_accounts_get_ui_ops();
2352 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), FALSE);
2353 g_return_val_if_fail(who != NULL, FALSE);
2355 priv = purple_account_get_instance_private(account);
2356 name = purple_normalize(account, who);
2358 for (l = priv->permit; l != NULL; l = l->next) {
2359 if (g_str_equal(name, l->data))
2360 /* We found the buddy we were looking for */
2361 break;
2364 if (l == NULL)
2365 /* We didn't find the buddy we were looking for, so bail out */
2366 return FALSE;
2368 /* We should not free l->data just yet. There can be occasions where
2369 * l->data == who. In such cases, freeing l->data here can cause crashes
2370 * later when who is used. */
2371 del = l->data;
2372 priv->permit = g_slist_delete_link(priv->permit, l);
2374 if (!local_only && purple_account_is_connected(account))
2375 purple_serv_rem_permit(purple_account_get_connection(account), who);
2377 if (ui_ops != NULL && ui_ops->permit_removed != NULL)
2378 ui_ops->permit_removed(account, who);
2380 purple_blist_save_account(purple_blist_get_default(), account);
2382 buddy = purple_blist_find_buddy(account, name);
2383 if (buddy != NULL) {
2384 purple_signal_emit(purple_blist_get_handle(),
2385 "buddy-privacy-changed", buddy);
2387 g_free(del);
2388 return TRUE;
2391 gboolean
2392 purple_account_privacy_deny_add(PurpleAccount *account, const char *who,
2393 gboolean local_only)
2395 GSList *l;
2396 char *name;
2397 PurpleBuddy *buddy;
2398 PurpleAccountPrivate *priv;
2399 PurpleAccountUiOps *ui_ops = purple_accounts_get_ui_ops();
2401 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), FALSE);
2402 g_return_val_if_fail(who != NULL, FALSE);
2404 priv = purple_account_get_instance_private(account);
2405 name = g_strdup(purple_normalize(account, who));
2407 for (l = priv->deny; l != NULL; l = l->next) {
2408 if (g_str_equal(name, l->data))
2409 /* This buddy already exists */
2410 break;
2413 if (l != NULL)
2415 /* This buddy already exists, so bail out */
2416 g_free(name);
2417 return FALSE;
2420 priv->deny = g_slist_append(priv->deny, name);
2422 if (!local_only && purple_account_is_connected(account))
2423 purple_serv_add_deny(purple_account_get_connection(account), who);
2425 if (ui_ops != NULL && ui_ops->deny_added != NULL)
2426 ui_ops->deny_added(account, who);
2428 purple_blist_save_account(purple_blist_get_default(), account);
2430 buddy = purple_blist_find_buddy(account, name);
2431 if (buddy != NULL) {
2432 purple_signal_emit(purple_blist_get_handle(),
2433 "buddy-privacy-changed", buddy);
2435 return TRUE;
2438 gboolean
2439 purple_account_privacy_deny_remove(PurpleAccount *account, const char *who,
2440 gboolean local_only)
2442 GSList *l;
2443 const char *normalized;
2444 char *name;
2445 PurpleBuddy *buddy;
2446 PurpleAccountPrivate *priv;
2447 PurpleAccountUiOps *ui_ops = purple_accounts_get_ui_ops();
2449 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), FALSE);
2450 g_return_val_if_fail(who != NULL, FALSE);
2452 priv = purple_account_get_instance_private(account);
2453 normalized = purple_normalize(account, who);
2455 for (l = priv->deny; l != NULL; l = l->next) {
2456 if (g_str_equal(normalized, l->data))
2457 /* We found the buddy we were looking for */
2458 break;
2461 if (l == NULL)
2462 /* We didn't find the buddy we were looking for, so bail out */
2463 return FALSE;
2465 buddy = purple_blist_find_buddy(account, normalized);
2467 name = l->data;
2468 priv->deny = g_slist_delete_link(priv->deny, l);
2470 if (!local_only && purple_account_is_connected(account))
2471 purple_serv_rem_deny(purple_account_get_connection(account), name);
2473 if (ui_ops != NULL && ui_ops->deny_removed != NULL)
2474 ui_ops->deny_removed(account, who);
2476 if (buddy != NULL) {
2477 purple_signal_emit(purple_blist_get_handle(),
2478 "buddy-privacy-changed", buddy);
2481 g_free(name);
2483 purple_blist_save_account(purple_blist_get_default(), account);
2485 return TRUE;
2488 void
2489 purple_account_privacy_allow(PurpleAccount *account, const char *who)
2491 GSList *list;
2492 PurpleAccountPrivacyType type = purple_account_get_privacy_type(account);
2493 PurpleAccountPrivate *priv = purple_account_get_instance_private(account);
2495 switch (type) {
2496 case PURPLE_ACCOUNT_PRIVACY_ALLOW_ALL:
2497 return;
2498 case PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS:
2499 purple_account_privacy_permit_add(account, who, FALSE);
2500 break;
2501 case PURPLE_ACCOUNT_PRIVACY_DENY_USERS:
2502 purple_account_privacy_deny_remove(account, who, FALSE);
2503 break;
2504 case PURPLE_ACCOUNT_PRIVACY_DENY_ALL:
2506 /* Empty the allow-list. */
2507 const char *norm = purple_normalize(account, who);
2508 for (list = priv->permit; list != NULL;) {
2509 char *person = list->data;
2510 list = list->next;
2511 if (!purple_strequal(norm, person))
2512 purple_account_privacy_permit_remove(account, person, FALSE);
2514 purple_account_privacy_permit_add(account, who, FALSE);
2515 purple_account_set_privacy_type(account, PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS);
2517 break;
2518 case PURPLE_ACCOUNT_PRIVACY_ALLOW_BUDDYLIST:
2519 if (!purple_blist_find_buddy(account, who)) {
2520 add_all_buddies_to_permit_list(account, FALSE);
2521 purple_account_privacy_permit_add(account, who, FALSE);
2522 purple_account_set_privacy_type(account, PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS);
2524 break;
2525 default:
2526 g_return_if_reached();
2529 /* Notify the server if the privacy setting was changed */
2530 if (type != purple_account_get_privacy_type(account) && purple_account_is_connected(account))
2531 purple_serv_set_permit_deny(purple_account_get_connection(account));
2534 void
2535 purple_account_privacy_deny(PurpleAccount *account, const char *who)
2537 GSList *list;
2538 PurpleAccountPrivacyType type = purple_account_get_privacy_type(account);
2539 PurpleAccountPrivate *priv = purple_account_get_instance_private(account);
2541 switch (type) {
2542 case PURPLE_ACCOUNT_PRIVACY_ALLOW_ALL:
2544 /* Empty the deny-list. */
2545 const char *norm = purple_normalize(account, who);
2546 for (list = priv->deny; list != NULL; ) {
2547 char *person = list->data;
2548 list = list->next;
2549 if (!purple_strequal(norm, person))
2550 purple_account_privacy_deny_remove(account, person, FALSE);
2552 purple_account_privacy_deny_add(account, who, FALSE);
2553 purple_account_set_privacy_type(account, PURPLE_ACCOUNT_PRIVACY_DENY_USERS);
2555 break;
2556 case PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS:
2557 purple_account_privacy_permit_remove(account, who, FALSE);
2558 break;
2559 case PURPLE_ACCOUNT_PRIVACY_DENY_USERS:
2560 purple_account_privacy_deny_add(account, who, FALSE);
2561 break;
2562 case PURPLE_ACCOUNT_PRIVACY_DENY_ALL:
2563 break;
2564 case PURPLE_ACCOUNT_PRIVACY_ALLOW_BUDDYLIST:
2565 if (purple_blist_find_buddy(account, who)) {
2566 add_all_buddies_to_permit_list(account, FALSE);
2567 purple_account_privacy_permit_remove(account, who, FALSE);
2568 purple_account_set_privacy_type(account, PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS);
2570 break;
2571 default:
2572 g_return_if_reached();
2575 /* Notify the server if the privacy setting was changed */
2576 if (type != purple_account_get_privacy_type(account) && purple_account_is_connected(account))
2577 purple_serv_set_permit_deny(purple_account_get_connection(account));
2580 GSList *
2581 purple_account_privacy_get_permitted(PurpleAccount *account)
2583 PurpleAccountPrivate *priv = NULL;
2585 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
2587 priv = purple_account_get_instance_private(account);
2588 return priv->permit;
2591 GSList *
2592 purple_account_privacy_get_denied(PurpleAccount *account)
2594 PurpleAccountPrivate *priv = NULL;
2596 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
2598 priv = purple_account_get_instance_private(account);
2599 return priv->deny;
2602 gboolean
2603 purple_account_privacy_check(PurpleAccount *account, const char *who)
2605 GSList *list;
2606 PurpleAccountPrivate *priv = purple_account_get_instance_private(account);
2608 switch (purple_account_get_privacy_type(account)) {
2609 case PURPLE_ACCOUNT_PRIVACY_ALLOW_ALL:
2610 return TRUE;
2612 case PURPLE_ACCOUNT_PRIVACY_DENY_ALL:
2613 return FALSE;
2615 case PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS:
2616 who = purple_normalize(account, who);
2617 for (list=priv->permit; list!=NULL; list=list->next) {
2618 if (g_str_equal(who, list->data))
2619 return TRUE;
2621 return FALSE;
2623 case PURPLE_ACCOUNT_PRIVACY_DENY_USERS:
2624 who = purple_normalize(account, who);
2625 for (list=priv->deny; list!=NULL; list=list->next) {
2626 if (g_str_equal(who, list->data))
2627 return FALSE;
2629 return TRUE;
2631 case PURPLE_ACCOUNT_PRIVACY_ALLOW_BUDDYLIST:
2632 return (purple_blist_find_buddy(account, who) != NULL);
2634 default:
2635 g_return_val_if_reached(TRUE);
2639 PurpleStatus *
2640 purple_account_get_active_status(PurpleAccount *account)
2642 PurpleAccountPrivate *priv;
2644 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
2646 priv = purple_account_get_instance_private(account);
2647 return purple_presence_get_active_status(priv->presence);
2650 PurpleStatus *
2651 purple_account_get_status(PurpleAccount *account, const char *status_id)
2653 PurpleAccountPrivate *priv;
2655 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
2656 g_return_val_if_fail(status_id != NULL, NULL);
2658 priv = purple_account_get_instance_private(account);
2660 return purple_presence_get_status(priv->presence, status_id);
2663 PurpleStatusType *
2664 purple_account_get_status_type(PurpleAccount *account, const char *id)
2666 GList *l;
2668 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
2669 g_return_val_if_fail(id != NULL, NULL);
2671 for (l = purple_account_get_status_types(account); l != NULL; l = l->next)
2673 PurpleStatusType *status_type = (PurpleStatusType *)l->data;
2675 if (purple_strequal(purple_status_type_get_id(status_type), id))
2676 return status_type;
2679 return NULL;
2682 PurpleStatusType *
2683 purple_account_get_status_type_with_primitive(PurpleAccount *account, PurpleStatusPrimitive primitive)
2685 GList *l;
2687 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
2689 for (l = purple_account_get_status_types(account); l != NULL; l = l->next)
2691 PurpleStatusType *status_type = (PurpleStatusType *)l->data;
2693 if (purple_status_type_get_primitive(status_type) == primitive)
2694 return status_type;
2697 return NULL;
2700 PurplePresence *
2701 purple_account_get_presence(PurpleAccount *account)
2703 PurpleAccountPrivate *priv;
2705 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
2707 priv = purple_account_get_instance_private(account);
2708 return priv->presence;
2711 gboolean
2712 purple_account_is_status_active(PurpleAccount *account,
2713 const char *status_id)
2715 PurpleAccountPrivate *priv;
2717 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), FALSE);
2718 g_return_val_if_fail(status_id != NULL, FALSE);
2720 priv = purple_account_get_instance_private(account);
2722 return purple_presence_is_status_active(priv->presence, status_id);
2725 GList *
2726 purple_account_get_status_types(PurpleAccount *account)
2728 PurpleAccountPrivate *priv;
2730 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
2732 priv = purple_account_get_instance_private(account);
2733 return priv->status_types;
2737 purple_account_get_int(PurpleAccount *account, const char *name,
2738 int default_value)
2740 PurpleAccountSetting *setting;
2741 PurpleAccountPrivate *priv;
2743 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), default_value);
2744 g_return_val_if_fail(name != NULL, default_value);
2746 priv = purple_account_get_instance_private(account);
2748 setting = g_hash_table_lookup(priv->settings, name);
2750 if (setting == NULL)
2751 return default_value;
2753 g_return_val_if_fail(G_VALUE_HOLDS_INT(&setting->value), default_value);
2755 return g_value_get_int(&setting->value);
2758 const char *
2759 purple_account_get_string(PurpleAccount *account, const char *name,
2760 const char *default_value)
2762 PurpleAccountSetting *setting;
2763 PurpleAccountPrivate *priv;
2765 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), default_value);
2766 g_return_val_if_fail(name != NULL, default_value);
2768 priv = purple_account_get_instance_private(account);
2770 setting = g_hash_table_lookup(priv->settings, name);
2772 if (setting == NULL)
2773 return default_value;
2775 g_return_val_if_fail(G_VALUE_HOLDS_STRING(&setting->value), default_value);
2777 return g_value_get_string(&setting->value);
2780 gboolean
2781 purple_account_get_bool(PurpleAccount *account, const char *name,
2782 gboolean default_value)
2784 PurpleAccountSetting *setting;
2785 PurpleAccountPrivate *priv;
2787 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), default_value);
2788 g_return_val_if_fail(name != NULL, default_value);
2790 priv = purple_account_get_instance_private(account);
2792 setting = g_hash_table_lookup(priv->settings, name);
2794 if (setting == NULL)
2795 return default_value;
2797 g_return_val_if_fail(G_VALUE_HOLDS_BOOLEAN(&setting->value), default_value);
2799 return g_value_get_boolean(&setting->value);
2803 purple_account_get_ui_int(PurpleAccount *account, const char *ui,
2804 const char *name, int default_value)
2806 PurpleAccountSetting *setting;
2807 PurpleAccountPrivate *priv;
2808 GHashTable *table;
2810 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), default_value);
2811 g_return_val_if_fail(ui != NULL, default_value);
2812 g_return_val_if_fail(name != NULL, default_value);
2814 priv = purple_account_get_instance_private(account);
2816 if ((table = g_hash_table_lookup(priv->ui_settings, ui)) == NULL)
2817 return default_value;
2819 if ((setting = g_hash_table_lookup(table, name)) == NULL)
2820 return default_value;
2822 g_return_val_if_fail(G_VALUE_HOLDS_INT(&setting->value), default_value);
2824 return g_value_get_int(&setting->value);
2827 const char *
2828 purple_account_get_ui_string(PurpleAccount *account, const char *ui,
2829 const char *name, const char *default_value)
2831 PurpleAccountSetting *setting;
2832 PurpleAccountPrivate *priv;
2833 GHashTable *table;
2835 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), default_value);
2836 g_return_val_if_fail(ui != NULL, default_value);
2837 g_return_val_if_fail(name != NULL, default_value);
2839 priv = purple_account_get_instance_private(account);
2841 if ((table = g_hash_table_lookup(priv->ui_settings, ui)) == NULL)
2842 return default_value;
2844 if ((setting = g_hash_table_lookup(table, name)) == NULL)
2845 return default_value;
2847 g_return_val_if_fail(G_VALUE_HOLDS_STRING(&setting->value), default_value);
2849 return g_value_get_string(&setting->value);
2852 gboolean
2853 purple_account_get_ui_bool(PurpleAccount *account, const char *ui,
2854 const char *name, gboolean default_value)
2856 PurpleAccountSetting *setting;
2857 PurpleAccountPrivate *priv;
2858 GHashTable *table;
2860 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), default_value);
2861 g_return_val_if_fail(ui != NULL, default_value);
2862 g_return_val_if_fail(name != NULL, default_value);
2864 priv = purple_account_get_instance_private(account);
2866 if ((table = g_hash_table_lookup(priv->ui_settings, ui)) == NULL)
2867 return default_value;
2869 if ((setting = g_hash_table_lookup(table, name)) == NULL)
2870 return default_value;
2872 g_return_val_if_fail(G_VALUE_HOLDS_BOOLEAN(&setting->value), default_value);
2874 return g_value_get_boolean(&setting->value);
2877 PurpleLog *
2878 purple_account_get_log(PurpleAccount *account, gboolean create)
2880 PurpleAccountPrivate *priv;
2882 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
2884 priv = purple_account_get_instance_private(account);
2886 if(!priv->system_log && create){
2887 PurplePresence *presence;
2888 int login_time;
2889 GDateTime *dt;
2891 presence = purple_account_get_presence(account);
2892 login_time = purple_presence_get_login_time(presence);
2893 if (login_time != 0) {
2894 dt = g_date_time_new_from_unix_local(login_time);
2895 } else {
2896 dt = g_date_time_new_now_local();
2899 priv->system_log = purple_log_new(PURPLE_LOG_SYSTEM,
2900 purple_account_get_username(account),
2901 account, NULL, dt);
2902 g_date_time_unref(dt);
2905 return priv->system_log;
2908 void
2909 purple_account_destroy_log(PurpleAccount *account)
2911 PurpleAccountPrivate *priv;
2913 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
2915 priv = purple_account_get_instance_private(account);
2917 if(priv->system_log){
2918 purple_log_free(priv->system_log);
2919 priv->system_log = NULL;
2923 void
2924 purple_account_add_buddy(PurpleAccount *account, PurpleBuddy *buddy, const char *message)
2926 PurpleProtocol *protocol = NULL;
2927 PurpleConnection *gc;
2929 g_return_if_fail(PURPLE_IS_ACCOUNT(account));
2930 g_return_if_fail(PURPLE_IS_BUDDY(buddy));
2932 gc = purple_account_get_connection(account);
2933 if (gc != NULL)
2934 protocol = purple_connection_get_protocol(gc);
2936 if (protocol != NULL)
2937 purple_protocol_server_iface_add_buddy(protocol, gc, buddy,
2938 purple_buddy_get_group(buddy), message);
2941 void
2942 purple_account_add_buddies(PurpleAccount *account, GList *buddies, const char *message)
2944 PurpleProtocol *protocol = NULL;
2945 PurpleConnection *gc = purple_account_get_connection(account);
2947 if (gc != NULL)
2948 protocol = purple_connection_get_protocol(gc);
2950 if (protocol) {
2951 GList *cur, *groups = NULL;
2953 /* Make a list of what group each buddy is in */
2954 for (cur = buddies; cur != NULL; cur = cur->next) {
2955 PurpleBuddy *buddy = cur->data;
2956 groups = g_list_append(groups, purple_buddy_get_group(buddy));
2959 if (PURPLE_PROTOCOL_IMPLEMENTS(protocol, SERVER, add_buddies))
2960 purple_protocol_server_iface_add_buddies(protocol, gc, buddies, groups, message);
2961 else if (PURPLE_PROTOCOL_IMPLEMENTS(protocol, SERVER, add_buddy)) {
2962 GList *curb = buddies, *curg = groups;
2964 while ((curb != NULL) && (curg != NULL)) {
2965 purple_protocol_server_iface_add_buddy(protocol, gc, curb->data, curg->data, message);
2966 curb = curb->next;
2967 curg = curg->next;
2971 g_list_free(groups);
2975 void
2976 purple_account_remove_buddy(PurpleAccount *account, PurpleBuddy *buddy,
2977 PurpleGroup *group)
2979 PurpleProtocol *protocol = NULL;
2980 PurpleConnection *gc = purple_account_get_connection(account);
2982 if (gc != NULL)
2983 protocol = purple_connection_get_protocol(gc);
2985 if (protocol)
2986 purple_protocol_server_iface_remove_buddy(protocol, gc, buddy, group);
2989 void
2990 purple_account_remove_buddies(PurpleAccount *account, GList *buddies, GList *groups)
2992 PurpleProtocol *protocol = NULL;
2993 PurpleConnection *gc = purple_account_get_connection(account);
2995 if (gc != NULL)
2996 protocol = purple_connection_get_protocol(gc);
2998 if (protocol) {
2999 if (PURPLE_PROTOCOL_IMPLEMENTS(protocol, SERVER, remove_buddies))
3000 purple_protocol_server_iface_remove_buddies(protocol, gc, buddies, groups);
3001 else {
3002 GList *curb = buddies;
3003 GList *curg = groups;
3004 while ((curb != NULL) && (curg != NULL)) {
3005 purple_account_remove_buddy(account, curb->data, curg->data);
3006 curb = curb->next;
3007 curg = curg->next;
3013 void
3014 purple_account_remove_group(PurpleAccount *account, PurpleGroup *group)
3016 PurpleProtocol *protocol = NULL;
3017 PurpleConnection *gc = purple_account_get_connection(account);
3019 if (gc != NULL)
3020 protocol = purple_connection_get_protocol(gc);
3022 if (protocol)
3023 purple_protocol_server_iface_remove_group(protocol, gc, group);
3026 void
3027 purple_account_change_password(PurpleAccount *account, const char *orig_pw,
3028 const char *new_pw)
3030 PurpleProtocol *protocol = NULL;
3031 PurpleConnection *gc = purple_account_get_connection(account);
3033 purple_account_set_password(account, new_pw, NULL, NULL);
3035 if (gc != NULL)
3036 protocol = purple_connection_get_protocol(gc);
3038 if (protocol)
3039 purple_protocol_server_iface_change_passwd(protocol, gc, orig_pw, new_pw);
3042 gboolean purple_account_supports_offline_message(PurpleAccount *account, PurpleBuddy *buddy)
3044 PurpleConnection *gc;
3045 PurpleProtocol *protocol = NULL;
3047 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), FALSE);
3048 g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), FALSE);
3050 gc = purple_account_get_connection(account);
3051 if (gc == NULL)
3052 return FALSE;
3054 protocol = purple_connection_get_protocol(gc);
3056 if (!protocol)
3057 return FALSE;
3058 return purple_protocol_client_iface_offline_message(protocol, buddy);
3061 const PurpleConnectionErrorInfo *
3062 purple_account_get_current_error(PurpleAccount *account)
3064 PurpleAccountPrivate *priv = purple_account_get_instance_private(account);
3066 return priv->current_error;
3069 void
3070 purple_account_clear_current_error(PurpleAccount *account)
3072 _purple_account_set_current_error(account, NULL);