* Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA G_DEFINE_QUARK(purple-connection-error-quark, purple_connection_error); * Represents an active connection on an account. /* Private data for a connection */ PurpleProtocol *protocol; /* The protocol. */ PurpleConnectionFlags flags; /* Connection flags. */ PurpleConnectionState state; /* The connection state. */ PurpleAccount *account; /* The account being connected to. */ char *password; /* The password used. */ GSList *active_chats; /* A list of active chats (#PurpleChatConversation structs). */ /* TODO Remove this and use protocol-specific subclasses. */ void *proto_data; /* Protocol-specific data. */ char *display_name; /* How you appear to other people. */ GSource *keepalive; /* Keep-alive. */ /* Wants to Die state. This is set when the user chooses to log out, or * when the protocol is disconnected and should not be automatically * reconnected (incorrect password, etc.). Protocols should rely on * purple_connection_error() to set this for them rather than * See purple_connection_error_is_fatal() gboolean is_finalizing; /* The object is being destroyed. */ /* The connection error and its description if an error occured */ PurpleConnectionErrorInfo *error_info; guint disconnect_timeout; /* Timer used for nasty stack tricks */ } PurpleConnectionPrivate; /* GObject property enums */ static GParamSpec *properties[PROP_LAST]; static GList *connections = NULL; static GList *connections_connecting = NULL; static PurpleConnectionUiOps *connection_ui_ops = NULL; static int connections_handle; static PurpleConnectionErrorInfo * purple_connection_error_info_new(PurpleConnectionError type, const gchar *description); G_DEFINE_TYPE_WITH_PRIVATE(PurpleConnection, purple_connection, G_TYPE_OBJECT) /************************************************************************** **************************************************************************/ send_keepalive(gpointer data) PurpleConnection *gc = data; PurpleConnectionPrivate *priv = purple_connection_get_instance_private(gc); purple_protocol_server_iface_keepalive(priv->protocol, gc); update_keepalive(PurpleConnection *gc, gboolean on) PurpleConnectionPrivate *priv = purple_connection_get_instance_private(gc); if (!PURPLE_PROTOCOL_IMPLEMENTS(priv->protocol, SERVER, keepalive)) if (on && !priv->keepalive) int interval = purple_protocol_server_iface_get_keepalive_interval(priv->protocol); purple_debug_info("connection", "Activating keepalive to %d seconds.", interval); priv->keepalive = g_main_context_find_source_by_id(NULL, g_timeout_add_seconds(interval, send_keepalive, gc)); else if (!on && priv->keepalive) purple_debug_info("connection", "Deactivating keepalive.\n"); g_source_destroy(priv->keepalive); purple_connection_set_state(PurpleConnection *gc, PurpleConnectionState state) PurpleConnectionPrivate *priv = NULL; PurpleConnectionUiOps *ops; g_return_if_fail(PURPLE_IS_CONNECTION(gc)); priv = purple_connection_get_instance_private(gc); if (priv->state == state) ops = purple_connections_get_ui_ops(); if (priv->state == PURPLE_CONNECTION_CONNECTING) { connections_connecting = g_list_append(connections_connecting, gc); connections_connecting = g_list_remove(connections_connecting, gc); if (priv->state == PURPLE_CONNECTION_CONNECTED) { PurplePresence *presence; account = purple_connection_get_account(gc); presence = purple_account_get_presence(account); /* Set the time the account came online */ purple_presence_set_login_time(presence, time(NULL)); if (purple_prefs_get_bool("/purple/logging/log_system")) PurpleLog *log = purple_account_get_log(account, TRUE); char *msg = g_strdup_printf(_("+++ %s signed on"), purple_account_get_username(account)); GDateTime *dt = g_date_time_new_from_unix_local(purple_presence_get_login_time(presence)); purple_log_write(log, PURPLE_MESSAGE_SYSTEM, purple_account_get_username(account), if (ops != NULL && ops->connected != NULL) purple_blist_add_account(account); purple_signal_emit(purple_connections_get_handle(), "signed-on", gc); purple_signal_emit_return_1(purple_connections_get_handle(), "autojoin", gc); purple_serv_set_permit_deny(gc); update_keepalive(gc, TRUE); else if (priv->state == PURPLE_CONNECTION_DISCONNECTED) { PurpleAccount *account = purple_connection_get_account(gc); if (purple_prefs_get_bool("/purple/logging/log_system")) PurpleLog *log = purple_account_get_log(account, FALSE); char *msg = g_strdup_printf(_("+++ %s signed off"), purple_account_get_username(account)); GDateTime *dt = g_date_time_new_now_utc(); purple_log_write(log, PURPLE_MESSAGE_SYSTEM, purple_account_get_username(account), purple_account_destroy_log(account); if (ops != NULL && ops->disconnected != NULL) if (!priv->is_finalizing) g_object_notify_by_pspec(G_OBJECT(gc), properties[PROP_STATE]); purple_connection_set_flags(PurpleConnection *gc, PurpleConnectionFlags flags) PurpleConnectionPrivate *priv = NULL; g_return_if_fail(PURPLE_IS_CONNECTION(gc)); priv = purple_connection_get_instance_private(gc); if (!priv->is_finalizing) g_object_notify_by_pspec(G_OBJECT(gc), properties[PROP_FLAGS]); purple_connection_set_display_name(PurpleConnection *gc, const char *name) PurpleConnectionPrivate *priv = NULL; g_return_if_fail(PURPLE_IS_CONNECTION(gc)); priv = purple_connection_get_instance_private(gc); g_free(priv->display_name); priv->display_name = g_strdup(name); g_object_notify_by_pspec(G_OBJECT(gc), properties[PROP_DISPLAY_NAME]); purple_connection_set_protocol_data(PurpleConnection *gc, void *proto_data) PurpleConnectionPrivate *priv = NULL; g_return_if_fail(PURPLE_IS_CONNECTION(gc)); priv = purple_connection_get_instance_private(gc); priv->proto_data = proto_data; purple_connection_get_state(PurpleConnection *gc) PurpleConnectionPrivate *priv = NULL; g_return_val_if_fail(PURPLE_IS_CONNECTION(gc), PURPLE_CONNECTION_DISCONNECTED); priv = purple_connection_get_instance_private(gc); purple_connection_get_flags(PurpleConnection *gc) PurpleConnectionPrivate *priv = NULL; g_return_val_if_fail(PURPLE_IS_CONNECTION(gc), 0); priv = purple_connection_get_instance_private(gc); purple_connection_is_disconnecting(PurpleConnection *gc) PurpleConnectionPrivate *priv = NULL; g_return_val_if_fail(PURPLE_IS_CONNECTION(gc), TRUE); priv = purple_connection_get_instance_private(gc); return priv->is_finalizing; purple_connection_get_account(PurpleConnection *gc) PurpleConnectionPrivate *priv = NULL; g_return_val_if_fail(PURPLE_IS_CONNECTION(gc), NULL); priv = purple_connection_get_instance_private(gc); purple_connection_get_protocol(PurpleConnection *gc) PurpleConnectionPrivate *priv = NULL; g_return_val_if_fail(PURPLE_IS_CONNECTION(gc), NULL); priv = purple_connection_get_instance_private(gc); purple_connection_get_password(PurpleConnection *gc) PurpleConnectionPrivate *priv = NULL; g_return_val_if_fail(PURPLE_IS_CONNECTION(gc), NULL); priv = purple_connection_get_instance_private(gc); purple_connection_get_active_chats(PurpleConnection *gc) PurpleConnectionPrivate *priv = NULL; g_return_val_if_fail(PURPLE_IS_CONNECTION(gc), NULL); priv = purple_connection_get_instance_private(gc); return priv->active_chats; purple_connection_get_display_name(PurpleConnection *gc) PurpleConnectionPrivate *priv = NULL; g_return_val_if_fail(PURPLE_IS_CONNECTION(gc), NULL); priv = purple_connection_get_instance_private(gc); return priv->display_name; purple_connection_get_protocol_data(PurpleConnection *gc) PurpleConnectionPrivate *priv = NULL; g_return_val_if_fail(PURPLE_IS_CONNECTION(gc), NULL); priv = purple_connection_get_instance_private(gc); _purple_connection_add_active_chat(PurpleConnection *gc, PurpleChatConversation *chat) PurpleConnectionPrivate *priv = NULL; g_return_if_fail(PURPLE_IS_CONNECTION(gc)); priv = purple_connection_get_instance_private(gc); priv->active_chats = g_slist_append(priv->active_chats, chat); _purple_connection_remove_active_chat(PurpleConnection *gc, PurpleChatConversation *chat) PurpleConnectionPrivate *priv = NULL; g_return_if_fail(PURPLE_IS_CONNECTION(gc)); priv = purple_connection_get_instance_private(gc); priv->active_chats = g_slist_remove(priv->active_chats, chat); _purple_connection_wants_to_die(PurpleConnection *gc) PurpleConnectionPrivate *priv = NULL; g_return_val_if_fail(PURPLE_IS_CONNECTION(gc), FALSE); priv = purple_connection_get_instance_private(gc); return priv->wants_to_die; purple_connection_update_progress(PurpleConnection *gc, const char *text, size_t step, size_t count) PurpleConnectionUiOps *ops; g_return_if_fail(PURPLE_IS_CONNECTION(gc)); g_return_if_fail(text != NULL); g_return_if_fail(step < count); g_return_if_fail(count > 1); ops = purple_connections_get_ui_ops(); if (ops != NULL && ops->connect_progress != NULL) ops->connect_progress(gc, text, step, count); purple_connection_notice(PurpleConnection *gc, const char *text) PurpleConnectionUiOps *ops; g_return_if_fail(PURPLE_IS_CONNECTION(gc)); g_return_if_fail(text != NULL); ops = purple_connections_get_ui_ops(); if (ops != NULL && ops->notice != NULL) purple_connection_disconnect_cb(gpointer data) gc = purple_account_get_connection(account); if (PURPLE_IS_CONNECTION(gc)) { PurpleConnectionPrivate *priv; priv = purple_connection_get_instance_private(gc); priv->disconnect_timeout = 0; purple_account_disconnect(account); purple_connection_error (PurpleConnection *gc, PurpleConnectionError reason, PurpleConnectionPrivate *priv = NULL; PurpleConnectionUiOps *ops; g_return_if_fail(PURPLE_IS_CONNECTION(gc)); priv = purple_connection_get_instance_private(gc); /* This sanity check relies on PURPLE_CONNECTION_ERROR_OTHER_ERROR * being the last member of the PurpleConnectionError enum in * connection.h; if other reasons are added after it, this check should if (reason > PURPLE_CONNECTION_ERROR_OTHER_ERROR) { purple_debug_error("connection", "purple_connection_error: reason %u isn't a " "valid reason\n", reason); reason = PURPLE_CONNECTION_ERROR_OTHER_ERROR; if (description == NULL) { purple_debug_error("connection", "purple_connection_error called with NULL description\n"); description = _("Unknown error"); /* If we've already got one error, we don't need any more */ if (purple_connection_get_error_info(gc)) priv->wants_to_die = purple_connection_error_is_fatal (reason); purple_debug_info("connection", "Connection error on %p (reason: %u description: %s)\n", gc, reason, description); ops = purple_connections_get_ui_ops(); if (ops && ops->report_disconnect) ops->report_disconnect(gc, reason, description); priv->error_info = purple_connection_error_info_new(reason, description); purple_signal_emit(purple_connections_get_handle(), "connection-error", gc, reason, description); priv->disconnect_timeout = g_timeout_add(0, purple_connection_disconnect_cb, purple_connection_get_account(gc)); PurpleConnectionErrorInfo * purple_connection_get_error_info(PurpleConnection *gc) PurpleConnectionPrivate *priv = NULL; g_return_val_if_fail(PURPLE_IS_CONNECTION(gc), NULL); priv = purple_connection_get_instance_private(gc); purple_connection_ssl_error (PurpleConnection *gc, PurpleSslErrorType ssl_error) PurpleConnectionError reason; case PURPLE_SSL_HANDSHAKE_FAILED: reason = PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR; case PURPLE_SSL_CONNECT_FAILED: reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR; case PURPLE_SSL_CERTIFICATE_INVALID: /* TODO: maybe PURPLE_SSL_* should be more specific? */ reason = PURPLE_CONNECTION_ERROR_CERT_OTHER_ERROR; reason = PURPLE_CONNECTION_ERROR_CERT_OTHER_ERROR; purple_connection_error (gc, reason, purple_ssl_strerror(ssl_error)); purple_connection_g_error(PurpleConnection *pc, const GError *error) PurpleConnectionError reason; if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { /* Not a connection error. Ignore. */ if (error->domain == G_TLS_ERROR) { case G_TLS_ERROR_UNAVAILABLE: reason = PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT; case G_TLS_ERROR_NOT_TLS: case G_TLS_ERROR_HANDSHAKE: reason = PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR; case G_TLS_ERROR_BAD_CERTIFICATE: case G_TLS_ERROR_CERTIFICATE_REQUIRED: reason = PURPLE_CONNECTION_ERROR_CERT_OTHER_ERROR; reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR; } else if (error->domain == G_IO_ERROR) { reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR; } else if (error->domain == PURPLE_CONNECTION_ERROR) { reason = PURPLE_CONNECTION_ERROR_OTHER_ERROR; purple_connection_error(pc, reason, error->message); purple_connection_take_error(PurpleConnection *pc, GError *error) purple_connection_g_error(pc, error); purple_connection_error_is_fatal (PurpleConnectionError reason) case PURPLE_CONNECTION_ERROR_NETWORK_ERROR: case PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR: case PURPLE_CONNECTION_ERROR_INVALID_USERNAME: case PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED: case PURPLE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE: case PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT: case PURPLE_CONNECTION_ERROR_NAME_IN_USE: case PURPLE_CONNECTION_ERROR_INVALID_SETTINGS: case PURPLE_CONNECTION_ERROR_OTHER_ERROR: case PURPLE_CONNECTION_ERROR_CERT_NOT_PROVIDED: case PURPLE_CONNECTION_ERROR_CERT_UNTRUSTED: case PURPLE_CONNECTION_ERROR_CERT_EXPIRED: case PURPLE_CONNECTION_ERROR_CERT_NOT_ACTIVATED: case PURPLE_CONNECTION_ERROR_CERT_HOSTNAME_MISMATCH: case PURPLE_CONNECTION_ERROR_CERT_FINGERPRINT_MISMATCH: case PURPLE_CONNECTION_ERROR_CERT_SELF_SIGNED: case PURPLE_CONNECTION_ERROR_CERT_OTHER_ERROR: g_return_val_if_reached(TRUE); void purple_connection_update_last_received(PurpleConnection *gc) PurpleConnectionPrivate *priv = NULL; g_return_if_fail(PURPLE_IS_CONNECTION(gc)); priv = purple_connection_get_instance_private(gc); * For safety, actually this function shouldn't be called when the * keepalive mechanism is inactive. /* The #GTimeoutSource API doesn't expose a function to reset when a * #GTimeoutSource will dispatch the next time, but because it works to * directly call g_source_set_ready_time() on a #GTimeoutSource, and since * it seems unlikely that the implementation will change, we just do that * for now as a workaround for this API shortcoming. gint64 seconds_from_now = purple_protocol_server_iface_get_keepalive_interval(priv->protocol); g_get_monotonic_time() + (seconds_from_now * G_USEC_PER_SEC) static PurpleConnectionErrorInfo * purple_connection_error_info_new(PurpleConnectionError type, const gchar *description) PurpleConnectionErrorInfo *err; g_return_val_if_fail(description != NULL, NULL); err = g_new(PurpleConnectionErrorInfo, 1); err->description = g_strdup(description); /************************************************************************** **************************************************************************/ static PurpleConnectionUiOps * purple_connection_ui_ops_copy(PurpleConnectionUiOps *ops) PurpleConnectionUiOps *ops_new; g_return_val_if_fail(ops != NULL, NULL); ops_new = g_new(PurpleConnectionUiOps, 1); purple_connection_ui_ops_get_type(void) type = g_boxed_type_register_static("PurpleConnectionUiOps", (GBoxedCopyFunc)purple_connection_ui_ops_copy, static PurpleConnectionErrorInfo * purple_connection_error_info_copy(PurpleConnectionErrorInfo *err) g_return_val_if_fail(err != NULL, NULL); return purple_connection_error_info_new(err->type, err->description); purple_connection_error_info_free(PurpleConnectionErrorInfo *err) g_return_if_fail(err != NULL); g_free(err->description); purple_connection_error_info_get_type(void) type = g_boxed_type_register_static("PurpleConnectionErrorInfo", (GBoxedCopyFunc)purple_connection_error_info_copy, (GBoxedFreeFunc)purple_connection_error_info_free); /************************************************************************** **************************************************************************/ /* Set method for GObject properties */ purple_connection_set_property(GObject *obj, guint param_id, const GValue *value, PurpleConnection *gc = PURPLE_CONNECTION(obj); PurpleConnectionPrivate *priv = purple_connection_get_instance_private(gc); priv->protocol = g_value_get_object(value); purple_connection_set_flags(gc, g_value_get_flags(value)); purple_connection_set_state(gc, g_value_get_enum(value)); priv->account = g_value_get_object(value); priv->password = g_value_dup_string(value); purple_connection_set_display_name(gc, g_value_get_string(value)); G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); /* Get method for GObject properties */ purple_connection_get_property(GObject *obj, guint param_id, GValue *value, PurpleConnection *gc = PURPLE_CONNECTION(obj); g_value_set_object(value, purple_connection_get_protocol(gc)); g_value_set_flags(value, purple_connection_get_flags(gc)); g_value_set_enum(value, purple_connection_get_state(gc)); g_value_set_object(value, purple_connection_get_account(gc)); g_value_set_string(value, purple_connection_get_password(gc)); g_value_set_string(value, purple_connection_get_display_name(gc)); G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); /* GObject initialization function */ purple_connection_init(PurpleConnection *gc) purple_connection_set_state(gc, PURPLE_CONNECTION_CONNECTING); connections = g_list_append(connections, gc); /* Called when done constructing */ purple_connection_constructed(GObject *object) PurpleConnection *gc = PURPLE_CONNECTION(object); G_OBJECT_CLASS(purple_connection_parent_class)->constructed(object); g_object_get(gc, "account", &account, NULL); purple_account_set_connection(account, gc); purple_signal_emit(purple_connections_get_handle(), "signing-on", gc); /* GObject finalize function */ purple_connection_finalize(GObject *object) PurpleConnection *gc = PURPLE_CONNECTION(object); PurpleConnectionPrivate *priv = purple_connection_get_instance_private(gc); priv->is_finalizing = TRUE; account = purple_connection_get_account(gc); purple_debug_info("connection", "Disconnecting connection %p\n", gc); if (purple_connection_get_state(gc) != PURPLE_CONNECTION_CONNECTING) purple_signal_emit(purple_connections_get_handle(), "signing-off", gc); g_slist_free_full(priv->active_chats, (GDestroyNotify)purple_chat_conversation_leave); update_keepalive(gc, FALSE); purple_protocol_class_close(priv->protocol, gc); /* Clear out the proto data that was freed in the protocol's close method */ buddies = purple_blist_find_buddies(account, NULL); while (buddies != NULL) { PurpleBuddy *buddy = buddies->data; purple_buddy_set_protocol_data(buddy, NULL); buddies = g_slist_delete_link(buddies, buddies); purple_proxy_connect_cancel_with_handle(gc); connections = g_list_remove(connections, gc); purple_connection_set_state(gc, PURPLE_CONNECTION_DISCONNECTED); purple_blist_remove_account(account); purple_signal_emit(purple_connections_get_handle(), "signed-off", gc); purple_account_request_close_with_account(account); purple_request_close_with_handle(gc); purple_notify_close_with_handle(gc); purple_debug_info("connection", "Destroying connection %p\n", gc); purple_account_set_connection(account, NULL); purple_connection_error_info_free(priv->error_info); if (priv->disconnect_timeout > 0) g_source_remove(priv->disconnect_timeout); purple_str_wipe(priv->password); g_free(priv->display_name); G_OBJECT_CLASS(purple_connection_parent_class)->finalize(object); /* Class initializer function */ static void purple_connection_class_init(PurpleConnectionClass *klass) GObjectClass *obj_class = G_OBJECT_CLASS(klass); obj_class->finalize = purple_connection_finalize; obj_class->constructed = purple_connection_constructed; obj_class->get_property = purple_connection_get_property; obj_class->set_property = purple_connection_set_property; properties[PROP_PROTOCOL] = g_param_spec_object("protocol", "Protocol", "The protocol that the connection is using.", G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | properties[PROP_FLAGS] = g_param_spec_flags("flags", "Connection flags", "The flags of the connection.", PURPLE_TYPE_CONNECTION_FLAGS, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); properties[PROP_STATE] = g_param_spec_enum("state", "Connection state", "The current state of the connection.", PURPLE_TYPE_CONNECTION_STATE, PURPLE_CONNECTION_DISCONNECTED, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); properties[PROP_ACCOUNT] = g_param_spec_object("account", "Account", "The account using the connection.", PURPLE_TYPE_ACCOUNT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | properties[PROP_PASSWORD] = g_param_spec_string("password", "Password", "The password used for connection.", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | properties[PROP_DISPLAY_NAME] = g_param_spec_string("display-name", "Your name that appears to other people.", NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties(obj_class, PROP_LAST, properties); _purple_connection_new(PurpleAccount *account, gboolean regist, const char *password) PurpleProtocol *protocol; g_return_if_fail(PURPLE_IS_ACCOUNT(account)); if (!purple_account_is_disconnected(account)) protocol = purple_protocols_find(purple_account_get_protocol_id(account)); message = g_strdup_printf(_("Missing protocol for %s"), purple_account_get_username(account)); purple_notify_error(NULL, regist ? _("Registration Error") : _("Connection Error"), message, NULL, purple_request_cpar_from_account(account)); if (!PURPLE_PROTOCOL_IMPLEMENTS(protocol, SERVER, register_user)) if (((password == NULL) || (*password == '\0')) && !(purple_protocol_get_options(protocol) & OPT_PROTO_NO_PASSWORD) && !(purple_protocol_get_options(protocol) & OPT_PROTO_PASSWORD_OPTIONAL)) purple_debug_error("connection", "Cannot connect to account %s without " "a password.\n", purple_account_get_username(account)); if (PURPLE_PROTOCOL_IMPLEMENTS(protocol, FACTORY, connection_new)) gc = purple_protocol_factory_iface_connection_new(protocol, account, gc = g_object_new(PURPLE_TYPE_CONNECTION, g_return_if_fail(gc != NULL); PurpleConnectionPrivate *priv; purple_debug_info("connection", "Registering. gc = %p\n", gc); /* set this so we don't auto-reconnect after registering */ priv = purple_connection_get_instance_private(gc); priv->wants_to_die = TRUE; purple_protocol_server_iface_register_user(protocol, account); purple_debug_info("connection", "Connecting. gc = %p\n", gc); purple_signal_emit(purple_accounts_get_handle(), "account-connecting", account); purple_protocol_class_login(protocol, account); _purple_connection_new_unregister(PurpleAccount *account, const char *password, PurpleAccountUnregistrationCb cb, void *user_data) /* Lots of copy/pasted code to avoid API changes. You might want to integrate that into the previous function when posssible. */ PurpleProtocol *protocol; g_return_if_fail(PURPLE_IS_ACCOUNT(account)); protocol = purple_protocols_find(purple_account_get_protocol_id(account)); message = g_strdup_printf(_("Missing protocol for %s"), purple_account_get_username(account)); purple_notify_error(NULL, _("Unregistration Error"), message, NULL, purple_request_cpar_from_account(account)); if (!purple_account_is_disconnected(account)) { purple_protocol_server_iface_unregister_user(protocol, account, cb, user_data); if (((password == NULL) || (*password == '\0')) && !(purple_protocol_get_options(protocol) & OPT_PROTO_NO_PASSWORD) && !(purple_protocol_get_options(protocol) & OPT_PROTO_PASSWORD_OPTIONAL)) purple_debug_error("connection", "Cannot connect to account %s without " "a password.\n", purple_account_get_username(account)); if (PURPLE_PROTOCOL_IMPLEMENTS(protocol, FACTORY, connection_new)) gc = purple_protocol_factory_iface_connection_new(protocol, account, gc = g_object_new(PURPLE_TYPE_CONNECTION, g_return_if_fail(gc != NULL); purple_debug_info("connection", "Unregistering. gc = %p\n", gc); purple_protocol_server_iface_unregister_user(protocol, account, cb, user_data); /************************************************************************** **************************************************************************/ _purple_assert_connection_is_valid(PurpleConnection *gc, const gchar *file, int line) if (gc && g_list_find(purple_connections_get_all(), gc)) purple_debug_fatal("connection", "PURPLE_ASSERT_CONNECTION_IS_VALID(%p)" " failed at %s:%d", gc, file, line); purple_connections_disconnect_all(void) PurpleConnectionPrivate *priv; while ((l = purple_connections_get_all()) != NULL) { priv = purple_connection_get_instance_private(gc); priv->wants_to_die = TRUE; purple_account_disconnect(priv->account); purple_connections_get_all(void) purple_connections_get_connecting(void) return connections_connecting; purple_connections_set_ui_ops(PurpleConnectionUiOps *ops) purple_connections_get_ui_ops(void) return connection_ui_ops; purple_connections_init(void) void *handle = purple_connections_get_handle(); purple_signal_register(handle, "signing-on", purple_marshal_VOID__POINTER, G_TYPE_NONE, 1, purple_signal_register(handle, "signed-on", purple_marshal_VOID__POINTER, G_TYPE_NONE, 1, purple_signal_register(handle, "signing-off", purple_marshal_VOID__POINTER, G_TYPE_NONE, 1, purple_signal_register(handle, "signed-off", purple_marshal_VOID__POINTER, G_TYPE_NONE, 1, purple_signal_register(handle, "connection-error", purple_marshal_VOID__POINTER_INT_POINTER, G_TYPE_NONE, 3, PURPLE_TYPE_CONNECTION, PURPLE_TYPE_CONNECTION_ERROR, G_TYPE_STRING); purple_signal_register(handle, "autojoin", purple_marshal_BOOLEAN__POINTER, G_TYPE_NONE, 1, purple_connections_uninit(void) purple_signals_unregister_by_instance(purple_connections_get_handle()); purple_connections_get_handle(void) return &connections_handle;