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
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
23 #include "glibcompat.h"
26 #include "buddylist.h"
27 #include "connection.h"
40 G_DEFINE_QUARK(purple
-connection
-error
-quark
, purple_connection_error
);
45 * Represents an active connection on an account.
47 struct _PurpleConnection
52 /* Private data for a connection */
55 PurpleProtocol
*protocol
; /* The protocol. */
56 PurpleConnectionFlags flags
; /* Connection flags. */
58 PurpleConnectionState state
; /* The connection state. */
60 PurpleAccount
*account
; /* The account being connected to. */
61 char *password
; /* The password used. */
63 GSList
*active_chats
; /* A list of active chats
64 (#PurpleChatConversation structs). */
66 /* TODO Remove this and use protocol-specific subclasses. */
67 void *proto_data
; /* Protocol-specific data. */
69 char *display_name
; /* How you appear to other people. */
70 GSource
*keepalive
; /* Keep-alive. */
72 /* Wants to Die state. This is set when the user chooses to log out, or
73 * when the protocol is disconnected and should not be automatically
74 * reconnected (incorrect password, etc.). Protocols should rely on
75 * purple_connection_error() to set this for them rather than
76 * setting it themselves.
77 * See purple_connection_error_is_fatal()
79 gboolean wants_to_die
;
81 gboolean is_finalizing
; /* The object is being destroyed. */
83 /* The connection error and its description if an error occured */
84 PurpleConnectionErrorInfo
*error_info
;
86 guint disconnect_timeout
; /* Timer used for nasty stack tricks */
87 } PurpleConnectionPrivate
;
89 /* GObject property enums */
102 static GParamSpec
*properties
[PROP_LAST
];
104 static GList
*connections
= NULL
;
105 static GList
*connections_connecting
= NULL
;
106 static PurpleConnectionUiOps
*connection_ui_ops
= NULL
;
108 static int connections_handle
;
110 static PurpleConnectionErrorInfo
*
111 purple_connection_error_info_new(PurpleConnectionError type
,
112 const gchar
*description
);
114 G_DEFINE_TYPE_WITH_PRIVATE(PurpleConnection
, purple_connection
, G_TYPE_OBJECT
)
116 /**************************************************************************
118 **************************************************************************/
120 send_keepalive(gpointer data
)
122 PurpleConnection
*gc
= data
;
123 PurpleConnectionPrivate
*priv
= purple_connection_get_instance_private(gc
);
125 purple_protocol_server_iface_keepalive(priv
->protocol
, gc
);
131 update_keepalive(PurpleConnection
*gc
, gboolean on
)
133 PurpleConnectionPrivate
*priv
= purple_connection_get_instance_private(gc
);
135 if (!PURPLE_PROTOCOL_IMPLEMENTS(priv
->protocol
, SERVER
, keepalive
))
138 if (on
&& !priv
->keepalive
)
140 int interval
= purple_protocol_server_iface_get_keepalive_interval(priv
->protocol
);
141 purple_debug_info("connection", "Activating keepalive to %d seconds.", interval
);
142 priv
->keepalive
= g_main_context_find_source_by_id(NULL
, g_timeout_add_seconds(interval
, send_keepalive
, gc
));
144 else if (!on
&& priv
->keepalive
)
146 purple_debug_info("connection", "Deactivating keepalive.\n");
147 g_source_destroy(priv
->keepalive
);
148 priv
->keepalive
= NULL
;
163 purple_connection_set_state(PurpleConnection
*gc
, PurpleConnectionState state
)
165 PurpleConnectionPrivate
*priv
= NULL
;
166 PurpleConnectionUiOps
*ops
;
168 g_return_if_fail(PURPLE_IS_CONNECTION(gc
));
170 priv
= purple_connection_get_instance_private(gc
);
172 if (priv
->state
== state
)
177 ops
= purple_connections_get_ui_ops();
179 if (priv
->state
== PURPLE_CONNECTION_CONNECTING
) {
180 connections_connecting
= g_list_append(connections_connecting
, gc
);
183 connections_connecting
= g_list_remove(connections_connecting
, gc
);
186 if (priv
->state
== PURPLE_CONNECTION_CONNECTED
) {
187 PurpleAccount
*account
;
188 PurplePresence
*presence
;
190 account
= purple_connection_get_account(gc
);
191 presence
= purple_account_get_presence(account
);
193 /* Set the time the account came online */
194 purple_presence_set_login_time(presence
, time(NULL
));
196 if (purple_prefs_get_bool("/purple/logging/log_system"))
198 PurpleLog
*log
= purple_account_get_log(account
, TRUE
);
202 char *msg
= g_strdup_printf(_("+++ %s signed on"),
203 purple_account_get_username(account
));
204 GDateTime
*dt
= g_date_time_new_from_unix_local(purple_presence_get_login_time(presence
));
205 purple_log_write(log
, PURPLE_MESSAGE_SYSTEM
,
206 purple_account_get_username(account
),
208 g_date_time_unref(dt
);
213 if (ops
!= NULL
&& ops
->connected
!= NULL
)
216 purple_blist_add_account(account
);
218 purple_signal_emit(purple_connections_get_handle(), "signed-on", gc
);
219 purple_signal_emit_return_1(purple_connections_get_handle(), "autojoin", gc
);
221 purple_serv_set_permit_deny(gc
);
223 update_keepalive(gc
, TRUE
);
225 else if (priv
->state
== PURPLE_CONNECTION_DISCONNECTED
) {
226 PurpleAccount
*account
= purple_connection_get_account(gc
);
228 if (purple_prefs_get_bool("/purple/logging/log_system"))
230 PurpleLog
*log
= purple_account_get_log(account
, FALSE
);
234 char *msg
= g_strdup_printf(_("+++ %s signed off"),
235 purple_account_get_username(account
));
236 GDateTime
*dt
= g_date_time_new_now_utc();
237 purple_log_write(log
, PURPLE_MESSAGE_SYSTEM
,
238 purple_account_get_username(account
),
240 g_date_time_unref(dt
);
245 purple_account_destroy_log(account
);
247 if (ops
!= NULL
&& ops
->disconnected
!= NULL
)
248 ops
->disconnected(gc
);
251 if (!priv
->is_finalizing
)
252 g_object_notify_by_pspec(G_OBJECT(gc
), properties
[PROP_STATE
]);
256 purple_connection_set_flags(PurpleConnection
*gc
, PurpleConnectionFlags flags
)
258 PurpleConnectionPrivate
*priv
= NULL
;
260 g_return_if_fail(PURPLE_IS_CONNECTION(gc
));
262 priv
= purple_connection_get_instance_private(gc
);
265 if (!priv
->is_finalizing
)
266 g_object_notify_by_pspec(G_OBJECT(gc
), properties
[PROP_FLAGS
]);
270 purple_connection_set_display_name(PurpleConnection
*gc
, const char *name
)
272 PurpleConnectionPrivate
*priv
= NULL
;
274 g_return_if_fail(PURPLE_IS_CONNECTION(gc
));
276 priv
= purple_connection_get_instance_private(gc
);
277 g_free(priv
->display_name
);
278 priv
->display_name
= g_strdup(name
);
280 g_object_notify_by_pspec(G_OBJECT(gc
), properties
[PROP_DISPLAY_NAME
]);
284 purple_connection_set_protocol_data(PurpleConnection
*gc
, void *proto_data
)
286 PurpleConnectionPrivate
*priv
= NULL
;
288 g_return_if_fail(PURPLE_IS_CONNECTION(gc
));
290 priv
= purple_connection_get_instance_private(gc
);
291 priv
->proto_data
= proto_data
;
294 PurpleConnectionState
295 purple_connection_get_state(PurpleConnection
*gc
)
297 PurpleConnectionPrivate
*priv
= NULL
;
299 g_return_val_if_fail(PURPLE_IS_CONNECTION(gc
), PURPLE_CONNECTION_DISCONNECTED
);
301 priv
= purple_connection_get_instance_private(gc
);
305 PurpleConnectionFlags
306 purple_connection_get_flags(PurpleConnection
*gc
)
308 PurpleConnectionPrivate
*priv
= NULL
;
310 g_return_val_if_fail(PURPLE_IS_CONNECTION(gc
), 0);
312 priv
= purple_connection_get_instance_private(gc
);
317 purple_connection_is_disconnecting(PurpleConnection
*gc
)
319 PurpleConnectionPrivate
*priv
= NULL
;
321 g_return_val_if_fail(PURPLE_IS_CONNECTION(gc
), TRUE
);
323 priv
= purple_connection_get_instance_private(gc
);
324 return priv
->is_finalizing
;
328 purple_connection_get_account(PurpleConnection
*gc
)
330 PurpleConnectionPrivate
*priv
= NULL
;
332 g_return_val_if_fail(PURPLE_IS_CONNECTION(gc
), NULL
);
334 priv
= purple_connection_get_instance_private(gc
);
335 return priv
->account
;
339 purple_connection_get_protocol(PurpleConnection
*gc
)
341 PurpleConnectionPrivate
*priv
= NULL
;
343 g_return_val_if_fail(PURPLE_IS_CONNECTION(gc
), NULL
);
345 priv
= purple_connection_get_instance_private(gc
);
346 return priv
->protocol
;
350 purple_connection_get_password(PurpleConnection
*gc
)
352 PurpleConnectionPrivate
*priv
= NULL
;
354 g_return_val_if_fail(PURPLE_IS_CONNECTION(gc
), NULL
);
356 priv
= purple_connection_get_instance_private(gc
);
357 return priv
->password
;
361 purple_connection_get_active_chats(PurpleConnection
*gc
)
363 PurpleConnectionPrivate
*priv
= NULL
;
365 g_return_val_if_fail(PURPLE_IS_CONNECTION(gc
), NULL
);
367 priv
= purple_connection_get_instance_private(gc
);
368 return priv
->active_chats
;
372 purple_connection_get_display_name(PurpleConnection
*gc
)
374 PurpleConnectionPrivate
*priv
= NULL
;
376 g_return_val_if_fail(PURPLE_IS_CONNECTION(gc
), NULL
);
378 priv
= purple_connection_get_instance_private(gc
);
379 return priv
->display_name
;
383 purple_connection_get_protocol_data(PurpleConnection
*gc
)
385 PurpleConnectionPrivate
*priv
= NULL
;
387 g_return_val_if_fail(PURPLE_IS_CONNECTION(gc
), NULL
);
389 priv
= purple_connection_get_instance_private(gc
);
390 return priv
->proto_data
;
394 _purple_connection_add_active_chat(PurpleConnection
*gc
, PurpleChatConversation
*chat
)
396 PurpleConnectionPrivate
*priv
= NULL
;
398 g_return_if_fail(PURPLE_IS_CONNECTION(gc
));
400 priv
= purple_connection_get_instance_private(gc
);
401 priv
->active_chats
= g_slist_append(priv
->active_chats
, chat
);
405 _purple_connection_remove_active_chat(PurpleConnection
*gc
, PurpleChatConversation
*chat
)
407 PurpleConnectionPrivate
*priv
= NULL
;
409 g_return_if_fail(PURPLE_IS_CONNECTION(gc
));
411 priv
= purple_connection_get_instance_private(gc
);
412 priv
->active_chats
= g_slist_remove(priv
->active_chats
, chat
);
416 _purple_connection_wants_to_die(PurpleConnection
*gc
)
418 PurpleConnectionPrivate
*priv
= NULL
;
420 g_return_val_if_fail(PURPLE_IS_CONNECTION(gc
), FALSE
);
422 priv
= purple_connection_get_instance_private(gc
);
423 return priv
->wants_to_die
;
427 purple_connection_update_progress(PurpleConnection
*gc
, const char *text
,
428 size_t step
, size_t count
)
430 PurpleConnectionUiOps
*ops
;
432 g_return_if_fail(PURPLE_IS_CONNECTION(gc
));
433 g_return_if_fail(text
!= NULL
);
434 g_return_if_fail(step
< count
);
435 g_return_if_fail(count
> 1);
437 ops
= purple_connections_get_ui_ops();
439 if (ops
!= NULL
&& ops
->connect_progress
!= NULL
)
440 ops
->connect_progress(gc
, text
, step
, count
);
444 purple_connection_notice(PurpleConnection
*gc
, const char *text
)
446 PurpleConnectionUiOps
*ops
;
448 g_return_if_fail(PURPLE_IS_CONNECTION(gc
));
449 g_return_if_fail(text
!= NULL
);
451 ops
= purple_connections_get_ui_ops();
453 if (ops
!= NULL
&& ops
->notice
!= NULL
)
454 ops
->notice(gc
, text
);
458 purple_connection_disconnect_cb(gpointer data
)
460 PurpleAccount
*account
;
461 PurpleConnection
*gc
;
464 gc
= purple_account_get_connection(account
);
466 if (PURPLE_IS_CONNECTION(gc
)) {
467 PurpleConnectionPrivate
*priv
;
468 priv
= purple_connection_get_instance_private(gc
);
469 priv
->disconnect_timeout
= 0;
472 purple_account_disconnect(account
);
477 purple_connection_error (PurpleConnection
*gc
,
478 PurpleConnectionError reason
,
479 const char *description
)
481 PurpleConnectionPrivate
*priv
= NULL
;
482 PurpleConnectionUiOps
*ops
;
484 g_return_if_fail(PURPLE_IS_CONNECTION(gc
));
485 priv
= purple_connection_get_instance_private(gc
);
487 /* This sanity check relies on PURPLE_CONNECTION_ERROR_OTHER_ERROR
488 * being the last member of the PurpleConnectionError enum in
489 * connection.h; if other reasons are added after it, this check should
492 if (reason
> PURPLE_CONNECTION_ERROR_OTHER_ERROR
) {
493 purple_debug_error("connection",
494 "purple_connection_error: reason %u isn't a "
495 "valid reason\n", reason
);
496 reason
= PURPLE_CONNECTION_ERROR_OTHER_ERROR
;
499 if (description
== NULL
) {
500 purple_debug_error("connection", "purple_connection_error called with NULL description\n");
501 description
= _("Unknown error");
504 /* If we've already got one error, we don't need any more */
505 if (purple_connection_get_error_info(gc
))
508 priv
->wants_to_die
= purple_connection_error_is_fatal (reason
);
510 purple_debug_info("connection", "Connection error on %p (reason: %u description: %s)\n",
511 gc
, reason
, description
);
513 ops
= purple_connections_get_ui_ops();
515 if (ops
&& ops
->report_disconnect
)
516 ops
->report_disconnect(gc
, reason
, description
);
518 priv
->error_info
= purple_connection_error_info_new(reason
, description
);
520 purple_signal_emit(purple_connections_get_handle(), "connection-error",
521 gc
, reason
, description
);
523 priv
->disconnect_timeout
= g_timeout_add(0, purple_connection_disconnect_cb
,
524 purple_connection_get_account(gc
));
527 PurpleConnectionErrorInfo
*
528 purple_connection_get_error_info(PurpleConnection
*gc
)
530 PurpleConnectionPrivate
*priv
= NULL
;
532 g_return_val_if_fail(PURPLE_IS_CONNECTION(gc
), NULL
);
534 priv
= purple_connection_get_instance_private(gc
);
535 return priv
->error_info
;
539 purple_connection_ssl_error (PurpleConnection
*gc
,
540 PurpleSslErrorType ssl_error
)
542 PurpleConnectionError reason
;
545 case PURPLE_SSL_HANDSHAKE_FAILED
:
546 reason
= PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR
;
548 case PURPLE_SSL_CONNECT_FAILED
:
549 reason
= PURPLE_CONNECTION_ERROR_NETWORK_ERROR
;
551 case PURPLE_SSL_CERTIFICATE_INVALID
:
552 /* TODO: maybe PURPLE_SSL_* should be more specific? */
553 reason
= PURPLE_CONNECTION_ERROR_CERT_OTHER_ERROR
;
556 g_assert_not_reached ();
557 reason
= PURPLE_CONNECTION_ERROR_CERT_OTHER_ERROR
;
560 purple_connection_error (gc
, reason
,
561 purple_ssl_strerror(ssl_error
));
565 purple_connection_g_error(PurpleConnection
*pc
, const GError
*error
)
567 PurpleConnectionError reason
;
569 if (g_error_matches(error
, G_IO_ERROR
, G_IO_ERROR_CANCELLED
)) {
570 /* Not a connection error. Ignore. */
574 if (error
->domain
== G_TLS_ERROR
) {
575 switch (error
->code
) {
576 case G_TLS_ERROR_UNAVAILABLE
:
577 reason
= PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT
;
579 case G_TLS_ERROR_NOT_TLS
:
580 case G_TLS_ERROR_HANDSHAKE
:
581 reason
= PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR
;
583 case G_TLS_ERROR_BAD_CERTIFICATE
:
584 case G_TLS_ERROR_CERTIFICATE_REQUIRED
:
585 reason
= PURPLE_CONNECTION_ERROR_CERT_OTHER_ERROR
;
587 case G_TLS_ERROR_EOF
:
588 case G_TLS_ERROR_MISC
:
590 reason
= PURPLE_CONNECTION_ERROR_NETWORK_ERROR
;
592 } else if (error
->domain
== G_IO_ERROR
) {
593 reason
= PURPLE_CONNECTION_ERROR_NETWORK_ERROR
;
594 } else if (error
->domain
== PURPLE_CONNECTION_ERROR
) {
595 reason
= error
->code
;
597 reason
= PURPLE_CONNECTION_ERROR_OTHER_ERROR
;
600 purple_connection_error(pc
, reason
, error
->message
);
604 purple_connection_take_error(PurpleConnection
*pc
, GError
*error
)
606 purple_connection_g_error(pc
, error
);
611 purple_connection_error_is_fatal (PurpleConnectionError reason
)
615 case PURPLE_CONNECTION_ERROR_NETWORK_ERROR
:
616 case PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR
:
618 case PURPLE_CONNECTION_ERROR_INVALID_USERNAME
:
619 case PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED
:
620 case PURPLE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE
:
621 case PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT
:
622 case PURPLE_CONNECTION_ERROR_NAME_IN_USE
:
623 case PURPLE_CONNECTION_ERROR_INVALID_SETTINGS
:
624 case PURPLE_CONNECTION_ERROR_OTHER_ERROR
:
625 case PURPLE_CONNECTION_ERROR_CERT_NOT_PROVIDED
:
626 case PURPLE_CONNECTION_ERROR_CERT_UNTRUSTED
:
627 case PURPLE_CONNECTION_ERROR_CERT_EXPIRED
:
628 case PURPLE_CONNECTION_ERROR_CERT_NOT_ACTIVATED
:
629 case PURPLE_CONNECTION_ERROR_CERT_HOSTNAME_MISMATCH
:
630 case PURPLE_CONNECTION_ERROR_CERT_FINGERPRINT_MISMATCH
:
631 case PURPLE_CONNECTION_ERROR_CERT_SELF_SIGNED
:
632 case PURPLE_CONNECTION_ERROR_CERT_OTHER_ERROR
:
635 g_return_val_if_reached(TRUE
);
639 void purple_connection_update_last_received(PurpleConnection
*gc
)
641 PurpleConnectionPrivate
*priv
= NULL
;
643 g_return_if_fail(PURPLE_IS_CONNECTION(gc
));
644 priv
= purple_connection_get_instance_private(gc
);
647 * For safety, actually this function shouldn't be called when the
648 * keepalive mechanism is inactive.
650 if (priv
->keepalive
) {
651 purple_timeout_reset(priv
->keepalive
, purple_protocol_server_iface_get_keepalive_interval(priv
->protocol
));
655 static PurpleConnectionErrorInfo
*
656 purple_connection_error_info_new(PurpleConnectionError type
,
657 const gchar
*description
)
659 PurpleConnectionErrorInfo
*err
;
661 g_return_val_if_fail(description
!= NULL
, NULL
);
663 err
= g_new(PurpleConnectionErrorInfo
, 1);
666 err
->description
= g_strdup(description
);
671 /**************************************************************************
673 **************************************************************************/
674 static PurpleConnectionUiOps
*
675 purple_connection_ui_ops_copy(PurpleConnectionUiOps
*ops
)
677 PurpleConnectionUiOps
*ops_new
;
679 g_return_val_if_fail(ops
!= NULL
, NULL
);
681 ops_new
= g_new(PurpleConnectionUiOps
, 1);
688 purple_connection_ui_ops_get_type(void)
690 static GType type
= 0;
693 type
= g_boxed_type_register_static("PurpleConnectionUiOps",
694 (GBoxedCopyFunc
)purple_connection_ui_ops_copy
,
695 (GBoxedFreeFunc
)g_free
);
701 static PurpleConnectionErrorInfo
*
702 purple_connection_error_info_copy(PurpleConnectionErrorInfo
*err
)
704 g_return_val_if_fail(err
!= NULL
, NULL
);
706 return purple_connection_error_info_new(err
->type
, err
->description
);
710 purple_connection_error_info_free(PurpleConnectionErrorInfo
*err
)
712 g_return_if_fail(err
!= NULL
);
714 g_free(err
->description
);
719 purple_connection_error_info_get_type(void)
721 static GType type
= 0;
724 type
= g_boxed_type_register_static("PurpleConnectionErrorInfo",
725 (GBoxedCopyFunc
)purple_connection_error_info_copy
,
726 (GBoxedFreeFunc
)purple_connection_error_info_free
);
732 /**************************************************************************
734 **************************************************************************/
736 /* Set method for GObject properties */
738 purple_connection_set_property(GObject
*obj
, guint param_id
, const GValue
*value
,
741 PurpleConnection
*gc
= PURPLE_CONNECTION(obj
);
742 PurpleConnectionPrivate
*priv
= purple_connection_get_instance_private(gc
);
746 priv
->protocol
= g_value_get_object(value
);
749 purple_connection_set_flags(gc
, g_value_get_flags(value
));
752 purple_connection_set_state(gc
, g_value_get_enum(value
));
755 priv
->account
= g_value_get_object(value
);
758 g_free(priv
->password
);
759 priv
->password
= g_value_dup_string(value
);
761 case PROP_DISPLAY_NAME
:
762 purple_connection_set_display_name(gc
, g_value_get_string(value
));
765 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
770 /* Get method for GObject properties */
772 purple_connection_get_property(GObject
*obj
, guint param_id
, GValue
*value
,
775 PurpleConnection
*gc
= PURPLE_CONNECTION(obj
);
779 g_value_set_object(value
, purple_connection_get_protocol(gc
));
782 g_value_set_flags(value
, purple_connection_get_flags(gc
));
785 g_value_set_enum(value
, purple_connection_get_state(gc
));
788 g_value_set_object(value
, purple_connection_get_account(gc
));
791 g_value_set_string(value
, purple_connection_get_password(gc
));
793 case PROP_DISPLAY_NAME
:
794 g_value_set_string(value
, purple_connection_get_display_name(gc
));
797 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
802 /* GObject initialization function */
804 purple_connection_init(PurpleConnection
*gc
)
806 purple_connection_set_state(gc
, PURPLE_CONNECTION_CONNECTING
);
807 connections
= g_list_append(connections
, gc
);
810 /* Called when done constructing */
812 purple_connection_constructed(GObject
*object
)
814 PurpleConnection
*gc
= PURPLE_CONNECTION(object
);
815 PurpleAccount
*account
;
817 G_OBJECT_CLASS(purple_connection_parent_class
)->constructed(object
);
819 g_object_get(gc
, "account", &account
, NULL
);
820 purple_account_set_connection(account
, gc
);
821 g_object_unref(account
);
823 purple_signal_emit(purple_connections_get_handle(), "signing-on", gc
);
826 /* GObject finalize function */
828 purple_connection_finalize(GObject
*object
)
830 PurpleConnection
*gc
= PURPLE_CONNECTION(object
);
831 PurpleConnectionPrivate
*priv
= purple_connection_get_instance_private(gc
);
832 PurpleAccount
*account
;
834 gboolean remove
= FALSE
;
836 priv
->is_finalizing
= TRUE
;
838 account
= purple_connection_get_account(gc
);
840 purple_debug_info("connection", "Disconnecting connection %p\n", gc
);
842 if (purple_connection_get_state(gc
) != PURPLE_CONNECTION_CONNECTING
)
845 purple_signal_emit(purple_connections_get_handle(), "signing-off", gc
);
847 while (priv
->active_chats
)
849 PurpleChatConversation
*b
= priv
->active_chats
->data
;
851 priv
->active_chats
= g_slist_remove(priv
->active_chats
, b
);
852 purple_chat_conversation_leave(b
);
855 update_keepalive(gc
, FALSE
);
857 purple_protocol_class_close(priv
->protocol
, gc
);
859 /* Clear out the proto data that was freed in the protocol's close method */
860 buddies
= purple_blist_find_buddies(account
, NULL
);
861 while (buddies
!= NULL
) {
862 PurpleBuddy
*buddy
= buddies
->data
;
863 purple_buddy_set_protocol_data(buddy
, NULL
);
864 buddies
= g_slist_delete_link(buddies
, buddies
);
867 purple_http_conn_cancel_all(gc
);
868 purple_proxy_connect_cancel_with_handle(gc
);
870 connections
= g_list_remove(connections
, gc
);
872 purple_connection_set_state(gc
, PURPLE_CONNECTION_DISCONNECTED
);
875 purple_blist_remove_account(account
);
877 purple_signal_emit(purple_connections_get_handle(), "signed-off", gc
);
879 purple_account_request_close_with_account(account
);
880 purple_request_close_with_handle(gc
);
881 purple_notify_close_with_handle(gc
);
883 purple_debug_info("connection", "Destroying connection %p\n", gc
);
885 purple_account_set_connection(account
, NULL
);
887 if (priv
->error_info
)
888 purple_connection_error_info_free(priv
->error_info
);
890 if (priv
->disconnect_timeout
> 0)
891 g_source_remove(priv
->disconnect_timeout
);
893 purple_str_wipe(priv
->password
);
894 g_free(priv
->display_name
);
896 G_OBJECT_CLASS(purple_connection_parent_class
)->finalize(object
);
899 /* Class initializer function */
900 static void purple_connection_class_init(PurpleConnectionClass
*klass
)
902 GObjectClass
*obj_class
= G_OBJECT_CLASS(klass
);
904 obj_class
->finalize
= purple_connection_finalize
;
905 obj_class
->constructed
= purple_connection_constructed
;
907 /* Setup properties */
908 obj_class
->get_property
= purple_connection_get_property
;
909 obj_class
->set_property
= purple_connection_set_property
;
911 properties
[PROP_PROTOCOL
] = g_param_spec_object("protocol", "Protocol",
912 "The protocol that the connection is using.",
913 PURPLE_TYPE_PROTOCOL
,
914 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
915 G_PARAM_STATIC_STRINGS
);
917 properties
[PROP_FLAGS
] = g_param_spec_flags("flags", "Connection flags",
918 "The flags of the connection.",
919 PURPLE_TYPE_CONNECTION_FLAGS
, 0,
920 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
922 properties
[PROP_STATE
] = g_param_spec_enum("state", "Connection state",
923 "The current state of the connection.",
924 PURPLE_TYPE_CONNECTION_STATE
, PURPLE_CONNECTION_DISCONNECTED
,
925 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
927 properties
[PROP_ACCOUNT
] = g_param_spec_object("account", "Account",
928 "The account using the connection.", PURPLE_TYPE_ACCOUNT
,
929 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
930 G_PARAM_STATIC_STRINGS
);
932 properties
[PROP_PASSWORD
] = g_param_spec_string("password", "Password",
933 "The password used for connection.", NULL
,
934 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
935 G_PARAM_STATIC_STRINGS
);
937 properties
[PROP_DISPLAY_NAME
] = g_param_spec_string("display-name",
939 "Your name that appears to other people.", NULL
,
940 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
942 g_object_class_install_properties(obj_class
, PROP_LAST
, properties
);
946 _purple_connection_new(PurpleAccount
*account
, gboolean regist
, const char *password
)
948 PurpleConnection
*gc
;
949 PurpleProtocol
*protocol
;
951 g_return_if_fail(PURPLE_IS_ACCOUNT(account
));
953 if (!purple_account_is_disconnected(account
))
956 protocol
= purple_protocols_find(purple_account_get_protocol_id(account
));
958 if (protocol
== NULL
) {
961 message
= g_strdup_printf(_("Missing protocol for %s"),
962 purple_account_get_username(account
));
963 purple_notify_error(NULL
, regist
? _("Registration Error") :
964 _("Connection Error"), message
, NULL
,
965 purple_request_cpar_from_account(account
));
972 if (!PURPLE_PROTOCOL_IMPLEMENTS(protocol
, SERVER
, register_user
))
977 if (((password
== NULL
) || (*password
== '\0')) &&
978 !(purple_protocol_get_options(protocol
) & OPT_PROTO_NO_PASSWORD
) &&
979 !(purple_protocol_get_options(protocol
) & OPT_PROTO_PASSWORD_OPTIONAL
))
981 purple_debug_error("connection", "Cannot connect to account %s without "
982 "a password.\n", purple_account_get_username(account
));
987 if (PURPLE_PROTOCOL_IMPLEMENTS(protocol
, FACTORY
, connection_new
))
988 gc
= purple_protocol_factory_iface_connection_new(protocol
, account
,
991 gc
= g_object_new(PURPLE_TYPE_CONNECTION
,
992 "protocol", protocol
,
994 "password", password
,
997 g_return_if_fail(gc
!= NULL
);
1001 PurpleConnectionPrivate
*priv
;
1002 purple_debug_info("connection", "Registering. gc = %p\n", gc
);
1004 /* set this so we don't auto-reconnect after registering */
1005 priv
= purple_connection_get_instance_private(gc
);
1006 priv
->wants_to_die
= TRUE
;
1008 purple_protocol_server_iface_register_user(protocol
, account
);
1012 purple_debug_info("connection", "Connecting. gc = %p\n", gc
);
1014 purple_signal_emit(purple_accounts_get_handle(), "account-connecting", account
);
1015 purple_protocol_class_login(protocol
, account
);
1020 _purple_connection_new_unregister(PurpleAccount
*account
, const char *password
,
1021 PurpleAccountUnregistrationCb cb
, void *user_data
)
1023 /* Lots of copy/pasted code to avoid API changes. You might want to integrate that into the previous function when posssible. */
1024 PurpleConnection
*gc
;
1025 PurpleProtocol
*protocol
;
1027 g_return_if_fail(PURPLE_IS_ACCOUNT(account
));
1029 protocol
= purple_protocols_find(purple_account_get_protocol_id(account
));
1031 if (protocol
== NULL
) {
1034 message
= g_strdup_printf(_("Missing protocol for %s"),
1035 purple_account_get_username(account
));
1036 purple_notify_error(NULL
, _("Unregistration Error"), message
,
1037 NULL
, purple_request_cpar_from_account(account
));
1042 if (!purple_account_is_disconnected(account
)) {
1043 purple_protocol_server_iface_unregister_user(protocol
, account
, cb
, user_data
);
1047 if (((password
== NULL
) || (*password
== '\0')) &&
1048 !(purple_protocol_get_options(protocol
) & OPT_PROTO_NO_PASSWORD
) &&
1049 !(purple_protocol_get_options(protocol
) & OPT_PROTO_PASSWORD_OPTIONAL
))
1051 purple_debug_error("connection", "Cannot connect to account %s without "
1052 "a password.\n", purple_account_get_username(account
));
1056 if (PURPLE_PROTOCOL_IMPLEMENTS(protocol
, FACTORY
, connection_new
))
1057 gc
= purple_protocol_factory_iface_connection_new(protocol
, account
,
1060 gc
= g_object_new(PURPLE_TYPE_CONNECTION
,
1061 "protocol", protocol
,
1063 "password", password
,
1066 g_return_if_fail(gc
!= NULL
);
1068 purple_debug_info("connection", "Unregistering. gc = %p\n", gc
);
1070 purple_protocol_server_iface_unregister_user(protocol
, account
, cb
, user_data
);
1073 /**************************************************************************
1075 **************************************************************************/
1078 _purple_assert_connection_is_valid(PurpleConnection
*gc
,
1079 const gchar
*file
, int line
)
1081 if (gc
&& g_list_find(purple_connections_get_all(), gc
))
1084 purple_debug_fatal("connection", "PURPLE_ASSERT_CONNECTION_IS_VALID(%p)"
1085 " failed at %s:%d", gc
, file
, line
);
1090 purple_connections_disconnect_all(void)
1093 PurpleConnection
*gc
;
1094 PurpleConnectionPrivate
*priv
;
1096 while ((l
= purple_connections_get_all()) != NULL
) {
1098 priv
= purple_connection_get_instance_private(gc
);
1099 priv
->wants_to_die
= TRUE
;
1100 purple_account_disconnect(priv
->account
);
1105 purple_connections_get_all(void)
1111 purple_connections_get_connecting(void)
1113 return connections_connecting
;
1117 purple_connections_set_ui_ops(PurpleConnectionUiOps
*ops
)
1119 connection_ui_ops
= ops
;
1122 PurpleConnectionUiOps
*
1123 purple_connections_get_ui_ops(void)
1125 return connection_ui_ops
;
1129 purple_connections_init(void)
1131 void *handle
= purple_connections_get_handle();
1133 purple_signal_register(handle
, "signing-on",
1134 purple_marshal_VOID__POINTER
, G_TYPE_NONE
, 1,
1135 PURPLE_TYPE_CONNECTION
);
1137 purple_signal_register(handle
, "signed-on",
1138 purple_marshal_VOID__POINTER
, G_TYPE_NONE
, 1,
1139 PURPLE_TYPE_CONNECTION
);
1141 purple_signal_register(handle
, "signing-off",
1142 purple_marshal_VOID__POINTER
, G_TYPE_NONE
, 1,
1143 PURPLE_TYPE_CONNECTION
);
1145 purple_signal_register(handle
, "signed-off",
1146 purple_marshal_VOID__POINTER
, G_TYPE_NONE
, 1,
1147 PURPLE_TYPE_CONNECTION
);
1149 purple_signal_register(handle
, "connection-error",
1150 purple_marshal_VOID__POINTER_INT_POINTER
,
1151 G_TYPE_NONE
, 3, PURPLE_TYPE_CONNECTION
,
1152 PURPLE_TYPE_CONNECTION_ERROR
, G_TYPE_STRING
);
1154 purple_signal_register(handle
, "autojoin",
1155 purple_marshal_BOOLEAN__POINTER
, G_TYPE_NONE
, 1,
1156 PURPLE_TYPE_CONNECTION
);
1161 purple_connections_uninit(void)
1163 purple_signals_unregister_by_instance(purple_connections_get_handle());
1167 purple_connections_get_handle(void)
1169 return &connections_handle
;