| 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 "gaim.h" |
|
| 32 #include "log.h" |
|
| 33 #include "notify.h" |
|
| 34 #include "prefs.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 if (on && !gc->keepalive) |
|
| 65 { |
|
| 66 gaim_debug_info("connection", "Activating keepalive.\n"); |
|
| 67 gc->keepalive = gaim_timeout_add(30000, send_keepalive, gc); |
|
| 68 } |
|
| 69 else if (!on && gc->keepalive > 0) |
|
| 70 { |
|
| 71 gaim_debug_info("connection", "Deactivating keepalive.\n"); |
|
| 72 gaim_timeout_remove(gc->keepalive); |
|
| 73 gc->keepalive = 0; |
|
| 74 } |
|
| 75 } |
|
| 76 |
|
| 77 void |
|
| 78 gaim_connection_new(GaimAccount *account, gboolean regist, const char *password) |
|
| 79 { |
|
| 80 GaimConnection *gc; |
|
| 81 GaimPlugin *prpl; |
|
| 82 GaimPluginProtocolInfo *prpl_info; |
|
| 83 |
|
| 84 g_return_if_fail(account != NULL); |
|
| 85 |
|
| 86 if (!gaim_account_is_disconnected(account)) |
|
| 87 return; |
|
| 88 |
|
| 89 prpl = gaim_find_prpl(gaim_account_get_protocol_id(account)); |
|
| 90 |
|
| 91 if (prpl != NULL) |
|
| 92 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(prpl); |
|
| 93 else { |
|
| 94 gchar *message; |
|
| 95 |
|
| 96 message = g_strdup_printf(_("Missing protocol plugin for %s"), |
|
| 97 gaim_account_get_username(account)); |
|
| 98 gaim_notify_error(NULL, regist ? _("Registration Error") : |
|
| 99 _("Connection Error"), message, NULL); |
|
| 100 g_free(message); |
|
| 101 return; |
|
| 102 } |
|
| 103 |
|
| 104 if (regist) |
|
| 105 { |
|
| 106 if (prpl_info->register_user == NULL) |
|
| 107 return; |
|
| 108 } |
|
| 109 else |
|
| 110 { |
|
| 111 if (((password == NULL) || (*password == '\0')) && |
|
| 112 !(prpl_info->options & OPT_PROTO_NO_PASSWORD) && |
|
| 113 !(prpl_info->options & OPT_PROTO_PASSWORD_OPTIONAL)) |
|
| 114 { |
|
| 115 gaim_debug_error("connection", "Can not connect to account %s without " |
|
| 116 "a password.\n", gaim_account_get_username(account)); |
|
| 117 return; |
|
| 118 } |
|
| 119 } |
|
| 120 |
|
| 121 gc = g_new0(GaimConnection, 1); |
|
| 122 GAIM_DBUS_REGISTER_POINTER(gc, GaimConnection); |
|
| 123 |
|
| 124 gc->prpl = prpl; |
|
| 125 if ((password != NULL) && (*password != '\0')) |
|
| 126 gc->password = g_strdup(password); |
|
| 127 gaim_connection_set_account(gc, account); |
|
| 128 gaim_connection_set_state(gc, GAIM_CONNECTING); |
|
| 129 connections = g_list_append(connections, gc); |
|
| 130 gaim_account_set_connection(account, gc); |
|
| 131 |
|
| 132 gaim_signal_emit(gaim_connections_get_handle(), "signing-on", gc); |
|
| 133 |
|
| 134 if (regist) |
|
| 135 { |
|
| 136 gaim_debug_info("connection", "Registering. gc = %p\n", gc); |
|
| 137 |
|
| 138 /* set this so we don't auto-reconnect after registering */ |
|
| 139 gc->wants_to_die = TRUE; |
|
| 140 |
|
| 141 prpl_info->register_user(account); |
|
| 142 } |
|
| 143 else |
|
| 144 { |
|
| 145 gaim_debug_info("connection", "Connecting. gc = %p\n", gc); |
|
| 146 |
|
| 147 gaim_signal_emit(gaim_accounts_get_handle(), "account-connecting", account); |
|
| 148 prpl_info->login(account); |
|
| 149 } |
|
| 150 } |
|
| 151 |
|
| 152 void |
|
| 153 gaim_connection_destroy(GaimConnection *gc) |
|
| 154 { |
|
| 155 GaimAccount *account; |
|
| 156 #if 0 |
|
| 157 GList *wins; |
|
| 158 #endif |
|
| 159 GaimPluginProtocolInfo *prpl_info = NULL; |
|
| 160 gboolean remove = FALSE; |
|
| 161 |
|
| 162 g_return_if_fail(gc != NULL); |
|
| 163 |
|
| 164 account = gaim_connection_get_account(gc); |
|
| 165 |
|
| 166 gaim_debug_info("connection", "Disconnecting connection %p\n", gc); |
|
| 167 |
|
| 168 if (gaim_connection_get_state(gc) != GAIM_CONNECTING) |
|
| 169 remove = TRUE; |
|
| 170 |
|
| 171 gaim_signal_emit(gaim_connections_get_handle(), "signing-off", gc); |
|
| 172 |
|
| 173 while (gc->buddy_chats) |
|
| 174 { |
|
| 175 GaimConversation *b = gc->buddy_chats->data; |
|
| 176 |
|
| 177 gc->buddy_chats = g_slist_remove(gc->buddy_chats, b); |
|
| 178 gaim_conv_chat_left(GAIM_CONV_CHAT(b)); |
|
| 179 } |
|
| 180 |
|
| 181 update_keepalive(gc, FALSE); |
|
| 182 |
|
| 183 if (gc->prpl != NULL) |
|
| 184 { |
|
| 185 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); |
|
| 186 |
|
| 187 if (prpl_info->close) |
|
| 188 (prpl_info->close)(gc); |
|
| 189 } |
|
| 190 |
|
| 191 connections = g_list_remove(connections, gc); |
|
| 192 |
|
| 193 gaim_connection_set_state(gc, GAIM_DISCONNECTED); |
|
| 194 |
|
| 195 if (remove) |
|
| 196 gaim_blist_remove_account(account); |
|
| 197 |
|
| 198 gaim_signal_emit(gaim_connections_get_handle(), "signed-off", gc); |
|
| 199 |
|
| 200 #if 0 |
|
| 201 /* see comment later in file on if 0'd same code */ |
|
| 202 /* |
|
| 203 * XXX This is a hack! Remove this and replace it with a better event |
|
| 204 * notification system. |
|
| 205 */ |
|
| 206 for (wins = gaim_get_windows(); wins != NULL; wins = wins->next) { |
|
| 207 GaimConvWindow *win = (GaimConvWindow *)wins->data; |
|
| 208 gaim_conversation_update(gaim_conv_window_get_conversation_at(win, 0), |
|
| 209 GAIM_CONV_ACCOUNT_OFFLINE); |
|
| 210 } |
|
| 211 #endif |
|
| 212 |
|
| 213 gaim_request_close_with_handle(gc); |
|
| 214 gaim_notify_close_with_handle(gc); |
|
| 215 |
|
| 216 gaim_debug_info("connection", "Destroying connection %p\n", gc); |
|
| 217 |
|
| 218 gaim_account_set_connection(account, NULL); |
|
| 219 |
|
| 220 if (gc->password != NULL) |
|
| 221 g_free(gc->password); |
|
| 222 |
|
| 223 if (gc->display_name != NULL) |
|
| 224 g_free(gc->display_name); |
|
| 225 |
|
| 226 if (gc->disconnect_timeout) |
|
| 227 gaim_timeout_remove(gc->disconnect_timeout); |
|
| 228 |
|
| 229 GAIM_DBUS_UNREGISTER_POINTER(gc); |
|
| 230 g_free(gc); |
|
| 231 } |
|
| 232 |
|
| 233 /* |
|
| 234 * d:)->-< |
|
| 235 * |
|
| 236 * d:O-\-< |
|
| 237 * |
|
| 238 * d:D-/-< |
|
| 239 * |
|
| 240 * d8D->-< DANCE! |
|
| 241 */ |
|
| 242 |
|
| 243 void |
|
| 244 gaim_connection_set_state(GaimConnection *gc, GaimConnectionState state) |
|
| 245 { |
|
| 246 GaimConnectionUiOps *ops; |
|
| 247 |
|
| 248 g_return_if_fail(gc != NULL); |
|
| 249 |
|
| 250 if (gc->state == state) |
|
| 251 return; |
|
| 252 |
|
| 253 gc->state = state; |
|
| 254 |
|
| 255 ops = gaim_connections_get_ui_ops(); |
|
| 256 |
|
| 257 if (gc->state == GAIM_CONNECTING) { |
|
| 258 connections_connecting = g_list_append(connections_connecting, gc); |
|
| 259 } |
|
| 260 else { |
|
| 261 connections_connecting = g_list_remove(connections_connecting, gc); |
|
| 262 } |
|
| 263 |
|
| 264 if (gc->state == GAIM_CONNECTED) { |
|
| 265 GaimAccount *account; |
|
| 266 GaimPresence *presence; |
|
| 267 |
|
| 268 account = gaim_connection_get_account(gc); |
|
| 269 presence = gaim_account_get_presence(account); |
|
| 270 |
|
| 271 /* Set the time the account came online */ |
|
| 272 gaim_presence_set_login_time(presence, time(NULL)); |
|
| 273 |
|
| 274 if (gaim_prefs_get_bool("/core/logging/log_system")) |
|
| 275 { |
|
| 276 GaimLog *log = gaim_account_get_log(account, TRUE); |
|
| 277 |
|
| 278 if (log != NULL) |
|
| 279 { |
|
| 280 char *msg = g_strdup_printf(_("+++ %s signed on"), |
|
| 281 gaim_account_get_username(account)); |
|
| 282 gaim_log_write(log, GAIM_MESSAGE_SYSTEM, |
|
| 283 gaim_account_get_username(account), |
|
| 284 gaim_presence_get_login_time(presence), |
|
| 285 msg); |
|
| 286 g_free(msg); |
|
| 287 } |
|
| 288 } |
|
| 289 |
|
| 290 if (ops != NULL && ops->connected != NULL) |
|
| 291 ops->connected(gc); |
|
| 292 |
|
| 293 gaim_blist_add_account(account); |
|
| 294 |
|
| 295 gaim_signal_emit(gaim_connections_get_handle(), "signed-on", gc); |
|
| 296 |
|
| 297 serv_set_permit_deny(gc); |
|
| 298 |
|
| 299 update_keepalive(gc, TRUE); |
|
| 300 |
|
| 301 if (gaim_account_get_user_info(account) != NULL) |
|
| 302 serv_set_info(gc, gaim_account_get_user_info(account)); |
|
| 303 } |
|
| 304 else if (gc->state == GAIM_DISCONNECTED) { |
|
| 305 GaimAccount *account = gaim_connection_get_account(gc); |
|
| 306 |
|
| 307 if (gaim_prefs_get_bool("/core/logging/log_system")) |
|
| 308 { |
|
| 309 GaimLog *log = gaim_account_get_log(account, FALSE); |
|
| 310 |
|
| 311 if (log != NULL) |
|
| 312 { |
|
| 313 char *msg = g_strdup_printf(_("+++ %s signed off"), |
|
| 314 gaim_account_get_username(account)); |
|
| 315 gaim_log_write(log, GAIM_MESSAGE_SYSTEM, |
|
| 316 gaim_account_get_username(account), time(NULL), |
|
| 317 msg); |
|
| 318 g_free(msg); |
|
| 319 } |
|
| 320 } |
|
| 321 |
|
| 322 gaim_account_destroy_log(account); |
|
| 323 |
|
| 324 if (ops != NULL && ops->disconnected != NULL) |
|
| 325 ops->disconnected(gc); |
|
| 326 } |
|
| 327 } |
|
| 328 |
|
| 329 void |
|
| 330 gaim_connection_set_account(GaimConnection *gc, GaimAccount *account) |
|
| 331 { |
|
| 332 g_return_if_fail(gc != NULL); |
|
| 333 g_return_if_fail(account != NULL); |
|
| 334 |
|
| 335 gc->account = account; |
|
| 336 } |
|
| 337 |
|
| 338 void |
|
| 339 gaim_connection_set_display_name(GaimConnection *gc, const char *name) |
|
| 340 { |
|
| 341 g_return_if_fail(gc != NULL); |
|
| 342 |
|
| 343 if (gc->display_name != NULL) |
|
| 344 g_free(gc->display_name); |
|
| 345 |
|
| 346 gc->display_name = (name == NULL ? NULL : g_strdup(name)); |
|
| 347 } |
|
| 348 |
|
| 349 GaimConnectionState |
|
| 350 gaim_connection_get_state(const GaimConnection *gc) |
|
| 351 { |
|
| 352 g_return_val_if_fail(gc != NULL, GAIM_DISCONNECTED); |
|
| 353 |
|
| 354 return gc->state; |
|
| 355 } |
|
| 356 |
|
| 357 GaimAccount * |
|
| 358 gaim_connection_get_account(const GaimConnection *gc) |
|
| 359 { |
|
| 360 g_return_val_if_fail(gc != NULL, NULL); |
|
| 361 |
|
| 362 return gc->account; |
|
| 363 } |
|
| 364 |
|
| 365 const char * |
|
| 366 gaim_connection_get_password(const GaimConnection *gc) |
|
| 367 { |
|
| 368 g_return_val_if_fail(gc != NULL, NULL); |
|
| 369 |
|
| 370 return gc->password; |
|
| 371 } |
|
| 372 |
|
| 373 const char * |
|
| 374 gaim_connection_get_display_name(const GaimConnection *gc) |
|
| 375 { |
|
| 376 g_return_val_if_fail(gc != NULL, NULL); |
|
| 377 |
|
| 378 return gc->display_name; |
|
| 379 } |
|
| 380 |
|
| 381 void |
|
| 382 gaim_connection_update_progress(GaimConnection *gc, const char *text, |
|
| 383 size_t step, size_t count) |
|
| 384 { |
|
| 385 GaimConnectionUiOps *ops; |
|
| 386 |
|
| 387 g_return_if_fail(gc != NULL); |
|
| 388 g_return_if_fail(text != NULL); |
|
| 389 g_return_if_fail(step < count); |
|
| 390 g_return_if_fail(count > 1); |
|
| 391 |
|
| 392 ops = gaim_connections_get_ui_ops(); |
|
| 393 |
|
| 394 if (ops != NULL && ops->connect_progress != NULL) |
|
| 395 ops->connect_progress(gc, text, step, count); |
|
| 396 } |
|
| 397 |
|
| 398 void |
|
| 399 gaim_connection_notice(GaimConnection *gc, const char *text) |
|
| 400 { |
|
| 401 GaimConnectionUiOps *ops; |
|
| 402 |
|
| 403 g_return_if_fail(gc != NULL); |
|
| 404 g_return_if_fail(text != NULL); |
|
| 405 |
|
| 406 ops = gaim_connections_get_ui_ops(); |
|
| 407 |
|
| 408 if (ops != NULL && ops->notice != NULL) |
|
| 409 ops->notice(gc, text); |
|
| 410 } |
|
| 411 |
|
| 412 static gboolean |
|
| 413 gaim_connection_disconnect_cb(gpointer data) |
|
| 414 { |
|
| 415 GaimAccount *account = data; |
|
| 416 char *password = g_strdup(gaim_account_get_password(account)); |
|
| 417 gaim_account_disconnect(account); |
|
| 418 gaim_account_set_password(account, password); |
|
| 419 g_free(password); |
|
| 420 return FALSE; |
|
| 421 } |
|
| 422 |
|
| 423 void |
|
| 424 gaim_connection_error(GaimConnection *gc, const char *text) |
|
| 425 { |
|
| 426 GaimConnectionUiOps *ops; |
|
| 427 |
|
| 428 g_return_if_fail(gc != NULL); |
|
| 429 g_return_if_fail(text != NULL); |
|
| 430 |
|
| 431 /* If we've already got one error, we don't need any more */ |
|
| 432 if (gc->disconnect_timeout) |
|
| 433 return; |
|
| 434 |
|
| 435 ops = gaim_connections_get_ui_ops(); |
|
| 436 |
|
| 437 if (ops != NULL) { |
|
| 438 if (ops->report_disconnect != NULL) |
|
| 439 ops->report_disconnect(gc, text); |
|
| 440 } |
|
| 441 |
|
| 442 gc->disconnect_timeout = gaim_timeout_add(0, gaim_connection_disconnect_cb, |
|
| 443 gaim_connection_get_account(gc)); |
|
| 444 } |
|
| 445 |
|
| 446 void |
|
| 447 gaim_connections_disconnect_all(void) |
|
| 448 { |
|
| 449 GList *l; |
|
| 450 GaimConnection *gc; |
|
| 451 |
|
| 452 while ((l = gaim_connections_get_all()) != NULL) { |
|
| 453 gc = l->data; |
|
| 454 gc->wants_to_die = TRUE; |
|
| 455 gaim_account_disconnect(gc->account); |
|
| 456 } |
|
| 457 } |
|
| 458 |
|
| 459 GList * |
|
| 460 gaim_connections_get_all(void) |
|
| 461 { |
|
| 462 return connections; |
|
| 463 } |
|
| 464 |
|
| 465 GList * |
|
| 466 gaim_connections_get_connecting(void) |
|
| 467 { |
|
| 468 return connections_connecting; |
|
| 469 } |
|
| 470 |
|
| 471 void |
|
| 472 gaim_connections_set_ui_ops(GaimConnectionUiOps *ops) |
|
| 473 { |
|
| 474 connection_ui_ops = ops; |
|
| 475 } |
|
| 476 |
|
| 477 GaimConnectionUiOps * |
|
| 478 gaim_connections_get_ui_ops(void) |
|
| 479 { |
|
| 480 return connection_ui_ops; |
|
| 481 } |
|
| 482 |
|
| 483 void |
|
| 484 gaim_connections_init(void) |
|
| 485 { |
|
| 486 void *handle = gaim_connections_get_handle(); |
|
| 487 |
|
| 488 gaim_signal_register(handle, "signing-on", |
|
| 489 gaim_marshal_VOID__POINTER, NULL, 1, |
|
| 490 gaim_value_new(GAIM_TYPE_SUBTYPE, |
|
| 491 GAIM_SUBTYPE_CONNECTION)); |
|
| 492 |
|
| 493 gaim_signal_register(handle, "signed-on", |
|
| 494 gaim_marshal_VOID__POINTER, NULL, 1, |
|
| 495 gaim_value_new(GAIM_TYPE_SUBTYPE, |
|
| 496 GAIM_SUBTYPE_CONNECTION)); |
|
| 497 |
|
| 498 gaim_signal_register(handle, "signing-off", |
|
| 499 gaim_marshal_VOID__POINTER, NULL, 1, |
|
| 500 gaim_value_new(GAIM_TYPE_SUBTYPE, |
|
| 501 GAIM_SUBTYPE_CONNECTION)); |
|
| 502 |
|
| 503 gaim_signal_register(handle, "signed-off", |
|
| 504 gaim_marshal_VOID__POINTER, NULL, 1, |
|
| 505 gaim_value_new(GAIM_TYPE_SUBTYPE, |
|
| 506 GAIM_SUBTYPE_CONNECTION)); |
|
| 507 } |
|
| 508 |
|
| 509 void |
|
| 510 gaim_connections_uninit(void) |
|
| 511 { |
|
| 512 gaim_signals_unregister_by_instance(gaim_connections_get_handle()); |
|
| 513 } |
|
| 514 |
|
| 515 void * |
|
| 516 gaim_connections_get_handle(void) |
|
| 517 { |
|
| 518 return &connections_handle; |
|
| 519 } |
|