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
= g_timeout_add_seconds(KEEPALIVE_INTERVAL
, send_keepalive
, gc
);
151 else if (!on
&& priv
->keepalive
> 0)
153 purple_debug_info("connection", "Deactivating keepalive.\n");
154 g_source_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 GDateTime
*dt
= g_date_time_new_from_unix_local(purple_presence_get_login_time(presence
));
210 purple_log_write(log
, PURPLE_MESSAGE_SYSTEM
,
211 purple_account_get_username(account
),
213 g_date_time_unref(dt
);
218 if (ops
!= NULL
&& ops
->connected
!= NULL
)
221 purple_blist_add_account(account
);
223 purple_signal_emit(purple_connections_get_handle(), "signed-on", gc
);
224 purple_signal_emit_return_1(purple_connections_get_handle(), "autojoin", gc
);
226 purple_serv_set_permit_deny(gc
);
228 update_keepalive(gc
, TRUE
);
230 else if (priv
->state
== PURPLE_CONNECTION_DISCONNECTED
) {
231 PurpleAccount
*account
= purple_connection_get_account(gc
);
233 if (purple_prefs_get_bool("/purple/logging/log_system"))
235 PurpleLog
*log
= purple_account_get_log(account
, FALSE
);
239 char *msg
= g_strdup_printf(_("+++ %s signed off"),
240 purple_account_get_username(account
));
241 GDateTime
*dt
= g_date_time_new_now_utc();
242 purple_log_write(log
, PURPLE_MESSAGE_SYSTEM
,
243 purple_account_get_username(account
),
245 g_date_time_unref(dt
);
250 purple_account_destroy_log(account
);
252 if (ops
!= NULL
&& ops
->disconnected
!= NULL
)
253 ops
->disconnected(gc
);
256 if (!priv
->is_finalizing
)
257 g_object_notify_by_pspec(G_OBJECT(gc
), properties
[PROP_STATE
]);
261 purple_connection_set_flags(PurpleConnection
*gc
, PurpleConnectionFlags flags
)
263 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
265 g_return_if_fail(priv
!= NULL
);
269 if (!priv
->is_finalizing
)
270 g_object_notify_by_pspec(G_OBJECT(gc
), properties
[PROP_FLAGS
]);
274 purple_connection_set_display_name(PurpleConnection
*gc
, const char *name
)
276 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
278 g_return_if_fail(priv
!= NULL
);
280 g_free(priv
->display_name
);
281 priv
->display_name
= g_strdup(name
);
283 g_object_notify_by_pspec(G_OBJECT(gc
), properties
[PROP_DISPLAY_NAME
]);
287 purple_connection_set_protocol_data(PurpleConnection
*gc
, void *proto_data
)
289 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
291 g_return_if_fail(priv
!= NULL
);
293 priv
->proto_data
= proto_data
;
296 PurpleConnectionState
297 purple_connection_get_state(const PurpleConnection
*gc
)
299 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
301 g_return_val_if_fail(priv
!= NULL
, PURPLE_CONNECTION_DISCONNECTED
);
306 PurpleConnectionFlags
307 purple_connection_get_flags(const PurpleConnection
*gc
)
309 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
311 g_return_val_if_fail(priv
!= NULL
, 0);
317 purple_connection_is_disconnecting(const PurpleConnection
*gc
)
319 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
321 g_return_val_if_fail(priv
!= NULL
, TRUE
);
323 return priv
->is_finalizing
;
327 purple_connection_get_account(const PurpleConnection
*gc
)
329 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
331 g_return_val_if_fail(priv
!= NULL
, NULL
);
333 return priv
->account
;
337 purple_connection_get_protocol(const PurpleConnection
*gc
)
339 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
341 g_return_val_if_fail(priv
!= NULL
, NULL
);
343 return priv
->protocol
;
347 purple_connection_get_password(const PurpleConnection
*gc
)
349 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
351 g_return_val_if_fail(priv
!= NULL
, NULL
);
353 return priv
->password
;
357 purple_connection_get_active_chats(const PurpleConnection
*gc
)
359 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
361 g_return_val_if_fail(priv
!= NULL
, NULL
);
363 return priv
->active_chats
;
367 purple_connection_get_display_name(const PurpleConnection
*gc
)
369 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
371 g_return_val_if_fail(priv
!= NULL
, NULL
);
373 return priv
->display_name
;
377 purple_connection_get_protocol_data(const PurpleConnection
*gc
)
379 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
381 g_return_val_if_fail(priv
!= NULL
, NULL
);
383 return priv
->proto_data
;
387 _purple_connection_add_active_chat(PurpleConnection
*gc
, PurpleChatConversation
*chat
)
389 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
391 g_return_if_fail(priv
!= NULL
);
393 priv
->active_chats
= g_slist_append(priv
->active_chats
, chat
);
397 _purple_connection_remove_active_chat(PurpleConnection
*gc
, PurpleChatConversation
*chat
)
399 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
401 g_return_if_fail(priv
!= NULL
);
403 priv
->active_chats
= g_slist_remove(priv
->active_chats
, chat
);
407 _purple_connection_wants_to_die(const PurpleConnection
*gc
)
409 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
411 g_return_val_if_fail(priv
!= NULL
, FALSE
);
413 return priv
->wants_to_die
;
417 purple_connection_update_progress(PurpleConnection
*gc
, const char *text
,
418 size_t step
, size_t count
)
420 PurpleConnectionUiOps
*ops
;
422 g_return_if_fail(PURPLE_IS_CONNECTION(gc
));
423 g_return_if_fail(text
!= NULL
);
424 g_return_if_fail(step
< count
);
425 g_return_if_fail(count
> 1);
427 ops
= purple_connections_get_ui_ops();
429 if (ops
!= NULL
&& ops
->connect_progress
!= NULL
)
430 ops
->connect_progress(gc
, text
, step
, count
);
434 purple_connection_notice(PurpleConnection
*gc
, const char *text
)
436 PurpleConnectionUiOps
*ops
;
438 g_return_if_fail(PURPLE_IS_CONNECTION(gc
));
439 g_return_if_fail(text
!= NULL
);
441 ops
= purple_connections_get_ui_ops();
443 if (ops
!= NULL
&& ops
->notice
!= NULL
)
444 ops
->notice(gc
, text
);
448 purple_connection_disconnect_cb(gpointer data
)
450 PurpleAccount
*account
;
451 PurpleConnection
*gc
;
452 PurpleConnectionPrivate
*priv
;
455 gc
= purple_account_get_connection(account
);
456 priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
459 priv
->disconnect_timeout
= 0;
461 purple_account_disconnect(account
);
466 purple_connection_error (PurpleConnection
*gc
,
467 PurpleConnectionError reason
,
468 const char *description
)
470 PurpleConnectionUiOps
*ops
;
471 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
473 g_return_if_fail(priv
!= NULL
);
474 /* This sanity check relies on PURPLE_CONNECTION_ERROR_OTHER_ERROR
475 * being the last member of the PurpleConnectionError enum in
476 * connection.h; if other reasons are added after it, this check should
479 if (reason
> PURPLE_CONNECTION_ERROR_OTHER_ERROR
) {
480 purple_debug_error("connection",
481 "purple_connection_error: reason %u isn't a "
482 "valid reason\n", reason
);
483 reason
= PURPLE_CONNECTION_ERROR_OTHER_ERROR
;
486 if (description
== NULL
) {
487 purple_debug_error("connection", "purple_connection_error called with NULL description\n");
488 description
= _("Unknown error");
491 /* If we've already got one error, we don't need any more */
492 if (purple_connection_get_error_info(gc
))
495 priv
->wants_to_die
= purple_connection_error_is_fatal (reason
);
497 purple_debug_info("connection", "Connection error on %p (reason: %u description: %s)\n",
498 gc
, reason
, description
);
500 ops
= purple_connections_get_ui_ops();
502 if (ops
&& ops
->report_disconnect
)
503 ops
->report_disconnect(gc
, reason
, description
);
505 priv
->error_info
= purple_connection_error_info_new(reason
, description
);
507 purple_signal_emit(purple_connections_get_handle(), "connection-error",
508 gc
, reason
, description
);
510 priv
->disconnect_timeout
= g_timeout_add(0, purple_connection_disconnect_cb
,
511 purple_connection_get_account(gc
));
514 PurpleConnectionErrorInfo
*
515 purple_connection_get_error_info(const PurpleConnection
*gc
)
517 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
519 g_return_val_if_fail(priv
!= NULL
, NULL
);
521 return priv
->error_info
;
525 purple_connection_ssl_error (PurpleConnection
*gc
,
526 PurpleSslErrorType ssl_error
)
528 PurpleConnectionError reason
;
531 case PURPLE_SSL_HANDSHAKE_FAILED
:
532 reason
= PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR
;
534 case PURPLE_SSL_CONNECT_FAILED
:
535 reason
= PURPLE_CONNECTION_ERROR_NETWORK_ERROR
;
537 case PURPLE_SSL_CERTIFICATE_INVALID
:
538 /* TODO: maybe PURPLE_SSL_* should be more specific? */
539 reason
= PURPLE_CONNECTION_ERROR_CERT_OTHER_ERROR
;
542 g_assert_not_reached ();
543 reason
= PURPLE_CONNECTION_ERROR_CERT_OTHER_ERROR
;
546 purple_connection_error (gc
, reason
,
547 purple_ssl_strerror(ssl_error
));
551 purple_connection_g_error(PurpleConnection
*pc
, const GError
*error
)
553 PurpleConnectionError reason
;
555 if (g_error_matches(error
, G_IO_ERROR
, G_IO_ERROR_CANCELLED
)) {
556 /* Not a connection error. Ignore. */
560 if (error
->domain
== G_TLS_ERROR
) {
561 switch (error
->code
) {
562 case G_TLS_ERROR_UNAVAILABLE
:
563 reason
= PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT
;
565 case G_TLS_ERROR_NOT_TLS
:
566 case G_TLS_ERROR_HANDSHAKE
:
567 reason
= PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR
;
569 case G_TLS_ERROR_BAD_CERTIFICATE
:
570 case G_TLS_ERROR_CERTIFICATE_REQUIRED
:
571 reason
= PURPLE_CONNECTION_ERROR_CERT_OTHER_ERROR
;
573 case G_TLS_ERROR_EOF
:
574 case G_TLS_ERROR_MISC
:
576 reason
= PURPLE_CONNECTION_ERROR_NETWORK_ERROR
;
578 } else if (error
->domain
== G_IO_ERROR
) {
579 reason
= PURPLE_CONNECTION_ERROR_NETWORK_ERROR
;
580 } else if (error
->domain
== PURPLE_CONNECTION_ERROR
) {
581 reason
= error
->code
;
583 reason
= PURPLE_CONNECTION_ERROR_OTHER_ERROR
;
586 purple_connection_error(pc
, reason
, error
->message
);
590 purple_connection_take_error(PurpleConnection
*pc
, GError
*error
)
592 purple_connection_g_error(pc
, error
);
597 purple_connection_error_is_fatal (PurpleConnectionError reason
)
601 case PURPLE_CONNECTION_ERROR_NETWORK_ERROR
:
602 case PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR
:
604 case PURPLE_CONNECTION_ERROR_INVALID_USERNAME
:
605 case PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED
:
606 case PURPLE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE
:
607 case PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT
:
608 case PURPLE_CONNECTION_ERROR_NAME_IN_USE
:
609 case PURPLE_CONNECTION_ERROR_INVALID_SETTINGS
:
610 case PURPLE_CONNECTION_ERROR_OTHER_ERROR
:
611 case PURPLE_CONNECTION_ERROR_CERT_NOT_PROVIDED
:
612 case PURPLE_CONNECTION_ERROR_CERT_UNTRUSTED
:
613 case PURPLE_CONNECTION_ERROR_CERT_EXPIRED
:
614 case PURPLE_CONNECTION_ERROR_CERT_NOT_ACTIVATED
:
615 case PURPLE_CONNECTION_ERROR_CERT_HOSTNAME_MISMATCH
:
616 case PURPLE_CONNECTION_ERROR_CERT_FINGERPRINT_MISMATCH
:
617 case PURPLE_CONNECTION_ERROR_CERT_SELF_SIGNED
:
618 case PURPLE_CONNECTION_ERROR_CERT_OTHER_ERROR
:
621 g_return_val_if_reached(TRUE
);
625 void purple_connection_update_last_received(PurpleConnection
*gc
)
627 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
629 g_return_if_fail(priv
!= NULL
);
631 priv
->last_received
= time(NULL
);
634 static PurpleConnectionErrorInfo
*
635 purple_connection_error_info_new(PurpleConnectionError type
,
636 const gchar
*description
)
638 PurpleConnectionErrorInfo
*err
;
640 g_return_val_if_fail(description
!= NULL
, NULL
);
642 err
= g_new(PurpleConnectionErrorInfo
, 1);
645 err
->description
= g_strdup(description
);
650 /**************************************************************************
652 **************************************************************************/
653 static PurpleConnectionUiOps
*
654 purple_connection_ui_ops_copy(PurpleConnectionUiOps
*ops
)
656 PurpleConnectionUiOps
*ops_new
;
658 g_return_val_if_fail(ops
!= NULL
, NULL
);
660 ops_new
= g_new(PurpleConnectionUiOps
, 1);
667 purple_connection_ui_ops_get_type(void)
669 static GType type
= 0;
672 type
= g_boxed_type_register_static("PurpleConnectionUiOps",
673 (GBoxedCopyFunc
)purple_connection_ui_ops_copy
,
674 (GBoxedFreeFunc
)g_free
);
680 static PurpleConnectionErrorInfo
*
681 purple_connection_error_info_copy(PurpleConnectionErrorInfo
*err
)
683 g_return_val_if_fail(err
!= NULL
, NULL
);
685 return purple_connection_error_info_new(err
->type
, err
->description
);
689 purple_connection_error_info_free(PurpleConnectionErrorInfo
*err
)
691 g_return_if_fail(err
!= NULL
);
693 g_free(err
->description
);
698 purple_connection_error_info_get_type(void)
700 static GType type
= 0;
703 type
= g_boxed_type_register_static("PurpleConnectionErrorInfo",
704 (GBoxedCopyFunc
)purple_connection_error_info_copy
,
705 (GBoxedFreeFunc
)purple_connection_error_info_free
);
711 /**************************************************************************
713 **************************************************************************/
715 /* Set method for GObject properties */
717 purple_connection_set_property(GObject
*obj
, guint param_id
, const GValue
*value
,
720 PurpleConnection
*gc
= PURPLE_CONNECTION(obj
);
721 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
725 priv
->protocol
= g_value_get_object(value
);
728 purple_connection_set_flags(gc
, g_value_get_flags(value
));
731 purple_connection_set_state(gc
, g_value_get_enum(value
));
734 priv
->account
= g_value_get_object(value
);
737 g_free(priv
->password
);
738 priv
->password
= g_strdup(g_value_get_string(value
));
740 case PROP_DISPLAY_NAME
:
741 purple_connection_set_display_name(gc
, g_value_get_string(value
));
744 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
749 /* Get method for GObject properties */
751 purple_connection_get_property(GObject
*obj
, guint param_id
, GValue
*value
,
754 PurpleConnection
*gc
= PURPLE_CONNECTION(obj
);
758 g_value_set_object(value
, purple_connection_get_protocol(gc
));
761 g_value_set_flags(value
, purple_connection_get_flags(gc
));
764 g_value_set_enum(value
, purple_connection_get_state(gc
));
767 g_value_set_object(value
, purple_connection_get_account(gc
));
770 g_value_set_string(value
, purple_connection_get_password(gc
));
772 case PROP_DISPLAY_NAME
:
773 g_value_set_string(value
, purple_connection_get_display_name(gc
));
776 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
781 /* GObject initialization function */
783 purple_connection_init(GTypeInstance
*instance
, gpointer klass
)
785 PurpleConnection
*gc
= PURPLE_CONNECTION(instance
);
787 purple_connection_set_state(gc
, PURPLE_CONNECTION_CONNECTING
);
788 connections
= g_list_append(connections
, gc
);
790 PURPLE_DBUS_REGISTER_POINTER(gc
, PurpleConnection
);
793 /* Called when done constructing */
795 purple_connection_constructed(GObject
*object
)
797 PurpleConnection
*gc
= PURPLE_CONNECTION(object
);
798 PurpleAccount
*account
;
800 G_OBJECT_CLASS(parent_class
)->constructed(object
);
802 g_object_get(gc
, "account", &account
, NULL
);
803 purple_account_set_connection(account
, gc
);
804 g_object_unref(account
);
806 purple_signal_emit(purple_connections_get_handle(), "signing-on", gc
);
809 /* GObject finalize function */
811 purple_connection_finalize(GObject
*object
)
813 PurpleConnection
*gc
= PURPLE_CONNECTION(object
);
814 PurpleConnectionPrivate
*priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
815 PurpleAccount
*account
;
817 gboolean remove
= FALSE
;
819 priv
->is_finalizing
= TRUE
;
821 account
= purple_connection_get_account(gc
);
823 purple_debug_info("connection", "Disconnecting connection %p\n", gc
);
825 if (purple_connection_get_state(gc
) != PURPLE_CONNECTION_CONNECTING
)
828 purple_signal_emit(purple_connections_get_handle(), "signing-off", gc
);
830 while (priv
->active_chats
)
832 PurpleChatConversation
*b
= priv
->active_chats
->data
;
834 priv
->active_chats
= g_slist_remove(priv
->active_chats
, b
);
835 purple_chat_conversation_leave(b
);
838 update_keepalive(gc
, FALSE
);
840 purple_protocol_class_close(priv
->protocol
, gc
);
842 /* Clear out the proto data that was freed in the protocol's close method */
843 buddies
= purple_blist_find_buddies(account
, NULL
);
844 while (buddies
!= NULL
) {
845 PurpleBuddy
*buddy
= buddies
->data
;
846 purple_buddy_set_protocol_data(buddy
, NULL
);
847 buddies
= g_slist_delete_link(buddies
, buddies
);
850 purple_http_conn_cancel_all(gc
);
851 purple_proxy_connect_cancel_with_handle(gc
);
853 connections
= g_list_remove(connections
, gc
);
855 purple_connection_set_state(gc
, PURPLE_CONNECTION_DISCONNECTED
);
858 purple_blist_remove_account(account
);
860 purple_signal_emit(purple_connections_get_handle(), "signed-off", gc
);
862 purple_account_request_close_with_account(account
);
863 purple_request_close_with_handle(gc
);
864 purple_notify_close_with_handle(gc
);
866 purple_debug_info("connection", "Destroying connection %p\n", gc
);
868 purple_account_set_connection(account
, NULL
);
870 if (priv
->error_info
)
871 purple_connection_error_info_free(priv
->error_info
);
873 if (priv
->disconnect_timeout
> 0)
874 g_source_remove(priv
->disconnect_timeout
);
876 purple_str_wipe(priv
->password
);
877 g_free(priv
->display_name
);
879 PURPLE_DBUS_UNREGISTER_POINTER(gc
);
881 G_OBJECT_CLASS(parent_class
)->finalize(object
);
884 /* Class initializer function */
885 static void purple_connection_class_init(PurpleConnectionClass
*klass
)
887 GObjectClass
*obj_class
= G_OBJECT_CLASS(klass
);
889 parent_class
= g_type_class_peek_parent(klass
);
891 obj_class
->finalize
= purple_connection_finalize
;
892 obj_class
->constructed
= purple_connection_constructed
;
894 /* Setup properties */
895 obj_class
->get_property
= purple_connection_get_property
;
896 obj_class
->set_property
= purple_connection_set_property
;
898 g_type_class_add_private(klass
, sizeof(PurpleConnectionPrivate
));
900 properties
[PROP_PROTOCOL
] = g_param_spec_object("protocol", "Protocol",
901 "The protocol that the connection is using.",
902 PURPLE_TYPE_PROTOCOL
,
903 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
904 G_PARAM_STATIC_STRINGS
);
906 properties
[PROP_FLAGS
] = g_param_spec_flags("flags", "Connection flags",
907 "The flags of the connection.",
908 PURPLE_TYPE_CONNECTION_FLAGS
, 0,
909 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
911 properties
[PROP_STATE
] = g_param_spec_enum("state", "Connection state",
912 "The current state of the connection.",
913 PURPLE_TYPE_CONNECTION_STATE
, PURPLE_CONNECTION_DISCONNECTED
,
914 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
916 properties
[PROP_ACCOUNT
] = g_param_spec_object("account", "Account",
917 "The account using the connection.", PURPLE_TYPE_ACCOUNT
,
918 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
919 G_PARAM_STATIC_STRINGS
);
921 properties
[PROP_PASSWORD
] = g_param_spec_string("password", "Password",
922 "The password used for connection.", NULL
,
923 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
924 G_PARAM_STATIC_STRINGS
);
926 properties
[PROP_DISPLAY_NAME
] = g_param_spec_string("display-name",
928 "Your name that appears to other people.", NULL
,
929 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
931 g_object_class_install_properties(obj_class
, PROP_LAST
, properties
);
935 purple_connection_get_type(void)
937 static GType type
= 0;
940 static const GTypeInfo info
= {
941 sizeof(PurpleConnectionClass
),
944 (GClassInitFunc
)purple_connection_class_init
,
947 sizeof(PurpleConnection
),
949 (GInstanceInitFunc
)purple_connection_init
,
953 type
= g_type_register_static(G_TYPE_OBJECT
, "PurpleConnection",
961 _purple_connection_new(PurpleAccount
*account
, gboolean regist
, const char *password
)
963 PurpleConnection
*gc
;
964 PurpleProtocol
*protocol
;
966 g_return_if_fail(PURPLE_IS_ACCOUNT(account
));
968 if (!purple_account_is_disconnected(account
))
971 protocol
= purple_protocols_find(purple_account_get_protocol_id(account
));
973 if (protocol
== NULL
) {
976 message
= g_strdup_printf(_("Missing protocol for %s"),
977 purple_account_get_username(account
));
978 purple_notify_error(NULL
, regist
? _("Registration Error") :
979 _("Connection Error"), message
, NULL
,
980 purple_request_cpar_from_account(account
));
987 if (!PURPLE_PROTOCOL_IMPLEMENTS(protocol
, SERVER_IFACE
, register_user
))
992 if (((password
== NULL
) || (*password
== '\0')) &&
993 !(purple_protocol_get_options(protocol
) & OPT_PROTO_NO_PASSWORD
) &&
994 !(purple_protocol_get_options(protocol
) & OPT_PROTO_PASSWORD_OPTIONAL
))
996 purple_debug_error("connection", "Cannot connect to account %s without "
997 "a password.\n", purple_account_get_username(account
));
1002 if (PURPLE_PROTOCOL_IMPLEMENTS(protocol
, FACTORY_IFACE
, connection_new
))
1003 gc
= purple_protocol_factory_iface_connection_new(protocol
, account
,
1006 gc
= g_object_new(PURPLE_TYPE_CONNECTION
,
1007 "protocol", protocol
,
1009 "password", password
,
1012 g_return_if_fail(gc
!= NULL
);
1016 purple_debug_info("connection", "Registering. gc = %p\n", gc
);
1018 /* set this so we don't auto-reconnect after registering */
1019 PURPLE_CONNECTION_GET_PRIVATE(gc
)->wants_to_die
= TRUE
;
1021 purple_protocol_server_iface_register_user(protocol
, account
);
1025 purple_debug_info("connection", "Connecting. gc = %p\n", gc
);
1027 purple_signal_emit(purple_accounts_get_handle(), "account-connecting", account
);
1028 purple_protocol_class_login(protocol
, account
);
1033 _purple_connection_new_unregister(PurpleAccount
*account
, const char *password
,
1034 PurpleAccountUnregistrationCb cb
, void *user_data
)
1036 /* Lots of copy/pasted code to avoid API changes. You might want to integrate that into the previous function when posssible. */
1037 PurpleConnection
*gc
;
1038 PurpleProtocol
*protocol
;
1040 g_return_if_fail(PURPLE_IS_ACCOUNT(account
));
1042 protocol
= purple_protocols_find(purple_account_get_protocol_id(account
));
1044 if (protocol
== NULL
) {
1047 message
= g_strdup_printf(_("Missing protocol for %s"),
1048 purple_account_get_username(account
));
1049 purple_notify_error(NULL
, _("Unregistration Error"), message
,
1050 NULL
, purple_request_cpar_from_account(account
));
1055 if (!purple_account_is_disconnected(account
)) {
1056 purple_protocol_server_iface_unregister_user(protocol
, account
, cb
, user_data
);
1060 if (((password
== NULL
) || (*password
== '\0')) &&
1061 !(purple_protocol_get_options(protocol
) & OPT_PROTO_NO_PASSWORD
) &&
1062 !(purple_protocol_get_options(protocol
) & OPT_PROTO_PASSWORD_OPTIONAL
))
1064 purple_debug_error("connection", "Cannot connect to account %s without "
1065 "a password.\n", purple_account_get_username(account
));
1069 if (PURPLE_PROTOCOL_IMPLEMENTS(protocol
, FACTORY_IFACE
, connection_new
))
1070 gc
= purple_protocol_factory_iface_connection_new(protocol
, account
,
1073 gc
= g_object_new(PURPLE_TYPE_CONNECTION
,
1074 "protocol", protocol
,
1076 "password", password
,
1079 g_return_if_fail(gc
!= NULL
);
1081 purple_debug_info("connection", "Unregistering. gc = %p\n", gc
);
1083 purple_protocol_server_iface_unregister_user(protocol
, account
, cb
, user_data
);
1086 /**************************************************************************
1088 **************************************************************************/
1091 _purple_assert_connection_is_valid(PurpleConnection
*gc
,
1092 const gchar
*file
, int line
)
1094 if (gc
&& g_list_find(purple_connections_get_all(), gc
))
1097 purple_debug_fatal("connection", "PURPLE_ASSERT_CONNECTION_IS_VALID(%p)"
1098 " failed at %s:%d", gc
, file
, line
);
1103 purple_connections_disconnect_all(void)
1106 PurpleConnection
*gc
;
1107 PurpleConnectionPrivate
*priv
;
1109 while ((l
= purple_connections_get_all()) != NULL
) {
1111 priv
= PURPLE_CONNECTION_GET_PRIVATE(gc
);
1112 priv
->wants_to_die
= TRUE
;
1113 purple_account_disconnect(priv
->account
);
1118 purple_connections_get_all(void)
1124 purple_connections_get_connecting(void)
1126 return connections_connecting
;
1130 purple_connections_set_ui_ops(PurpleConnectionUiOps
*ops
)
1132 connection_ui_ops
= ops
;
1135 PurpleConnectionUiOps
*
1136 purple_connections_get_ui_ops(void)
1138 return connection_ui_ops
;
1142 purple_connections_init(void)
1144 void *handle
= purple_connections_get_handle();
1146 purple_signal_register(handle
, "signing-on",
1147 purple_marshal_VOID__POINTER
, G_TYPE_NONE
, 1,
1148 PURPLE_TYPE_CONNECTION
);
1150 purple_signal_register(handle
, "signed-on",
1151 purple_marshal_VOID__POINTER
, G_TYPE_NONE
, 1,
1152 PURPLE_TYPE_CONNECTION
);
1154 purple_signal_register(handle
, "signing-off",
1155 purple_marshal_VOID__POINTER
, G_TYPE_NONE
, 1,
1156 PURPLE_TYPE_CONNECTION
);
1158 purple_signal_register(handle
, "signed-off",
1159 purple_marshal_VOID__POINTER
, G_TYPE_NONE
, 1,
1160 PURPLE_TYPE_CONNECTION
);
1162 purple_signal_register(handle
, "connection-error",
1163 purple_marshal_VOID__POINTER_INT_POINTER
,
1164 G_TYPE_NONE
, 3, PURPLE_TYPE_CONNECTION
,
1165 PURPLE_TYPE_CONNECTION_ERROR
, G_TYPE_STRING
);
1167 purple_signal_register(handle
, "autojoin",
1168 purple_marshal_BOOLEAN__POINTER
, G_TYPE_NONE
, 1,
1169 PURPLE_TYPE_CONNECTION
);
1174 purple_connections_uninit(void)
1176 purple_signals_unregister_by_instance(purple_connections_get_handle());
1180 purple_connections_get_handle(void)
1182 return &connections_handle
;