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"
39 G_DEFINE_QUARK(purple
-connection
-error
-quark
, purple_connection_error
);
44 * Represents an active connection on an account.
46 struct _PurpleConnection
51 /* Private data for a connection */
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 GSource
*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 } PurpleConnectionPrivate
;
88 /* GObject property enums */
101 static GParamSpec
*properties
[PROP_LAST
];
103 static GList
*connections
= NULL
;
104 static GList
*connections_connecting
= NULL
;
105 static PurpleConnectionUiOps
*connection_ui_ops
= NULL
;
107 static int connections_handle
;
109 static PurpleConnectionErrorInfo
*
110 purple_connection_error_info_new(PurpleConnectionError type
,
111 const gchar
*description
);
113 G_DEFINE_TYPE_WITH_PRIVATE(PurpleConnection
, purple_connection
, G_TYPE_OBJECT
)
115 /**************************************************************************
117 **************************************************************************/
119 send_keepalive(gpointer data
)
121 PurpleConnection
*gc
= data
;
122 PurpleConnectionPrivate
*priv
= purple_connection_get_instance_private(gc
);
124 purple_protocol_server_iface_keepalive(priv
->protocol
, gc
);
130 update_keepalive(PurpleConnection
*gc
, gboolean on
)
132 PurpleConnectionPrivate
*priv
= purple_connection_get_instance_private(gc
);
134 if (!PURPLE_PROTOCOL_IMPLEMENTS(priv
->protocol
, SERVER
, keepalive
))
137 if (on
&& !priv
->keepalive
)
139 int interval
= purple_protocol_server_iface_get_keepalive_interval(priv
->protocol
);
140 purple_debug_info("connection", "Activating keepalive to %d seconds.", interval
);
141 priv
->keepalive
= g_main_context_find_source_by_id(NULL
, g_timeout_add_seconds(interval
, send_keepalive
, gc
));
143 else if (!on
&& priv
->keepalive
)
145 purple_debug_info("connection", "Deactivating keepalive.\n");
146 g_source_destroy(priv
->keepalive
);
147 priv
->keepalive
= NULL
;
162 purple_connection_set_state(PurpleConnection
*gc
, PurpleConnectionState state
)
164 PurpleConnectionPrivate
*priv
= NULL
;
165 PurpleConnectionUiOps
*ops
;
167 g_return_if_fail(PURPLE_IS_CONNECTION(gc
));
169 priv
= purple_connection_get_instance_private(gc
);
171 if (priv
->state
== state
)
176 ops
= purple_connections_get_ui_ops();
178 if (priv
->state
== PURPLE_CONNECTION_CONNECTING
) {
179 connections_connecting
= g_list_append(connections_connecting
, gc
);
182 connections_connecting
= g_list_remove(connections_connecting
, gc
);
185 if (priv
->state
== PURPLE_CONNECTION_CONNECTED
) {
186 PurpleAccount
*account
;
187 PurplePresence
*presence
;
189 account
= purple_connection_get_account(gc
);
190 presence
= purple_account_get_presence(account
);
192 /* Set the time the account came online */
193 purple_presence_set_login_time(presence
, time(NULL
));
195 if (purple_prefs_get_bool("/purple/logging/log_system"))
197 PurpleLog
*log
= purple_account_get_log(account
, TRUE
);
201 char *msg
= g_strdup_printf(_("+++ %s signed on"),
202 purple_account_get_username(account
));
203 GDateTime
*dt
= g_date_time_new_from_unix_local(purple_presence_get_login_time(presence
));
204 purple_log_write(log
, PURPLE_MESSAGE_SYSTEM
,
205 purple_account_get_username(account
),
207 g_date_time_unref(dt
);
212 if (ops
!= NULL
&& ops
->connected
!= NULL
)
215 purple_blist_add_account(account
);
217 purple_signal_emit(purple_connections_get_handle(), "signed-on", gc
);
218 purple_signal_emit_return_1(purple_connections_get_handle(), "autojoin", gc
);
220 purple_serv_set_permit_deny(gc
);
222 update_keepalive(gc
, TRUE
);
224 else if (priv
->state
== PURPLE_CONNECTION_DISCONNECTED
) {
225 PurpleAccount
*account
= purple_connection_get_account(gc
);
227 if (purple_prefs_get_bool("/purple/logging/log_system"))
229 PurpleLog
*log
= purple_account_get_log(account
, FALSE
);
233 char *msg
= g_strdup_printf(_("+++ %s signed off"),
234 purple_account_get_username(account
));
235 GDateTime
*dt
= g_date_time_new_now_utc();
236 purple_log_write(log
, PURPLE_MESSAGE_SYSTEM
,
237 purple_account_get_username(account
),
239 g_date_time_unref(dt
);
244 purple_account_destroy_log(account
);
246 if (ops
!= NULL
&& ops
->disconnected
!= NULL
)
247 ops
->disconnected(gc
);
250 if (!priv
->is_finalizing
)
251 g_object_notify_by_pspec(G_OBJECT(gc
), properties
[PROP_STATE
]);
255 purple_connection_set_flags(PurpleConnection
*gc
, PurpleConnectionFlags flags
)
257 PurpleConnectionPrivate
*priv
= NULL
;
259 g_return_if_fail(PURPLE_IS_CONNECTION(gc
));
261 priv
= purple_connection_get_instance_private(gc
);
264 if (!priv
->is_finalizing
)
265 g_object_notify_by_pspec(G_OBJECT(gc
), properties
[PROP_FLAGS
]);
269 purple_connection_set_display_name(PurpleConnection
*gc
, const char *name
)
271 PurpleConnectionPrivate
*priv
= NULL
;
273 g_return_if_fail(PURPLE_IS_CONNECTION(gc
));
275 priv
= purple_connection_get_instance_private(gc
);
276 g_free(priv
->display_name
);
277 priv
->display_name
= g_strdup(name
);
279 g_object_notify_by_pspec(G_OBJECT(gc
), properties
[PROP_DISPLAY_NAME
]);
283 purple_connection_set_protocol_data(PurpleConnection
*gc
, void *proto_data
)
285 PurpleConnectionPrivate
*priv
= NULL
;
287 g_return_if_fail(PURPLE_IS_CONNECTION(gc
));
289 priv
= purple_connection_get_instance_private(gc
);
290 priv
->proto_data
= proto_data
;
293 PurpleConnectionState
294 purple_connection_get_state(PurpleConnection
*gc
)
296 PurpleConnectionPrivate
*priv
= NULL
;
298 g_return_val_if_fail(PURPLE_IS_CONNECTION(gc
), PURPLE_CONNECTION_DISCONNECTED
);
300 priv
= purple_connection_get_instance_private(gc
);
304 PurpleConnectionFlags
305 purple_connection_get_flags(PurpleConnection
*gc
)
307 PurpleConnectionPrivate
*priv
= NULL
;
309 g_return_val_if_fail(PURPLE_IS_CONNECTION(gc
), 0);
311 priv
= purple_connection_get_instance_private(gc
);
316 purple_connection_is_disconnecting(PurpleConnection
*gc
)
318 PurpleConnectionPrivate
*priv
= NULL
;
320 g_return_val_if_fail(PURPLE_IS_CONNECTION(gc
), TRUE
);
322 priv
= purple_connection_get_instance_private(gc
);
323 return priv
->is_finalizing
;
327 purple_connection_get_account(PurpleConnection
*gc
)
329 PurpleConnectionPrivate
*priv
= NULL
;
331 g_return_val_if_fail(PURPLE_IS_CONNECTION(gc
), NULL
);
333 priv
= purple_connection_get_instance_private(gc
);
334 return priv
->account
;
338 purple_connection_get_protocol(PurpleConnection
*gc
)
340 PurpleConnectionPrivate
*priv
= NULL
;
342 g_return_val_if_fail(PURPLE_IS_CONNECTION(gc
), NULL
);
344 priv
= purple_connection_get_instance_private(gc
);
345 return priv
->protocol
;
349 purple_connection_get_password(PurpleConnection
*gc
)
351 PurpleConnectionPrivate
*priv
= NULL
;
353 g_return_val_if_fail(PURPLE_IS_CONNECTION(gc
), NULL
);
355 priv
= purple_connection_get_instance_private(gc
);
356 return priv
->password
;
360 purple_connection_get_active_chats(PurpleConnection
*gc
)
362 PurpleConnectionPrivate
*priv
= NULL
;
364 g_return_val_if_fail(PURPLE_IS_CONNECTION(gc
), NULL
);
366 priv
= purple_connection_get_instance_private(gc
);
367 return priv
->active_chats
;
371 purple_connection_get_display_name(PurpleConnection
*gc
)
373 PurpleConnectionPrivate
*priv
= NULL
;
375 g_return_val_if_fail(PURPLE_IS_CONNECTION(gc
), NULL
);
377 priv
= purple_connection_get_instance_private(gc
);
378 return priv
->display_name
;
382 purple_connection_get_protocol_data(PurpleConnection
*gc
)
384 PurpleConnectionPrivate
*priv
= NULL
;
386 g_return_val_if_fail(PURPLE_IS_CONNECTION(gc
), NULL
);
388 priv
= purple_connection_get_instance_private(gc
);
389 return priv
->proto_data
;
393 _purple_connection_add_active_chat(PurpleConnection
*gc
, PurpleChatConversation
*chat
)
395 PurpleConnectionPrivate
*priv
= NULL
;
397 g_return_if_fail(PURPLE_IS_CONNECTION(gc
));
399 priv
= purple_connection_get_instance_private(gc
);
400 priv
->active_chats
= g_slist_append(priv
->active_chats
, chat
);
404 _purple_connection_remove_active_chat(PurpleConnection
*gc
, PurpleChatConversation
*chat
)
406 PurpleConnectionPrivate
*priv
= NULL
;
408 g_return_if_fail(PURPLE_IS_CONNECTION(gc
));
410 priv
= purple_connection_get_instance_private(gc
);
411 priv
->active_chats
= g_slist_remove(priv
->active_chats
, chat
);
415 _purple_connection_wants_to_die(PurpleConnection
*gc
)
417 PurpleConnectionPrivate
*priv
= NULL
;
419 g_return_val_if_fail(PURPLE_IS_CONNECTION(gc
), FALSE
);
421 priv
= purple_connection_get_instance_private(gc
);
422 return priv
->wants_to_die
;
426 purple_connection_update_progress(PurpleConnection
*gc
, const char *text
,
427 size_t step
, size_t count
)
429 PurpleConnectionUiOps
*ops
;
431 g_return_if_fail(PURPLE_IS_CONNECTION(gc
));
432 g_return_if_fail(text
!= NULL
);
433 g_return_if_fail(step
< count
);
434 g_return_if_fail(count
> 1);
436 ops
= purple_connections_get_ui_ops();
438 if (ops
!= NULL
&& ops
->connect_progress
!= NULL
)
439 ops
->connect_progress(gc
, text
, step
, count
);
443 purple_connection_notice(PurpleConnection
*gc
, const char *text
)
445 PurpleConnectionUiOps
*ops
;
447 g_return_if_fail(PURPLE_IS_CONNECTION(gc
));
448 g_return_if_fail(text
!= NULL
);
450 ops
= purple_connections_get_ui_ops();
452 if (ops
!= NULL
&& ops
->notice
!= NULL
)
453 ops
->notice(gc
, text
);
457 purple_connection_disconnect_cb(gpointer data
)
459 PurpleAccount
*account
;
460 PurpleConnection
*gc
;
463 gc
= purple_account_get_connection(account
);
465 if (PURPLE_IS_CONNECTION(gc
)) {
466 PurpleConnectionPrivate
*priv
;
467 priv
= purple_connection_get_instance_private(gc
);
468 priv
->disconnect_timeout
= 0;
471 purple_account_disconnect(account
);
476 purple_connection_error (PurpleConnection
*gc
,
477 PurpleConnectionError reason
,
478 const char *description
)
480 PurpleConnectionPrivate
*priv
= NULL
;
481 PurpleConnectionUiOps
*ops
;
483 g_return_if_fail(PURPLE_IS_CONNECTION(gc
));
484 priv
= purple_connection_get_instance_private(gc
);
486 /* This sanity check relies on PURPLE_CONNECTION_ERROR_OTHER_ERROR
487 * being the last member of the PurpleConnectionError enum in
488 * connection.h; if other reasons are added after it, this check should
491 if (reason
> PURPLE_CONNECTION_ERROR_OTHER_ERROR
) {
492 purple_debug_error("connection",
493 "purple_connection_error: reason %u isn't a "
494 "valid reason\n", reason
);
495 reason
= PURPLE_CONNECTION_ERROR_OTHER_ERROR
;
498 if (description
== NULL
) {
499 purple_debug_error("connection", "purple_connection_error called with NULL description\n");
500 description
= _("Unknown error");
503 /* If we've already got one error, we don't need any more */
504 if (purple_connection_get_error_info(gc
))
507 priv
->wants_to_die
= purple_connection_error_is_fatal (reason
);
509 purple_debug_info("connection", "Connection error on %p (reason: %u description: %s)\n",
510 gc
, reason
, description
);
512 ops
= purple_connections_get_ui_ops();
514 if (ops
&& ops
->report_disconnect
)
515 ops
->report_disconnect(gc
, reason
, description
);
517 priv
->error_info
= purple_connection_error_info_new(reason
, description
);
519 purple_signal_emit(purple_connections_get_handle(), "connection-error",
520 gc
, reason
, description
);
522 priv
->disconnect_timeout
= g_timeout_add(0, purple_connection_disconnect_cb
,
523 purple_connection_get_account(gc
));
526 PurpleConnectionErrorInfo
*
527 purple_connection_get_error_info(PurpleConnection
*gc
)
529 PurpleConnectionPrivate
*priv
= NULL
;
531 g_return_val_if_fail(PURPLE_IS_CONNECTION(gc
), NULL
);
533 priv
= purple_connection_get_instance_private(gc
);
534 return priv
->error_info
;
538 purple_connection_ssl_error (PurpleConnection
*gc
,
539 PurpleSslErrorType ssl_error
)
541 PurpleConnectionError reason
;
544 case PURPLE_SSL_HANDSHAKE_FAILED
:
545 reason
= PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR
;
547 case PURPLE_SSL_CONNECT_FAILED
:
548 reason
= PURPLE_CONNECTION_ERROR_NETWORK_ERROR
;
550 case PURPLE_SSL_CERTIFICATE_INVALID
:
551 /* TODO: maybe PURPLE_SSL_* should be more specific? */
552 reason
= PURPLE_CONNECTION_ERROR_CERT_OTHER_ERROR
;
555 g_assert_not_reached ();
556 reason
= PURPLE_CONNECTION_ERROR_CERT_OTHER_ERROR
;
559 purple_connection_error (gc
, reason
,
560 purple_ssl_strerror(ssl_error
));
564 purple_connection_g_error(PurpleConnection
*pc
, const GError
*error
)
566 PurpleConnectionError reason
;
568 if (g_error_matches(error
, G_IO_ERROR
, G_IO_ERROR_CANCELLED
)) {
569 /* Not a connection error. Ignore. */
573 if (error
->domain
== G_TLS_ERROR
) {
574 switch (error
->code
) {
575 case G_TLS_ERROR_UNAVAILABLE
:
576 reason
= PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT
;
578 case G_TLS_ERROR_NOT_TLS
:
579 case G_TLS_ERROR_HANDSHAKE
:
580 reason
= PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR
;
582 case G_TLS_ERROR_BAD_CERTIFICATE
:
583 case G_TLS_ERROR_CERTIFICATE_REQUIRED
:
584 reason
= PURPLE_CONNECTION_ERROR_CERT_OTHER_ERROR
;
586 case G_TLS_ERROR_EOF
:
587 case G_TLS_ERROR_MISC
:
589 reason
= PURPLE_CONNECTION_ERROR_NETWORK_ERROR
;
591 } else if (error
->domain
== G_IO_ERROR
) {
592 reason
= PURPLE_CONNECTION_ERROR_NETWORK_ERROR
;
593 } else if (error
->domain
== PURPLE_CONNECTION_ERROR
) {
594 reason
= error
->code
;
596 reason
= PURPLE_CONNECTION_ERROR_OTHER_ERROR
;
599 purple_connection_error(pc
, reason
, error
->message
);
603 purple_connection_take_error(PurpleConnection
*pc
, GError
*error
)
605 purple_connection_g_error(pc
, error
);
610 purple_connection_error_is_fatal (PurpleConnectionError reason
)
614 case PURPLE_CONNECTION_ERROR_NETWORK_ERROR
:
615 case PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR
:
617 case PURPLE_CONNECTION_ERROR_INVALID_USERNAME
:
618 case PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED
:
619 case PURPLE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE
:
620 case PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT
:
621 case PURPLE_CONNECTION_ERROR_NAME_IN_USE
:
622 case PURPLE_CONNECTION_ERROR_INVALID_SETTINGS
:
623 case PURPLE_CONNECTION_ERROR_OTHER_ERROR
:
624 case PURPLE_CONNECTION_ERROR_CERT_NOT_PROVIDED
:
625 case PURPLE_CONNECTION_ERROR_CERT_UNTRUSTED
:
626 case PURPLE_CONNECTION_ERROR_CERT_EXPIRED
:
627 case PURPLE_CONNECTION_ERROR_CERT_NOT_ACTIVATED
:
628 case PURPLE_CONNECTION_ERROR_CERT_HOSTNAME_MISMATCH
:
629 case PURPLE_CONNECTION_ERROR_CERT_FINGERPRINT_MISMATCH
:
630 case PURPLE_CONNECTION_ERROR_CERT_SELF_SIGNED
:
631 case PURPLE_CONNECTION_ERROR_CERT_OTHER_ERROR
:
634 g_return_val_if_reached(TRUE
);
638 void purple_connection_update_last_received(PurpleConnection
*gc
)
640 PurpleConnectionPrivate
*priv
= NULL
;
642 g_return_if_fail(PURPLE_IS_CONNECTION(gc
));
643 priv
= purple_connection_get_instance_private(gc
);
646 * For safety, actually this function shouldn't be called when the
647 * keepalive mechanism is inactive.
649 if (priv
->keepalive
) {
650 /* The #GTimeoutSource API doesn't expose a function to reset when a
651 * #GTimeoutSource will dispatch the next time, but because it works to
652 * directly call g_source_set_ready_time() on a #GTimeoutSource, and since
653 * it seems unlikely that the implementation will change, we just do that
654 * for now as a workaround for this API shortcoming.
656 gint64 seconds_from_now
= purple_protocol_server_iface_get_keepalive_interval(priv
->protocol
);
658 g_source_set_ready_time(
660 g_get_monotonic_time() + (seconds_from_now
* G_USEC_PER_SEC
)
665 static PurpleConnectionErrorInfo
*
666 purple_connection_error_info_new(PurpleConnectionError type
,
667 const gchar
*description
)
669 PurpleConnectionErrorInfo
*err
;
671 g_return_val_if_fail(description
!= NULL
, NULL
);
673 err
= g_new(PurpleConnectionErrorInfo
, 1);
676 err
->description
= g_strdup(description
);
681 /**************************************************************************
683 **************************************************************************/
684 static PurpleConnectionUiOps
*
685 purple_connection_ui_ops_copy(PurpleConnectionUiOps
*ops
)
687 PurpleConnectionUiOps
*ops_new
;
689 g_return_val_if_fail(ops
!= NULL
, NULL
);
691 ops_new
= g_new(PurpleConnectionUiOps
, 1);
698 purple_connection_ui_ops_get_type(void)
700 static GType type
= 0;
703 type
= g_boxed_type_register_static("PurpleConnectionUiOps",
704 (GBoxedCopyFunc
)purple_connection_ui_ops_copy
,
705 (GBoxedFreeFunc
)g_free
);
711 static PurpleConnectionErrorInfo
*
712 purple_connection_error_info_copy(PurpleConnectionErrorInfo
*err
)
714 g_return_val_if_fail(err
!= NULL
, NULL
);
716 return purple_connection_error_info_new(err
->type
, err
->description
);
720 purple_connection_error_info_free(PurpleConnectionErrorInfo
*err
)
722 g_return_if_fail(err
!= NULL
);
724 g_free(err
->description
);
729 purple_connection_error_info_get_type(void)
731 static GType type
= 0;
734 type
= g_boxed_type_register_static("PurpleConnectionErrorInfo",
735 (GBoxedCopyFunc
)purple_connection_error_info_copy
,
736 (GBoxedFreeFunc
)purple_connection_error_info_free
);
742 /**************************************************************************
744 **************************************************************************/
746 /* Set method for GObject properties */
748 purple_connection_set_property(GObject
*obj
, guint param_id
, const GValue
*value
,
751 PurpleConnection
*gc
= PURPLE_CONNECTION(obj
);
752 PurpleConnectionPrivate
*priv
= purple_connection_get_instance_private(gc
);
756 priv
->protocol
= g_value_get_object(value
);
759 purple_connection_set_flags(gc
, g_value_get_flags(value
));
762 purple_connection_set_state(gc
, g_value_get_enum(value
));
765 priv
->account
= g_value_get_object(value
);
768 g_free(priv
->password
);
769 priv
->password
= g_value_dup_string(value
);
771 case PROP_DISPLAY_NAME
:
772 purple_connection_set_display_name(gc
, g_value_get_string(value
));
775 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
780 /* Get method for GObject properties */
782 purple_connection_get_property(GObject
*obj
, guint param_id
, GValue
*value
,
785 PurpleConnection
*gc
= PURPLE_CONNECTION(obj
);
789 g_value_set_object(value
, purple_connection_get_protocol(gc
));
792 g_value_set_flags(value
, purple_connection_get_flags(gc
));
795 g_value_set_enum(value
, purple_connection_get_state(gc
));
798 g_value_set_object(value
, purple_connection_get_account(gc
));
801 g_value_set_string(value
, purple_connection_get_password(gc
));
803 case PROP_DISPLAY_NAME
:
804 g_value_set_string(value
, purple_connection_get_display_name(gc
));
807 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
812 /* GObject initialization function */
814 purple_connection_init(PurpleConnection
*gc
)
816 purple_connection_set_state(gc
, PURPLE_CONNECTION_CONNECTING
);
817 connections
= g_list_append(connections
, gc
);
820 /* Called when done constructing */
822 purple_connection_constructed(GObject
*object
)
824 PurpleConnection
*gc
= PURPLE_CONNECTION(object
);
825 PurpleAccount
*account
;
827 G_OBJECT_CLASS(purple_connection_parent_class
)->constructed(object
);
829 g_object_get(gc
, "account", &account
, NULL
);
830 purple_account_set_connection(account
, gc
);
831 g_object_unref(account
);
833 purple_signal_emit(purple_connections_get_handle(), "signing-on", gc
);
836 /* GObject finalize function */
838 purple_connection_finalize(GObject
*object
)
840 PurpleConnection
*gc
= PURPLE_CONNECTION(object
);
841 PurpleConnectionPrivate
*priv
= purple_connection_get_instance_private(gc
);
842 PurpleAccount
*account
;
844 gboolean remove
= FALSE
;
846 priv
->is_finalizing
= TRUE
;
848 account
= purple_connection_get_account(gc
);
850 purple_debug_info("connection", "Disconnecting connection %p\n", gc
);
852 if (purple_connection_get_state(gc
) != PURPLE_CONNECTION_CONNECTING
)
855 purple_signal_emit(purple_connections_get_handle(), "signing-off", gc
);
857 g_slist_free_full(priv
->active_chats
, (GDestroyNotify
)purple_chat_conversation_leave
);
859 update_keepalive(gc
, FALSE
);
861 purple_protocol_class_close(priv
->protocol
, gc
);
863 /* Clear out the proto data that was freed in the protocol's close method */
864 buddies
= purple_blist_find_buddies(account
, NULL
);
865 while (buddies
!= NULL
) {
866 PurpleBuddy
*buddy
= buddies
->data
;
867 purple_buddy_set_protocol_data(buddy
, NULL
);
868 buddies
= g_slist_delete_link(buddies
, buddies
);
871 purple_proxy_connect_cancel_with_handle(gc
);
873 connections
= g_list_remove(connections
, gc
);
875 purple_connection_set_state(gc
, PURPLE_CONNECTION_DISCONNECTED
);
878 purple_blist_remove_account(account
);
880 purple_signal_emit(purple_connections_get_handle(), "signed-off", gc
);
882 purple_account_request_close_with_account(account
);
883 purple_request_close_with_handle(gc
);
884 purple_notify_close_with_handle(gc
);
886 purple_debug_info("connection", "Destroying connection %p\n", gc
);
888 purple_account_set_connection(account
, NULL
);
890 if (priv
->error_info
)
891 purple_connection_error_info_free(priv
->error_info
);
893 if (priv
->disconnect_timeout
> 0)
894 g_source_remove(priv
->disconnect_timeout
);
896 purple_str_wipe(priv
->password
);
897 g_free(priv
->display_name
);
899 G_OBJECT_CLASS(purple_connection_parent_class
)->finalize(object
);
902 /* Class initializer function */
903 static void purple_connection_class_init(PurpleConnectionClass
*klass
)
905 GObjectClass
*obj_class
= G_OBJECT_CLASS(klass
);
907 obj_class
->finalize
= purple_connection_finalize
;
908 obj_class
->constructed
= purple_connection_constructed
;
910 /* Setup properties */
911 obj_class
->get_property
= purple_connection_get_property
;
912 obj_class
->set_property
= purple_connection_set_property
;
914 properties
[PROP_PROTOCOL
] = g_param_spec_object("protocol", "Protocol",
915 "The protocol that the connection is using.",
916 PURPLE_TYPE_PROTOCOL
,
917 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
918 G_PARAM_STATIC_STRINGS
);
920 properties
[PROP_FLAGS
] = g_param_spec_flags("flags", "Connection flags",
921 "The flags of the connection.",
922 PURPLE_TYPE_CONNECTION_FLAGS
, 0,
923 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
925 properties
[PROP_STATE
] = g_param_spec_enum("state", "Connection state",
926 "The current state of the connection.",
927 PURPLE_TYPE_CONNECTION_STATE
, PURPLE_CONNECTION_DISCONNECTED
,
928 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
930 properties
[PROP_ACCOUNT
] = g_param_spec_object("account", "Account",
931 "The account using the connection.", PURPLE_TYPE_ACCOUNT
,
932 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
933 G_PARAM_STATIC_STRINGS
);
935 properties
[PROP_PASSWORD
] = g_param_spec_string("password", "Password",
936 "The password used for connection.", NULL
,
937 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
938 G_PARAM_STATIC_STRINGS
);
940 properties
[PROP_DISPLAY_NAME
] = g_param_spec_string("display-name",
942 "Your name that appears to other people.", NULL
,
943 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
945 g_object_class_install_properties(obj_class
, PROP_LAST
, properties
);
949 _purple_connection_new(PurpleAccount
*account
, gboolean regist
, const char *password
)
951 PurpleConnection
*gc
;
952 PurpleProtocol
*protocol
;
954 g_return_if_fail(PURPLE_IS_ACCOUNT(account
));
956 if (!purple_account_is_disconnected(account
))
959 protocol
= purple_protocols_find(purple_account_get_protocol_id(account
));
961 if (protocol
== NULL
) {
964 message
= g_strdup_printf(_("Missing protocol for %s"),
965 purple_account_get_username(account
));
966 purple_notify_error(NULL
, regist
? _("Registration Error") :
967 _("Connection Error"), message
, NULL
,
968 purple_request_cpar_from_account(account
));
975 if (!PURPLE_PROTOCOL_IMPLEMENTS(protocol
, SERVER
, register_user
))
980 if (((password
== NULL
) || (*password
== '\0')) &&
981 !(purple_protocol_get_options(protocol
) & OPT_PROTO_NO_PASSWORD
) &&
982 !(purple_protocol_get_options(protocol
) & OPT_PROTO_PASSWORD_OPTIONAL
))
984 purple_debug_error("connection", "Cannot connect to account %s without "
985 "a password.\n", purple_account_get_username(account
));
990 if (PURPLE_PROTOCOL_IMPLEMENTS(protocol
, FACTORY
, connection_new
))
991 gc
= purple_protocol_factory_iface_connection_new(protocol
, account
,
994 gc
= g_object_new(PURPLE_TYPE_CONNECTION
,
995 "protocol", protocol
,
997 "password", password
,
1000 g_return_if_fail(gc
!= NULL
);
1004 PurpleConnectionPrivate
*priv
;
1005 purple_debug_info("connection", "Registering. gc = %p\n", gc
);
1007 /* set this so we don't auto-reconnect after registering */
1008 priv
= purple_connection_get_instance_private(gc
);
1009 priv
->wants_to_die
= TRUE
;
1011 purple_protocol_server_iface_register_user(protocol
, account
);
1015 purple_debug_info("connection", "Connecting. gc = %p\n", gc
);
1017 purple_signal_emit(purple_accounts_get_handle(), "account-connecting", account
);
1018 purple_protocol_class_login(protocol
, account
);
1023 _purple_connection_new_unregister(PurpleAccount
*account
, const char *password
,
1024 PurpleAccountUnregistrationCb cb
, void *user_data
)
1026 /* Lots of copy/pasted code to avoid API changes. You might want to integrate that into the previous function when posssible. */
1027 PurpleConnection
*gc
;
1028 PurpleProtocol
*protocol
;
1030 g_return_if_fail(PURPLE_IS_ACCOUNT(account
));
1032 protocol
= purple_protocols_find(purple_account_get_protocol_id(account
));
1034 if (protocol
== NULL
) {
1037 message
= g_strdup_printf(_("Missing protocol for %s"),
1038 purple_account_get_username(account
));
1039 purple_notify_error(NULL
, _("Unregistration Error"), message
,
1040 NULL
, purple_request_cpar_from_account(account
));
1045 if (!purple_account_is_disconnected(account
)) {
1046 purple_protocol_server_iface_unregister_user(protocol
, account
, cb
, user_data
);
1050 if (((password
== NULL
) || (*password
== '\0')) &&
1051 !(purple_protocol_get_options(protocol
) & OPT_PROTO_NO_PASSWORD
) &&
1052 !(purple_protocol_get_options(protocol
) & OPT_PROTO_PASSWORD_OPTIONAL
))
1054 purple_debug_error("connection", "Cannot connect to account %s without "
1055 "a password.\n", purple_account_get_username(account
));
1059 if (PURPLE_PROTOCOL_IMPLEMENTS(protocol
, FACTORY
, connection_new
))
1060 gc
= purple_protocol_factory_iface_connection_new(protocol
, account
,
1063 gc
= g_object_new(PURPLE_TYPE_CONNECTION
,
1064 "protocol", protocol
,
1066 "password", password
,
1069 g_return_if_fail(gc
!= NULL
);
1071 purple_debug_info("connection", "Unregistering. gc = %p\n", gc
);
1073 purple_protocol_server_iface_unregister_user(protocol
, account
, cb
, user_data
);
1076 /**************************************************************************
1078 **************************************************************************/
1081 _purple_assert_connection_is_valid(PurpleConnection
*gc
,
1082 const gchar
*file
, int line
)
1084 if (gc
&& g_list_find(purple_connections_get_all(), gc
))
1087 purple_debug_fatal("connection", "PURPLE_ASSERT_CONNECTION_IS_VALID(%p)"
1088 " failed at %s:%d", gc
, file
, line
);
1093 purple_connections_disconnect_all(void)
1096 PurpleConnection
*gc
;
1097 PurpleConnectionPrivate
*priv
;
1099 while ((l
= purple_connections_get_all()) != NULL
) {
1101 priv
= purple_connection_get_instance_private(gc
);
1102 priv
->wants_to_die
= TRUE
;
1103 purple_account_disconnect(priv
->account
);
1108 purple_connections_get_all(void)
1114 purple_connections_get_connecting(void)
1116 return connections_connecting
;
1120 purple_connections_set_ui_ops(PurpleConnectionUiOps
*ops
)
1122 connection_ui_ops
= ops
;
1125 PurpleConnectionUiOps
*
1126 purple_connections_get_ui_ops(void)
1128 return connection_ui_ops
;
1132 purple_connections_init(void)
1134 void *handle
= purple_connections_get_handle();
1136 purple_signal_register(handle
, "signing-on",
1137 purple_marshal_VOID__POINTER
, G_TYPE_NONE
, 1,
1138 PURPLE_TYPE_CONNECTION
);
1140 purple_signal_register(handle
, "signed-on",
1141 purple_marshal_VOID__POINTER
, G_TYPE_NONE
, 1,
1142 PURPLE_TYPE_CONNECTION
);
1144 purple_signal_register(handle
, "signing-off",
1145 purple_marshal_VOID__POINTER
, G_TYPE_NONE
, 1,
1146 PURPLE_TYPE_CONNECTION
);
1148 purple_signal_register(handle
, "signed-off",
1149 purple_marshal_VOID__POINTER
, G_TYPE_NONE
, 1,
1150 PURPLE_TYPE_CONNECTION
);
1152 purple_signal_register(handle
, "connection-error",
1153 purple_marshal_VOID__POINTER_INT_POINTER
,
1154 G_TYPE_NONE
, 3, PURPLE_TYPE_CONNECTION
,
1155 PURPLE_TYPE_CONNECTION_ERROR
, G_TYPE_STRING
);
1157 purple_signal_register(handle
, "autojoin",
1158 purple_marshal_BOOLEAN__POINTER
, G_TYPE_NONE
, 1,
1159 PURPLE_TYPE_CONNECTION
);
1164 purple_connections_uninit(void)
1166 purple_signals_unregister_by_instance(purple_connections_get_handle());
1170 purple_connections_get_handle(void)
1172 return &connections_handle
;