comparison libpurple/connection.c @ 15374:5fe8042783c1

Rename gtk/ and libgaim/ to pidgin/ and libpurple/
author Sean Egan <seanegan@gmail.com>
date Sat, 20 Jan 2007 02:32:10 +0000
parents
children cb3800fabd76
comparison
equal deleted inserted replaced
15373:f79e0f4df793 15374:5fe8042783c1
1 /**
2 * @file connection.c Connection API
3 * @ingroup core
4 *
5 * gaim
6 *
7 * Gaim is the legal property of its developers, whose names are too numerous
8 * to list here. Please refer to the COPYRIGHT file distributed with this
9 * source distribution.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25 #include "internal.h"
26 #include "account.h"
27 #include "blist.h"
28 #include "connection.h"
29 #include "dbus-maybe.h"
30 #include "debug.h"
31 #include "log.h"
32 #include "notify.h"
33 #include "prefs.h"
34 #include "proxy.h"
35 #include "request.h"
36 #include "server.h"
37 #include "signals.h"
38 #include "util.h"
39
40 static GList *connections = NULL;
41 static GList *connections_connecting = NULL;
42 static GaimConnectionUiOps *connection_ui_ops = NULL;
43
44 static int connections_handle;
45
46 static gboolean
47 send_keepalive(gpointer data)
48 {
49 GaimConnection *gc = data;
50 GaimPluginProtocolInfo *prpl_info = NULL;
51
52 if (gc != NULL && gc->prpl != NULL)
53 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl);
54
55 if (prpl_info && prpl_info->keepalive)
56 prpl_info->keepalive(gc);
57
58 return TRUE;
59 }
60
61 static void
62 update_keepalive(GaimConnection *gc, gboolean on)
63 {
64 GaimPluginProtocolInfo *prpl_info = NULL;
65
66 if (gc != NULL && gc->prpl != NULL)
67 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl);
68
69 if (!prpl_info || !prpl_info->keepalive)
70 return;
71
72 if (on && !gc->keepalive)
73 {
74 gaim_debug_info("connection", "Activating keepalive.\n");
75 gc->keepalive = gaim_timeout_add(30000, send_keepalive, gc);
76 }
77 else if (!on && gc->keepalive > 0)
78 {
79 gaim_debug_info("connection", "Deactivating keepalive.\n");
80 gaim_timeout_remove(gc->keepalive);
81 gc->keepalive = 0;
82 }
83 }
84
85 void
86 gaim_connection_new(GaimAccount *account, gboolean regist, const char *password)
87 {
88 GaimConnection *gc;
89 GaimPlugin *prpl;
90 GaimPluginProtocolInfo *prpl_info;
91
92 g_return_if_fail(account != NULL);
93
94 if (!gaim_account_is_disconnected(account))
95 return;
96
97 prpl = gaim_find_prpl(gaim_account_get_protocol_id(account));
98
99 if (prpl != NULL)
100 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(prpl);
101 else {
102 gchar *message;
103
104 message = g_strdup_printf(_("Missing protocol plugin for %s"),
105 gaim_account_get_username(account));
106 gaim_notify_error(NULL, regist ? _("Registration Error") :
107 _("Connection Error"), message, NULL);
108 g_free(message);
109 return;
110 }
111
112 if (regist)
113 {
114 if (prpl_info->register_user == NULL)
115 return;
116 }
117 else
118 {
119 if (((password == NULL) || (*password == '\0')) &&
120 !(prpl_info->options & OPT_PROTO_NO_PASSWORD) &&
121 !(prpl_info->options & OPT_PROTO_PASSWORD_OPTIONAL))
122 {
123 gaim_debug_error("connection", "Can not connect to account %s without "
124 "a password.\n", gaim_account_get_username(account));
125 return;
126 }
127 }
128
129 gc = g_new0(GaimConnection, 1);
130 GAIM_DBUS_REGISTER_POINTER(gc, GaimConnection);
131
132 gc->prpl = prpl;
133 if ((password != NULL) && (*password != '\0'))
134 gc->password = g_strdup(password);
135 gaim_connection_set_account(gc, account);
136 gaim_connection_set_state(gc, GAIM_CONNECTING);
137 connections = g_list_append(connections, gc);
138 gaim_account_set_connection(account, gc);
139
140 gaim_signal_emit(gaim_connections_get_handle(), "signing-on", gc);
141
142 if (regist)
143 {
144 gaim_debug_info("connection", "Registering. gc = %p\n", gc);
145
146 /* set this so we don't auto-reconnect after registering */
147 gc->wants_to_die = TRUE;
148
149 prpl_info->register_user(account);
150 }
151 else
152 {
153 gaim_debug_info("connection", "Connecting. gc = %p\n", gc);
154
155 gaim_signal_emit(gaim_accounts_get_handle(), "account-connecting", account);
156 prpl_info->login(account);
157 }
158 }
159
160 void
161 gaim_connection_destroy(GaimConnection *gc)
162 {
163 GaimAccount *account;
164 GSList *buddies, *tmp;
165 #if 0
166 GList *wins;
167 #endif
168 GaimPluginProtocolInfo *prpl_info = NULL;
169 gboolean remove = FALSE;
170
171 g_return_if_fail(gc != NULL);
172
173 account = gaim_connection_get_account(gc);
174
175 gaim_debug_info("connection", "Disconnecting connection %p\n", gc);
176
177 if (gaim_connection_get_state(gc) != GAIM_CONNECTING)
178 remove = TRUE;
179
180 gaim_signal_emit(gaim_connections_get_handle(), "signing-off", gc);
181
182 while (gc->buddy_chats)
183 {
184 GaimConversation *b = gc->buddy_chats->data;
185
186 gc->buddy_chats = g_slist_remove(gc->buddy_chats, b);
187 gaim_conv_chat_left(GAIM_CONV_CHAT(b));
188 }
189
190 update_keepalive(gc, FALSE);
191
192 gaim_proxy_connect_cancel_with_handle(gc);
193
194 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl);
195 if (prpl_info->close)
196 (prpl_info->close)(gc);
197
198 /* Clear out the proto data that was freed in the prpl close method*/
199 buddies = gaim_find_buddies(account, NULL);
200 for (tmp = buddies; tmp; tmp = tmp->next) {
201 GaimBuddy *buddy = tmp->data;
202 buddy->proto_data = NULL;
203 }
204 g_slist_free(buddies);
205
206 connections = g_list_remove(connections, gc);
207
208 gaim_connection_set_state(gc, GAIM_DISCONNECTED);
209
210 if (remove)
211 gaim_blist_remove_account(account);
212
213 gaim_signal_emit(gaim_connections_get_handle(), "signed-off", gc);
214
215 #if 0
216 /* see comment later in file on if 0'd same code */
217 /*
218 * XXX This is a hack! Remove this and replace it with a better event
219 * notification system.
220 */
221 for (wins = gaim_get_windows(); wins != NULL; wins = wins->next) {
222 GaimConvWindow *win = (GaimConvWindow *)wins->data;
223 gaim_conversation_update(gaim_conv_window_get_conversation_at(win, 0),
224 GAIM_CONV_ACCOUNT_OFFLINE);
225 }
226 #endif
227
228 gaim_request_close_with_handle(gc);
229 gaim_notify_close_with_handle(gc);
230
231 gaim_debug_info("connection", "Destroying connection %p\n", gc);
232
233 gaim_account_set_connection(account, NULL);
234
235 g_free(gc->password);
236 g_free(gc->display_name);
237
238 if (gc->disconnect_timeout)
239 gaim_timeout_remove(gc->disconnect_timeout);
240
241 GAIM_DBUS_UNREGISTER_POINTER(gc);
242 g_free(gc);
243 }
244
245 /*
246 * d:)->-<
247 *
248 * d:O-\-<
249 *
250 * d:D-/-<
251 *
252 * d8D->-< DANCE!
253 */
254
255 void
256 gaim_connection_set_state(GaimConnection *gc, GaimConnectionState state)
257 {
258 GaimConnectionUiOps *ops;
259
260 g_return_if_fail(gc != NULL);
261
262 if (gc->state == state)
263 return;
264
265 gc->state = state;
266
267 ops = gaim_connections_get_ui_ops();
268
269 if (gc->state == GAIM_CONNECTING) {
270 connections_connecting = g_list_append(connections_connecting, gc);
271 }
272 else {
273 connections_connecting = g_list_remove(connections_connecting, gc);
274 }
275
276 if (gc->state == GAIM_CONNECTED) {
277 GaimAccount *account;
278 GaimPresence *presence;
279
280 account = gaim_connection_get_account(gc);
281 presence = gaim_account_get_presence(account);
282
283 /* Set the time the account came online */
284 gaim_presence_set_login_time(presence, time(NULL));
285
286 if (gaim_prefs_get_bool("/core/logging/log_system"))
287 {
288 GaimLog *log = gaim_account_get_log(account, TRUE);
289
290 if (log != NULL)
291 {
292 char *msg = g_strdup_printf(_("+++ %s signed on"),
293 gaim_account_get_username(account));
294 gaim_log_write(log, GAIM_MESSAGE_SYSTEM,
295 gaim_account_get_username(account),
296 gaim_presence_get_login_time(presence),
297 msg);
298 g_free(msg);
299 }
300 }
301
302 if (ops != NULL && ops->connected != NULL)
303 ops->connected(gc);
304
305 gaim_blist_add_account(account);
306
307 gaim_signal_emit(gaim_connections_get_handle(), "signed-on", gc);
308
309 serv_set_permit_deny(gc);
310
311 update_keepalive(gc, TRUE);
312 }
313 else if (gc->state == GAIM_DISCONNECTED) {
314 GaimAccount *account = gaim_connection_get_account(gc);
315
316 if (gaim_prefs_get_bool("/core/logging/log_system"))
317 {
318 GaimLog *log = gaim_account_get_log(account, FALSE);
319
320 if (log != NULL)
321 {
322 char *msg = g_strdup_printf(_("+++ %s signed off"),
323 gaim_account_get_username(account));
324 gaim_log_write(log, GAIM_MESSAGE_SYSTEM,
325 gaim_account_get_username(account), time(NULL),
326 msg);
327 g_free(msg);
328 }
329 }
330
331 gaim_account_destroy_log(account);
332
333 if (ops != NULL && ops->disconnected != NULL)
334 ops->disconnected(gc);
335 }
336 }
337
338 void
339 gaim_connection_set_account(GaimConnection *gc, GaimAccount *account)
340 {
341 g_return_if_fail(gc != NULL);
342 g_return_if_fail(account != NULL);
343
344 gc->account = account;
345 }
346
347 void
348 gaim_connection_set_display_name(GaimConnection *gc, const char *name)
349 {
350 g_return_if_fail(gc != NULL);
351
352 g_free(gc->display_name);
353 gc->display_name = g_strdup(name);
354 }
355
356 GaimConnectionState
357 gaim_connection_get_state(const GaimConnection *gc)
358 {
359 g_return_val_if_fail(gc != NULL, GAIM_DISCONNECTED);
360
361 return gc->state;
362 }
363
364 GaimAccount *
365 gaim_connection_get_account(const GaimConnection *gc)
366 {
367 g_return_val_if_fail(gc != NULL, NULL);
368
369 return gc->account;
370 }
371
372 const char *
373 gaim_connection_get_password(const GaimConnection *gc)
374 {
375 g_return_val_if_fail(gc != NULL, NULL);
376
377 return gc->password;
378 }
379
380 const char *
381 gaim_connection_get_display_name(const GaimConnection *gc)
382 {
383 g_return_val_if_fail(gc != NULL, NULL);
384
385 return gc->display_name;
386 }
387
388 void
389 gaim_connection_update_progress(GaimConnection *gc, const char *text,
390 size_t step, size_t count)
391 {
392 GaimConnectionUiOps *ops;
393
394 g_return_if_fail(gc != NULL);
395 g_return_if_fail(text != NULL);
396 g_return_if_fail(step < count);
397 g_return_if_fail(count > 1);
398
399 ops = gaim_connections_get_ui_ops();
400
401 if (ops != NULL && ops->connect_progress != NULL)
402 ops->connect_progress(gc, text, step, count);
403 }
404
405 void
406 gaim_connection_notice(GaimConnection *gc, const char *text)
407 {
408 GaimConnectionUiOps *ops;
409
410 g_return_if_fail(gc != NULL);
411 g_return_if_fail(text != NULL);
412
413 ops = gaim_connections_get_ui_ops();
414
415 if (ops != NULL && ops->notice != NULL)
416 ops->notice(gc, text);
417 }
418
419 static gboolean
420 gaim_connection_disconnect_cb(gpointer data)
421 {
422 GaimAccount *account = data;
423 char *password = g_strdup(gaim_account_get_password(account));
424 gaim_account_disconnect(account);
425 gaim_account_set_password(account, password);
426 g_free(password);
427 return FALSE;
428 }
429
430 void
431 gaim_connection_error(GaimConnection *gc, const char *text)
432 {
433 GaimConnectionUiOps *ops;
434
435 g_return_if_fail(gc != NULL);
436 g_return_if_fail(text != NULL);
437
438 /* If we've already got one error, we don't need any more */
439 if (gc->disconnect_timeout)
440 return;
441
442 ops = gaim_connections_get_ui_ops();
443
444 if (ops != NULL) {
445 if (ops->report_disconnect != NULL)
446 ops->report_disconnect(gc, text);
447 }
448
449 gc->disconnect_timeout = gaim_timeout_add(0, gaim_connection_disconnect_cb,
450 gaim_connection_get_account(gc));
451 }
452
453 void
454 gaim_connections_disconnect_all(void)
455 {
456 GList *l;
457 GaimConnection *gc;
458
459 while ((l = gaim_connections_get_all()) != NULL) {
460 gc = l->data;
461 gc->wants_to_die = TRUE;
462 gaim_account_disconnect(gc->account);
463 }
464 }
465
466 GList *
467 gaim_connections_get_all(void)
468 {
469 return connections;
470 }
471
472 GList *
473 gaim_connections_get_connecting(void)
474 {
475 return connections_connecting;
476 }
477
478 void
479 gaim_connections_set_ui_ops(GaimConnectionUiOps *ops)
480 {
481 connection_ui_ops = ops;
482 }
483
484 GaimConnectionUiOps *
485 gaim_connections_get_ui_ops(void)
486 {
487 return connection_ui_ops;
488 }
489
490 void
491 gaim_connections_init(void)
492 {
493 void *handle = gaim_connections_get_handle();
494
495 gaim_signal_register(handle, "signing-on",
496 gaim_marshal_VOID__POINTER, NULL, 1,
497 gaim_value_new(GAIM_TYPE_SUBTYPE,
498 GAIM_SUBTYPE_CONNECTION));
499
500 gaim_signal_register(handle, "signed-on",
501 gaim_marshal_VOID__POINTER, NULL, 1,
502 gaim_value_new(GAIM_TYPE_SUBTYPE,
503 GAIM_SUBTYPE_CONNECTION));
504
505 gaim_signal_register(handle, "signing-off",
506 gaim_marshal_VOID__POINTER, NULL, 1,
507 gaim_value_new(GAIM_TYPE_SUBTYPE,
508 GAIM_SUBTYPE_CONNECTION));
509
510 gaim_signal_register(handle, "signed-off",
511 gaim_marshal_VOID__POINTER, NULL, 1,
512 gaim_value_new(GAIM_TYPE_SUBTYPE,
513 GAIM_SUBTYPE_CONNECTION));
514 }
515
516 void
517 gaim_connections_uninit(void)
518 {
519 gaim_signals_unregister_by_instance(gaim_connections_get_handle());
520 }
521
522 void *
523 gaim_connections_get_handle(void)
524 {
525 return &connections_handle;
526 }