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 /* The #GTimeoutSource API doesn't expose a function to reset when a
652 * #GTimeoutSource will dispatch the next time, but because it works to
653 * directly call g_source_set_ready_time() on a #GTimeoutSource, and since
654 * it seems unlikely that the implementation will change, we just do that
655 * for now as a workaround for this API shortcoming.
657 gint64 seconds_from_now
= purple_protocol_server_iface_get_keepalive_interval(priv
->protocol
);
659 g_source_set_ready_time(
661 g_get_monotonic_time() + (seconds_from_now
* G_USEC_PER_SEC
)
666 static PurpleConnectionErrorInfo
*
667 purple_connection_error_info_new(PurpleConnectionError type
,
668 const gchar
*description
)
670 PurpleConnectionErrorInfo
*err
;
672 g_return_val_if_fail(description
!= NULL
, NULL
);
674 err
= g_new(PurpleConnectionErrorInfo
, 1);
677 err
->description
= g_strdup(description
);
682 /**************************************************************************
684 **************************************************************************/
685 static PurpleConnectionUiOps
*
686 purple_connection_ui_ops_copy(PurpleConnectionUiOps
*ops
)
688 PurpleConnectionUiOps
*ops_new
;
690 g_return_val_if_fail(ops
!= NULL
, NULL
);
692 ops_new
= g_new(PurpleConnectionUiOps
, 1);
699 purple_connection_ui_ops_get_type(void)
701 static GType type
= 0;
704 type
= g_boxed_type_register_static("PurpleConnectionUiOps",
705 (GBoxedCopyFunc
)purple_connection_ui_ops_copy
,
706 (GBoxedFreeFunc
)g_free
);
712 static PurpleConnectionErrorInfo
*
713 purple_connection_error_info_copy(PurpleConnectionErrorInfo
*err
)
715 g_return_val_if_fail(err
!= NULL
, NULL
);
717 return purple_connection_error_info_new(err
->type
, err
->description
);
721 purple_connection_error_info_free(PurpleConnectionErrorInfo
*err
)
723 g_return_if_fail(err
!= NULL
);
725 g_free(err
->description
);
730 purple_connection_error_info_get_type(void)
732 static GType type
= 0;
735 type
= g_boxed_type_register_static("PurpleConnectionErrorInfo",
736 (GBoxedCopyFunc
)purple_connection_error_info_copy
,
737 (GBoxedFreeFunc
)purple_connection_error_info_free
);
743 /**************************************************************************
745 **************************************************************************/
747 /* Set method for GObject properties */
749 purple_connection_set_property(GObject
*obj
, guint param_id
, const GValue
*value
,
752 PurpleConnection
*gc
= PURPLE_CONNECTION(obj
);
753 PurpleConnectionPrivate
*priv
= purple_connection_get_instance_private(gc
);
757 priv
->protocol
= g_value_get_object(value
);
760 purple_connection_set_flags(gc
, g_value_get_flags(value
));
763 purple_connection_set_state(gc
, g_value_get_enum(value
));
766 priv
->account
= g_value_get_object(value
);
769 g_free(priv
->password
);
770 priv
->password
= g_value_dup_string(value
);
772 case PROP_DISPLAY_NAME
:
773 purple_connection_set_display_name(gc
, g_value_get_string(value
));
776 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
781 /* Get method for GObject properties */
783 purple_connection_get_property(GObject
*obj
, guint param_id
, GValue
*value
,
786 PurpleConnection
*gc
= PURPLE_CONNECTION(obj
);
790 g_value_set_object(value
, purple_connection_get_protocol(gc
));
793 g_value_set_flags(value
, purple_connection_get_flags(gc
));
796 g_value_set_enum(value
, purple_connection_get_state(gc
));
799 g_value_set_object(value
, purple_connection_get_account(gc
));
802 g_value_set_string(value
, purple_connection_get_password(gc
));
804 case PROP_DISPLAY_NAME
:
805 g_value_set_string(value
, purple_connection_get_display_name(gc
));
808 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
813 /* GObject initialization function */
815 purple_connection_init(PurpleConnection
*gc
)
817 purple_connection_set_state(gc
, PURPLE_CONNECTION_CONNECTING
);
818 connections
= g_list_append(connections
, gc
);
821 /* Called when done constructing */
823 purple_connection_constructed(GObject
*object
)
825 PurpleConnection
*gc
= PURPLE_CONNECTION(object
);
826 PurpleAccount
*account
;
828 G_OBJECT_CLASS(purple_connection_parent_class
)->constructed(object
);
830 g_object_get(gc
, "account", &account
, NULL
);
831 purple_account_set_connection(account
, gc
);
832 g_object_unref(account
);
834 purple_signal_emit(purple_connections_get_handle(), "signing-on", gc
);
837 /* GObject finalize function */
839 purple_connection_finalize(GObject
*object
)
841 PurpleConnection
*gc
= PURPLE_CONNECTION(object
);
842 PurpleConnectionPrivate
*priv
= purple_connection_get_instance_private(gc
);
843 PurpleAccount
*account
;
845 gboolean remove
= FALSE
;
847 priv
->is_finalizing
= TRUE
;
849 account
= purple_connection_get_account(gc
);
851 purple_debug_info("connection", "Disconnecting connection %p\n", gc
);
853 if (purple_connection_get_state(gc
) != PURPLE_CONNECTION_CONNECTING
)
856 purple_signal_emit(purple_connections_get_handle(), "signing-off", gc
);
858 while (priv
->active_chats
)
860 PurpleChatConversation
*b
= priv
->active_chats
->data
;
862 priv
->active_chats
= g_slist_remove(priv
->active_chats
, b
);
863 purple_chat_conversation_leave(b
);
866 update_keepalive(gc
, FALSE
);
868 purple_protocol_class_close(priv
->protocol
, gc
);
870 /* Clear out the proto data that was freed in the protocol's close method */
871 buddies
= purple_blist_find_buddies(account
, NULL
);
872 while (buddies
!= NULL
) {
873 PurpleBuddy
*buddy
= buddies
->data
;
874 purple_buddy_set_protocol_data(buddy
, NULL
);
875 buddies
= g_slist_delete_link(buddies
, buddies
);
878 purple_http_conn_cancel_all(gc
);
879 purple_proxy_connect_cancel_with_handle(gc
);
881 connections
= g_list_remove(connections
, gc
);
883 purple_connection_set_state(gc
, PURPLE_CONNECTION_DISCONNECTED
);
886 purple_blist_remove_account(account
);
888 purple_signal_emit(purple_connections_get_handle(), "signed-off", gc
);
890 purple_account_request_close_with_account(account
);
891 purple_request_close_with_handle(gc
);
892 purple_notify_close_with_handle(gc
);
894 purple_debug_info("connection", "Destroying connection %p\n", gc
);
896 purple_account_set_connection(account
, NULL
);
898 if (priv
->error_info
)
899 purple_connection_error_info_free(priv
->error_info
);
901 if (priv
->disconnect_timeout
> 0)
902 g_source_remove(priv
->disconnect_timeout
);
904 purple_str_wipe(priv
->password
);
905 g_free(priv
->display_name
);
907 G_OBJECT_CLASS(purple_connection_parent_class
)->finalize(object
);
910 /* Class initializer function */
911 static void purple_connection_class_init(PurpleConnectionClass
*klass
)
913 GObjectClass
*obj_class
= G_OBJECT_CLASS(klass
);
915 obj_class
->finalize
= purple_connection_finalize
;
916 obj_class
->constructed
= purple_connection_constructed
;
918 /* Setup properties */
919 obj_class
->get_property
= purple_connection_get_property
;
920 obj_class
->set_property
= purple_connection_set_property
;
922 properties
[PROP_PROTOCOL
] = g_param_spec_object("protocol", "Protocol",
923 "The protocol that the connection is using.",
924 PURPLE_TYPE_PROTOCOL
,
925 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
926 G_PARAM_STATIC_STRINGS
);
928 properties
[PROP_FLAGS
] = g_param_spec_flags("flags", "Connection flags",
929 "The flags of the connection.",
930 PURPLE_TYPE_CONNECTION_FLAGS
, 0,
931 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
933 properties
[PROP_STATE
] = g_param_spec_enum("state", "Connection state",
934 "The current state of the connection.",
935 PURPLE_TYPE_CONNECTION_STATE
, PURPLE_CONNECTION_DISCONNECTED
,
936 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
938 properties
[PROP_ACCOUNT
] = g_param_spec_object("account", "Account",
939 "The account using the connection.", PURPLE_TYPE_ACCOUNT
,
940 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
941 G_PARAM_STATIC_STRINGS
);
943 properties
[PROP_PASSWORD
] = g_param_spec_string("password", "Password",
944 "The password used for connection.", NULL
,
945 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
946 G_PARAM_STATIC_STRINGS
);
948 properties
[PROP_DISPLAY_NAME
] = g_param_spec_string("display-name",
950 "Your name that appears to other people.", NULL
,
951 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
953 g_object_class_install_properties(obj_class
, PROP_LAST
, properties
);
957 _purple_connection_new(PurpleAccount
*account
, gboolean regist
, const char *password
)
959 PurpleConnection
*gc
;
960 PurpleProtocol
*protocol
;
962 g_return_if_fail(PURPLE_IS_ACCOUNT(account
));
964 if (!purple_account_is_disconnected(account
))
967 protocol
= purple_protocols_find(purple_account_get_protocol_id(account
));
969 if (protocol
== NULL
) {
972 message
= g_strdup_printf(_("Missing protocol for %s"),
973 purple_account_get_username(account
));
974 purple_notify_error(NULL
, regist
? _("Registration Error") :
975 _("Connection Error"), message
, NULL
,
976 purple_request_cpar_from_account(account
));
983 if (!PURPLE_PROTOCOL_IMPLEMENTS(protocol
, SERVER
, register_user
))
988 if (((password
== NULL
) || (*password
== '\0')) &&
989 !(purple_protocol_get_options(protocol
) & OPT_PROTO_NO_PASSWORD
) &&
990 !(purple_protocol_get_options(protocol
) & OPT_PROTO_PASSWORD_OPTIONAL
))
992 purple_debug_error("connection", "Cannot connect to account %s without "
993 "a password.\n", purple_account_get_username(account
));
998 if (PURPLE_PROTOCOL_IMPLEMENTS(protocol
, FACTORY
, connection_new
))
999 gc
= purple_protocol_factory_iface_connection_new(protocol
, account
,
1002 gc
= g_object_new(PURPLE_TYPE_CONNECTION
,
1003 "protocol", protocol
,
1005 "password", password
,
1008 g_return_if_fail(gc
!= NULL
);
1012 PurpleConnectionPrivate
*priv
;
1013 purple_debug_info("connection", "Registering. gc = %p\n", gc
);
1015 /* set this so we don't auto-reconnect after registering */
1016 priv
= purple_connection_get_instance_private(gc
);
1017 priv
->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
, 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_instance_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
;