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
21 #define _PURPLE_CONNECTION_C_
24 #include "glibcompat.h"
27 #include "buddylist.h"
28 #include "connection.h"
29 #include "dbus-maybe.h"
42 G_DEFINE_QUARK(purple
-connection
-error
-quark
, purple_connection_error
);
44 #define KEEPALIVE_INTERVAL 30
46 #define PURPLE_CONNECTION_GET_PRIVATE(obj) \
47 (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_CONNECTION, PurpleConnectionPrivate))
49 typedef struct _PurpleConnectionPrivate PurpleConnectionPrivate
;
51 /* Private data for a connection */
52 struct _PurpleConnectionPrivate
54 PurpleProtocol
*protocol
; /* The protocol. */
55 PurpleConnectionFlags flags
; /* Connection flags. */
57 PurpleConnectionState state
; /* The connection state. */
59 PurpleAccount
*account
; /* The account being connected to. */
60 char *password
; /* The password used. */
62 GSList
*active_chats
; /* A list of active chats
63 (#PurpleChatConversation structs). */
65 /* TODO Remove this and use protocol-specific subclasses. */
66 void *proto_data
; /* Protocol-specific data. */
68 char *display_name
; /* How you appear to other people. */
69 guint keepalive
; /* Keep-alive. */
71 /* Wants to Die state. This is set when the user chooses to log out, or
72 * when the protocol is disconnected and should not be automatically
73 * reconnected (incorrect password, etc.). Protocols should rely on
74 * purple_connection_error() to set this for them rather than
75 * setting it themselves.
76 * See purple_connection_error_is_fatal()
78 gboolean wants_to_die
;
80 gboolean is_finalizing
; /* The object is being destroyed. */
82 /* The connection error and its description if an error occured */
83 PurpleConnectionErrorInfo
*error_info
;
85 guint disconnect_timeout
; /* Timer used for nasty stack tricks */
86 time_t last_received
; /* When we last received a packet. Set by the
87 protocols to avoid sending unneeded keepalives */
90 /* GObject property enums */
103 static GObjectClass
*parent_class
;
104 static GParamSpec
*properties
[PROP_LAST
];
106 static GList
*connections
= NULL
;
107 static GList
*connections_connecting
= NULL
;
108 static PurpleConnectionUiOps
*connection_ui_ops
= NULL
;
110 static int connections_handle
;
112 static PurpleConnectionErrorInfo
*
113 purple_connection_error_info_new(PurpleConnectionError type
,
114 const gchar
*description
);
116 /**************************************************************************
118 **************************************************************************/
120 send_keepalive(gpointer data
)
122 PurpleConnection
*gc
= data
;
123 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
125 /* Only send keep-alives if we haven't heard from the
128 if ((time(NULL
) - priv
->last_received
) < KEEPALIVE_INTERVAL
)
131 purple_protocol_server_iface_keepalive(priv
->protocol
, gc
);
137 update_keepalive(PurpleConnection
*gc
, gboolean on
)
139 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
141 g_return_if_fail(priv
!= NULL
);
143 if (!PURPLE_PROTOCOL_IMPLEMENTS(priv
->protocol
, SERVER_IFACE
, keepalive
))
146 if (on
&& !priv
->keepalive
)
148 purple_debug_info("connection", "Activating keepalive.\n");
149 priv
->keepalive
= purple_timeout_add_seconds(KEEPALIVE_INTERVAL
, send_keepalive
, gc
);
151 else if (!on
&& priv
->keepalive
> 0)
153 purple_debug_info("connection", "Deactivating keepalive.\n");
154 purple_timeout_remove(priv
->keepalive
);
170 purple_connection_set_state(PurpleConnection
*gc
, PurpleConnectionState state
)
172 PurpleConnectionUiOps
*ops
;
173 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
175 g_return_if_fail(priv
!= NULL
);
177 if (priv
->state
== state
)
182 ops
= purple_connections_get_ui_ops();
184 if (priv
->state
== PURPLE_CONNECTION_CONNECTING
) {
185 connections_connecting
= g_list_append(connections_connecting
, gc
);
188 connections_connecting
= g_list_remove(connections_connecting
, gc
);
191 if (priv
->state
== PURPLE_CONNECTION_CONNECTED
) {
192 PurpleAccount
*account
;
193 PurplePresence
*presence
;
195 account
= purple_connection_get_account(gc
);
196 presence
= purple_account_get_presence(account
);
198 /* Set the time the account came online */
199 purple_presence_set_login_time(presence
, time(NULL
));
201 if (purple_prefs_get_bool("/purple/logging/log_system"))
203 PurpleLog
*log
= purple_account_get_log(account
, TRUE
);
207 char *msg
= g_strdup_printf(_("+++ %s signed on"),
208 purple_account_get_username(account
));
209 purple_log_write(log
, PURPLE_MESSAGE_SYSTEM
,
210 purple_account_get_username(account
),
211 purple_presence_get_login_time(presence
),
217 if (ops
!= NULL
&& ops
->connected
!= NULL
)
220 purple_blist_add_account(account
);
222 purple_signal_emit(purple_connections_get_handle(), "signed-on", gc
);
223 purple_signal_emit_return_1(purple_connections_get_handle(), "autojoin", gc
);
225 purple_serv_set_permit_deny(gc
);
227 update_keepalive(gc
, TRUE
);
229 else if (priv
->state
== PURPLE_CONNECTION_DISCONNECTED
) {
230 PurpleAccount
*account
= purple_connection_get_account(gc
);
232 if (purple_prefs_get_bool("/purple/logging/log_system"))
234 PurpleLog
*log
= purple_account_get_log(account
, FALSE
);
238 char *msg
= g_strdup_printf(_("+++ %s signed off"),
239 purple_account_get_username(account
));
240 purple_log_write(log
, PURPLE_MESSAGE_SYSTEM
,
241 purple_account_get_username(account
), time(NULL
),
247 purple_account_destroy_log(account
);
249 if (ops
!= NULL
&& ops
->disconnected
!= NULL
)
250 ops
->disconnected(gc
);
253 if (!priv
->is_finalizing
)
254 g_object_notify_by_pspec(G_OBJECT(gc
), properties
[PROP_STATE
]);
258 purple_connection_set_flags(PurpleConnection
*gc
, PurpleConnectionFlags flags
)
260 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
262 g_return_if_fail(priv
!= NULL
);
266 if (!priv
->is_finalizing
)
267 g_object_notify_by_pspec(G_OBJECT(gc
), properties
[PROP_FLAGS
]);
271 purple_connection_set_display_name(PurpleConnection
*gc
, const char *name
)
273 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
275 g_return_if_fail(priv
!= NULL
);
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
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
288 g_return_if_fail(priv
!= NULL
);
290 priv
->proto_data
= proto_data
;
293 PurpleConnectionState
294 purple_connection_get_state(const PurpleConnection
*gc
)
296 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
298 g_return_val_if_fail(priv
!= NULL
, PURPLE_CONNECTION_DISCONNECTED
);
303 PurpleConnectionFlags
304 purple_connection_get_flags(const PurpleConnection
*gc
)
306 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
308 g_return_val_if_fail(priv
!= NULL
, 0);
314 purple_connection_is_disconnecting(const PurpleConnection
*gc
)
316 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
318 g_return_val_if_fail(priv
!= NULL
, TRUE
);
320 return priv
->is_finalizing
;
324 purple_connection_get_account(const PurpleConnection
*gc
)
326 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
328 g_return_val_if_fail(priv
!= NULL
, NULL
);
330 return priv
->account
;
334 purple_connection_get_protocol(const PurpleConnection
*gc
)
336 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
338 g_return_val_if_fail(priv
!= NULL
, NULL
);
340 return priv
->protocol
;
344 purple_connection_get_password(const PurpleConnection
*gc
)
346 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
348 g_return_val_if_fail(priv
!= NULL
, NULL
);
350 return priv
->password
;
354 purple_connection_get_active_chats(const PurpleConnection
*gc
)
356 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
358 g_return_val_if_fail(priv
!= NULL
, NULL
);
360 return priv
->active_chats
;
364 purple_connection_get_display_name(const PurpleConnection
*gc
)
366 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
368 g_return_val_if_fail(priv
!= NULL
, NULL
);
370 return priv
->display_name
;
374 purple_connection_get_protocol_data(const PurpleConnection
*gc
)
376 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
378 g_return_val_if_fail(priv
!= NULL
, NULL
);
380 return priv
->proto_data
;
384 _purple_connection_add_active_chat(PurpleConnection
*gc
, PurpleChatConversation
*chat
)
386 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
388 g_return_if_fail(priv
!= NULL
);
390 priv
->active_chats
= g_slist_append(priv
->active_chats
, chat
);
394 _purple_connection_remove_active_chat(PurpleConnection
*gc
, PurpleChatConversation
*chat
)
396 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
398 g_return_if_fail(priv
!= NULL
);
400 priv
->active_chats
= g_slist_remove(priv
->active_chats
, chat
);
404 _purple_connection_wants_to_die(const PurpleConnection
*gc
)
406 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
408 g_return_val_if_fail(priv
!= NULL
, FALSE
);
410 return priv
->wants_to_die
;
414 purple_connection_update_progress(PurpleConnection
*gc
, const char *text
,
415 size_t step
, size_t count
)
417 PurpleConnectionUiOps
*ops
;
419 g_return_if_fail(PURPLE_IS_CONNECTION(gc
));
420 g_return_if_fail(text
!= NULL
);
421 g_return_if_fail(step
< count
);
422 g_return_if_fail(count
> 1);
424 ops
= purple_connections_get_ui_ops();
426 if (ops
!= NULL
&& ops
->connect_progress
!= NULL
)
427 ops
->connect_progress(gc
, text
, step
, count
);
431 purple_connection_notice(PurpleConnection
*gc
, const char *text
)
433 PurpleConnectionUiOps
*ops
;
435 g_return_if_fail(PURPLE_IS_CONNECTION(gc
));
436 g_return_if_fail(text
!= NULL
);
438 ops
= purple_connections_get_ui_ops();
440 if (ops
!= NULL
&& ops
->notice
!= NULL
)
441 ops
->notice(gc
, text
);
445 purple_connection_disconnect_cb(gpointer data
)
447 PurpleAccount
*account
;
448 PurpleConnection
*gc
;
449 PurpleConnectionPrivate
*priv
;
452 gc
= purple_account_get_connection(account
);
453 priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
456 priv
->disconnect_timeout
= 0;
458 purple_account_disconnect(account
);
463 purple_connection_error (PurpleConnection
*gc
,
464 PurpleConnectionError reason
,
465 const char *description
)
467 PurpleConnectionUiOps
*ops
;
468 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
470 g_return_if_fail(priv
!= NULL
);
471 /* This sanity check relies on PURPLE_CONNECTION_ERROR_OTHER_ERROR
472 * being the last member of the PurpleConnectionError enum in
473 * connection.h; if other reasons are added after it, this check should
476 if (reason
> PURPLE_CONNECTION_ERROR_OTHER_ERROR
) {
477 purple_debug_error("connection",
478 "purple_connection_error: reason %u isn't a "
479 "valid reason\n", reason
);
480 reason
= PURPLE_CONNECTION_ERROR_OTHER_ERROR
;
483 if (description
== NULL
) {
484 purple_debug_error("connection", "purple_connection_error called with NULL description\n");
485 description
= _("Unknown error");
488 /* If we've already got one error, we don't need any more */
489 if (purple_connection_get_error_info(gc
))
492 priv
->wants_to_die
= purple_connection_error_is_fatal (reason
);
494 purple_debug_info("connection", "Connection error on %p (reason: %u description: %s)\n",
495 gc
, reason
, description
);
497 ops
= purple_connections_get_ui_ops();
499 if (ops
&& ops
->report_disconnect
)
500 ops
->report_disconnect(gc
, reason
, description
);
502 priv
->error_info
= purple_connection_error_info_new(reason
, description
);
504 purple_signal_emit(purple_connections_get_handle(), "connection-error",
505 gc
, reason
, description
);
507 priv
->disconnect_timeout
= purple_timeout_add(0, purple_connection_disconnect_cb
,
508 purple_connection_get_account(gc
));
511 PurpleConnectionErrorInfo
*
512 purple_connection_get_error_info(const PurpleConnection
*gc
)
514 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
516 g_return_val_if_fail(priv
!= NULL
, NULL
);
518 return priv
->error_info
;
522 purple_connection_ssl_error (PurpleConnection
*gc
,
523 PurpleSslErrorType ssl_error
)
525 PurpleConnectionError reason
;
528 case PURPLE_SSL_HANDSHAKE_FAILED
:
529 reason
= PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR
;
531 case PURPLE_SSL_CONNECT_FAILED
:
532 reason
= PURPLE_CONNECTION_ERROR_NETWORK_ERROR
;
534 case PURPLE_SSL_CERTIFICATE_INVALID
:
535 /* TODO: maybe PURPLE_SSL_* should be more specific? */
536 reason
= PURPLE_CONNECTION_ERROR_CERT_OTHER_ERROR
;
539 g_assert_not_reached ();
540 reason
= PURPLE_CONNECTION_ERROR_CERT_OTHER_ERROR
;
543 purple_connection_error (gc
, reason
,
544 purple_ssl_strerror(ssl_error
));
548 purple_connection_g_error(PurpleConnection
*pc
, const GError
*error
)
550 PurpleConnectionError reason
;
552 if (g_error_matches(error
, G_IO_ERROR
, G_IO_ERROR_CANCELLED
)) {
553 /* Not a connection error. Ignore. */
557 if (error
->domain
== G_TLS_ERROR
) {
558 switch (error
->code
) {
559 case G_TLS_ERROR_UNAVAILABLE
:
560 reason
= PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT
;
562 case G_TLS_ERROR_NOT_TLS
:
563 case G_TLS_ERROR_HANDSHAKE
:
564 reason
= PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR
;
566 case G_TLS_ERROR_BAD_CERTIFICATE
:
567 case G_TLS_ERROR_CERTIFICATE_REQUIRED
:
568 reason
= PURPLE_CONNECTION_ERROR_CERT_OTHER_ERROR
;
570 case G_TLS_ERROR_EOF
:
571 case G_TLS_ERROR_MISC
:
573 reason
= PURPLE_CONNECTION_ERROR_NETWORK_ERROR
;
575 } else if (error
->domain
== G_IO_ERROR
) {
576 reason
= PURPLE_CONNECTION_ERROR_NETWORK_ERROR
;
577 } else if (error
->domain
== PURPLE_CONNECTION_ERROR
) {
578 reason
= error
->code
;
580 reason
= PURPLE_CONNECTION_ERROR_OTHER_ERROR
;
583 purple_connection_error(pc
, reason
, error
->message
);
587 purple_connection_take_error(PurpleConnection
*pc
, GError
*error
)
589 purple_connection_g_error(pc
, error
);
594 purple_connection_error_is_fatal (PurpleConnectionError reason
)
598 case PURPLE_CONNECTION_ERROR_NETWORK_ERROR
:
599 case PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR
:
601 case PURPLE_CONNECTION_ERROR_INVALID_USERNAME
:
602 case PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED
:
603 case PURPLE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE
:
604 case PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT
:
605 case PURPLE_CONNECTION_ERROR_NAME_IN_USE
:
606 case PURPLE_CONNECTION_ERROR_INVALID_SETTINGS
:
607 case PURPLE_CONNECTION_ERROR_OTHER_ERROR
:
608 case PURPLE_CONNECTION_ERROR_CERT_NOT_PROVIDED
:
609 case PURPLE_CONNECTION_ERROR_CERT_UNTRUSTED
:
610 case PURPLE_CONNECTION_ERROR_CERT_EXPIRED
:
611 case PURPLE_CONNECTION_ERROR_CERT_NOT_ACTIVATED
:
612 case PURPLE_CONNECTION_ERROR_CERT_HOSTNAME_MISMATCH
:
613 case PURPLE_CONNECTION_ERROR_CERT_FINGERPRINT_MISMATCH
:
614 case PURPLE_CONNECTION_ERROR_CERT_SELF_SIGNED
:
615 case PURPLE_CONNECTION_ERROR_CERT_OTHER_ERROR
:
618 g_return_val_if_reached(TRUE
);
622 void purple_connection_update_last_received(PurpleConnection
*gc
)
624 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
626 g_return_if_fail(priv
!= NULL
);
628 priv
->last_received
= time(NULL
);
631 static PurpleConnectionErrorInfo
*
632 purple_connection_error_info_new(PurpleConnectionError type
,
633 const gchar
*description
)
635 PurpleConnectionErrorInfo
*err
;
637 g_return_val_if_fail(description
!= NULL
, NULL
);
639 err
= g_new(PurpleConnectionErrorInfo
, 1);
642 err
->description
= g_strdup(description
);
647 /**************************************************************************
649 **************************************************************************/
650 static PurpleConnectionUiOps
*
651 purple_connection_ui_ops_copy(PurpleConnectionUiOps
*ops
)
653 PurpleConnectionUiOps
*ops_new
;
655 g_return_val_if_fail(ops
!= NULL
, NULL
);
657 ops_new
= g_new(PurpleConnectionUiOps
, 1);
664 purple_connection_ui_ops_get_type(void)
666 static GType type
= 0;
669 type
= g_boxed_type_register_static("PurpleConnectionUiOps",
670 (GBoxedCopyFunc
)purple_connection_ui_ops_copy
,
671 (GBoxedFreeFunc
)g_free
);
677 static PurpleConnectionErrorInfo
*
678 purple_connection_error_info_copy(PurpleConnectionErrorInfo
*err
)
680 g_return_val_if_fail(err
!= NULL
, NULL
);
682 return purple_connection_error_info_new(err
->type
, err
->description
);
686 purple_connection_error_info_free(PurpleConnectionErrorInfo
*err
)
688 g_return_if_fail(err
!= NULL
);
690 g_free(err
->description
);
695 purple_connection_error_info_get_type(void)
697 static GType type
= 0;
700 type
= g_boxed_type_register_static("PurpleConnectionErrorInfo",
701 (GBoxedCopyFunc
)purple_connection_error_info_copy
,
702 (GBoxedFreeFunc
)purple_connection_error_info_free
);
708 /**************************************************************************
710 **************************************************************************/
712 /* Set method for GObject properties */
714 purple_connection_set_property(GObject
*obj
, guint param_id
, const GValue
*value
,
717 PurpleConnection
*gc
= PURPLE_CONNECTION(obj
);
718 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
722 priv
->protocol
= g_value_get_object(value
);
725 purple_connection_set_flags(gc
, g_value_get_flags(value
));
728 purple_connection_set_state(gc
, g_value_get_enum(value
));
731 priv
->account
= g_value_get_object(value
);
734 g_free(priv
->password
);
735 priv
->password
= g_strdup(g_value_get_string(value
));
737 case PROP_DISPLAY_NAME
:
738 purple_connection_set_display_name(gc
, g_value_get_string(value
));
741 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
746 /* Get method for GObject properties */
748 purple_connection_get_property(GObject
*obj
, guint param_id
, GValue
*value
,
751 PurpleConnection
*gc
= PURPLE_CONNECTION(obj
);
755 g_value_set_object(value
, purple_connection_get_protocol(gc
));
758 g_value_set_flags(value
, purple_connection_get_flags(gc
));
761 g_value_set_enum(value
, purple_connection_get_state(gc
));
764 g_value_set_object(value
, purple_connection_get_account(gc
));
767 g_value_set_string(value
, purple_connection_get_password(gc
));
769 case PROP_DISPLAY_NAME
:
770 g_value_set_string(value
, purple_connection_get_display_name(gc
));
773 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
778 /* GObject initialization function */
780 purple_connection_init(GTypeInstance
*instance
, gpointer klass
)
782 PurpleConnection
*gc
= PURPLE_CONNECTION(instance
);
784 purple_connection_set_state(gc
, PURPLE_CONNECTION_CONNECTING
);
785 connections
= g_list_append(connections
, gc
);
787 PURPLE_DBUS_REGISTER_POINTER(gc
, PurpleConnection
);
790 /* Called when done constructing */
792 purple_connection_constructed(GObject
*object
)
794 PurpleConnection
*gc
= PURPLE_CONNECTION(object
);
795 PurpleAccount
*account
;
797 G_OBJECT_CLASS(parent_class
)->constructed(object
);
799 g_object_get(gc
, "account", &account
, NULL
);
800 purple_account_set_connection(account
, gc
);
801 g_object_unref(account
);
803 purple_signal_emit(purple_connections_get_handle(), "signing-on", gc
);
806 /* GObject finalize function */
808 purple_connection_finalize(GObject
*object
)
810 PurpleConnection
*gc
= PURPLE_CONNECTION(object
);
811 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
812 PurpleAccount
*account
;
814 gboolean remove
= FALSE
;
816 priv
->is_finalizing
= TRUE
;
818 account
= purple_connection_get_account(gc
);
820 purple_debug_info("connection", "Disconnecting connection %p\n", gc
);
822 if (purple_connection_get_state(gc
) != PURPLE_CONNECTION_CONNECTING
)
825 purple_signal_emit(purple_connections_get_handle(), "signing-off", gc
);
827 while (priv
->active_chats
)
829 PurpleChatConversation
*b
= priv
->active_chats
->data
;
831 priv
->active_chats
= g_slist_remove(priv
->active_chats
, b
);
832 purple_chat_conversation_leave(b
);
835 update_keepalive(gc
, FALSE
);
837 purple_protocol_class_close(priv
->protocol
, gc
);
839 /* Clear out the proto data that was freed in the protocol's close method */
840 buddies
= purple_blist_find_buddies(account
, NULL
);
841 while (buddies
!= NULL
) {
842 PurpleBuddy
*buddy
= buddies
->data
;
843 purple_buddy_set_protocol_data(buddy
, NULL
);
844 buddies
= g_slist_delete_link(buddies
, buddies
);
847 purple_http_conn_cancel_all(gc
);
848 _purple_socket_cancel_with_connection(gc
);
849 purple_proxy_connect_cancel_with_handle(gc
);
851 connections
= g_list_remove(connections
, gc
);
853 purple_connection_set_state(gc
, PURPLE_CONNECTION_DISCONNECTED
);
856 purple_blist_remove_account(account
);
858 purple_signal_emit(purple_connections_get_handle(), "signed-off", gc
);
860 purple_account_request_close_with_account(account
);
861 purple_request_close_with_handle(gc
);
862 purple_notify_close_with_handle(gc
);
864 purple_debug_info("connection", "Destroying connection %p\n", gc
);
866 purple_account_set_connection(account
, NULL
);
868 if (priv
->error_info
)
869 purple_connection_error_info_free(priv
->error_info
);
871 if (priv
->disconnect_timeout
> 0)
872 purple_timeout_remove(priv
->disconnect_timeout
);
874 purple_str_wipe(priv
->password
);
875 g_free(priv
->display_name
);
877 PURPLE_DBUS_UNREGISTER_POINTER(gc
);
879 G_OBJECT_CLASS(parent_class
)->finalize(object
);
882 /* Class initializer function */
883 static void purple_connection_class_init(PurpleConnectionClass
*klass
)
885 GObjectClass
*obj_class
= G_OBJECT_CLASS(klass
);
887 parent_class
= g_type_class_peek_parent(klass
);
889 obj_class
->finalize
= purple_connection_finalize
;
890 obj_class
->constructed
= purple_connection_constructed
;
892 /* Setup properties */
893 obj_class
->get_property
= purple_connection_get_property
;
894 obj_class
->set_property
= purple_connection_set_property
;
896 g_type_class_add_private(klass
, sizeof(PurpleConnectionPrivate
));
898 properties
[PROP_PROTOCOL
] = g_param_spec_object("protocol", "Protocol",
899 "The protocol that the connection is using.",
900 PURPLE_TYPE_PROTOCOL
,
901 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
902 G_PARAM_STATIC_STRINGS
);
904 properties
[PROP_FLAGS
] = g_param_spec_flags("flags", "Connection flags",
905 "The flags of the connection.",
906 PURPLE_TYPE_CONNECTION_FLAGS
, 0,
907 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
909 properties
[PROP_STATE
] = g_param_spec_enum("state", "Connection state",
910 "The current state of the connection.",
911 PURPLE_TYPE_CONNECTION_STATE
, PURPLE_CONNECTION_DISCONNECTED
,
912 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
914 properties
[PROP_ACCOUNT
] = g_param_spec_object("account", "Account",
915 "The account using the connection.", PURPLE_TYPE_ACCOUNT
,
916 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
917 G_PARAM_STATIC_STRINGS
);
919 properties
[PROP_PASSWORD
] = g_param_spec_string("password", "Password",
920 "The password used for connection.", NULL
,
921 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
922 G_PARAM_STATIC_STRINGS
);
924 properties
[PROP_DISPLAY_NAME
] = g_param_spec_string("display-name",
926 "Your name that appears to other people.", NULL
,
927 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
929 g_object_class_install_properties(obj_class
, PROP_LAST
, properties
);
933 purple_connection_get_type(void)
935 static GType type
= 0;
938 static const GTypeInfo info
= {
939 sizeof(PurpleConnectionClass
),
942 (GClassInitFunc
)purple_connection_class_init
,
945 sizeof(PurpleConnection
),
947 (GInstanceInitFunc
)purple_connection_init
,
951 type
= g_type_register_static(G_TYPE_OBJECT
, "PurpleConnection",
959 _purple_connection_new(PurpleAccount
*account
, gboolean regist
, const char *password
)
961 PurpleConnection
*gc
;
962 PurpleProtocol
*protocol
;
964 g_return_if_fail(PURPLE_IS_ACCOUNT(account
));
966 if (!purple_account_is_disconnected(account
))
969 protocol
= purple_protocols_find(purple_account_get_protocol_id(account
));
971 if (protocol
== NULL
) {
974 message
= g_strdup_printf(_("Missing protocol for %s"),
975 purple_account_get_username(account
));
976 purple_notify_error(NULL
, regist
? _("Registration Error") :
977 _("Connection Error"), message
, NULL
,
978 purple_request_cpar_from_account(account
));
985 if (!PURPLE_PROTOCOL_IMPLEMENTS(protocol
, SERVER_IFACE
, register_user
))
990 if (((password
== NULL
) || (*password
== '\0')) &&
991 !(purple_protocol_get_options(protocol
) & OPT_PROTO_NO_PASSWORD
) &&
992 !(purple_protocol_get_options(protocol
) & OPT_PROTO_PASSWORD_OPTIONAL
))
994 purple_debug_error("connection", "Cannot connect to account %s without "
995 "a password.\n", purple_account_get_username(account
));
1000 if (PURPLE_PROTOCOL_IMPLEMENTS(protocol
, FACTORY_IFACE
, connection_new
))
1001 gc
= purple_protocol_factory_iface_connection_new(protocol
, account
,
1004 gc
= g_object_new(PURPLE_TYPE_CONNECTION
,
1005 "protocol", protocol
,
1007 "password", password
,
1010 g_return_if_fail(gc
!= NULL
);
1014 purple_debug_info("connection", "Registering. gc = %p\n", gc
);
1016 /* set this so we don't auto-reconnect after registering */
1017 PURPLE_CONNECTION_GET_PRIVATE(gc
)->wants_to_die
= TRUE
;
1019 purple_protocol_server_iface_register_user(protocol
, account
);
1023 purple_debug_info("connection", "Connecting. gc = %p\n", gc
);
1025 purple_signal_emit(purple_accounts_get_handle(), "account-connecting", account
);
1026 purple_protocol_class_login(protocol
, account
);
1031 _purple_connection_new_unregister(PurpleAccount
*account
, const char *password
,
1032 PurpleAccountUnregistrationCb cb
, void *user_data
)
1034 /* Lots of copy/pasted code to avoid API changes. You might want to integrate that into the previous function when posssible. */
1035 PurpleConnection
*gc
;
1036 PurpleProtocol
*protocol
;
1038 g_return_if_fail(PURPLE_IS_ACCOUNT(account
));
1040 protocol
= purple_protocols_find(purple_account_get_protocol_id(account
));
1042 if (protocol
== NULL
) {
1045 message
= g_strdup_printf(_("Missing protocol for %s"),
1046 purple_account_get_username(account
));
1047 purple_notify_error(NULL
, _("Unregistration Error"), message
,
1048 NULL
, purple_request_cpar_from_account(account
));
1053 if (!purple_account_is_disconnected(account
)) {
1054 purple_protocol_server_iface_unregister_user(protocol
, account
, cb
, user_data
);
1058 if (((password
== NULL
) || (*password
== '\0')) &&
1059 !(purple_protocol_get_options(protocol
) & OPT_PROTO_NO_PASSWORD
) &&
1060 !(purple_protocol_get_options(protocol
) & OPT_PROTO_PASSWORD_OPTIONAL
))
1062 purple_debug_error("connection", "Cannot connect to account %s without "
1063 "a password.\n", purple_account_get_username(account
));
1067 if (PURPLE_PROTOCOL_IMPLEMENTS(protocol
, FACTORY_IFACE
, connection_new
))
1068 gc
= purple_protocol_factory_iface_connection_new(protocol
, account
,
1071 gc
= g_object_new(PURPLE_TYPE_CONNECTION
,
1072 "protocol", protocol
,
1074 "password", password
,
1077 g_return_if_fail(gc
!= NULL
);
1079 purple_debug_info("connection", "Unregistering. gc = %p\n", gc
);
1081 purple_protocol_server_iface_unregister_user(protocol
, account
, cb
, user_data
);
1084 /**************************************************************************
1086 **************************************************************************/
1089 _purple_assert_connection_is_valid(PurpleConnection
*gc
,
1090 const gchar
*file
, int line
)
1092 if (gc
&& g_list_find(purple_connections_get_all(), gc
))
1095 purple_debug_fatal("connection", "PURPLE_ASSERT_CONNECTION_IS_VALID(%p)"
1096 " failed at %s:%d", gc
, file
, line
);
1101 purple_connections_disconnect_all(void)
1104 PurpleConnection
*gc
;
1105 PurpleConnectionPrivate
*priv
;
1107 while ((l
= purple_connections_get_all()) != NULL
) {
1109 priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
1110 priv
->wants_to_die
= TRUE
;
1111 purple_account_disconnect(priv
->account
);
1116 purple_connections_get_all(void)
1122 purple_connections_get_connecting(void)
1124 return connections_connecting
;
1128 purple_connections_set_ui_ops(PurpleConnectionUiOps
*ops
)
1130 connection_ui_ops
= ops
;
1133 PurpleConnectionUiOps
*
1134 purple_connections_get_ui_ops(void)
1136 return connection_ui_ops
;
1140 purple_connections_init(void)
1142 void *handle
= purple_connections_get_handle();
1144 purple_signal_register(handle
, "signing-on",
1145 purple_marshal_VOID__POINTER
, G_TYPE_NONE
, 1,
1146 PURPLE_TYPE_CONNECTION
);
1148 purple_signal_register(handle
, "signed-on",
1149 purple_marshal_VOID__POINTER
, G_TYPE_NONE
, 1,
1150 PURPLE_TYPE_CONNECTION
);
1152 purple_signal_register(handle
, "signing-off",
1153 purple_marshal_VOID__POINTER
, G_TYPE_NONE
, 1,
1154 PURPLE_TYPE_CONNECTION
);
1156 purple_signal_register(handle
, "signed-off",
1157 purple_marshal_VOID__POINTER
, G_TYPE_NONE
, 1,
1158 PURPLE_TYPE_CONNECTION
);
1160 purple_signal_register(handle
, "connection-error",
1161 purple_marshal_VOID__POINTER_INT_POINTER
,
1162 G_TYPE_NONE
, 3, PURPLE_TYPE_CONNECTION
,
1163 PURPLE_TYPE_CONNECTION_ERROR
, G_TYPE_STRING
);
1165 purple_signal_register(handle
, "autojoin",
1166 purple_marshal_BOOLEAN__POINTER
, G_TYPE_NONE
, 1,
1167 PURPLE_TYPE_CONNECTION
);
1172 purple_connections_uninit(void)
1174 purple_signals_unregister_by_instance(purple_connections_get_handle());
1178 purple_connections_get_handle(void)
1180 return &connections_handle
;