Mercurial > pidgin
comparison src/protocols/irc/irc.c @ 10365:d2f999970f91
[gaim-migrate @ 11583]
SSL for IRC ... thanks to datallah
committer: Tailor Script <tailor@pidgin.im>
| author | Ethan Blanton <elb@pidgin.im> |
|---|---|
| date | Tue, 14 Dec 2004 05:16:40 +0000 |
| parents | 357d4fa1bfbe |
| children | 3e4ecbdf8d0a |
comparison
equal
deleted
inserted
replaced
| 10364:db5e8c8b2abb | 10365:d2f999970f91 |
|---|---|
| 43 static void irc_blist_emblems(GaimBuddy *b, const char **se, const char **sw, const char **nw, const char **ne); | 43 static void irc_blist_emblems(GaimBuddy *b, const char **se, const char **sw, const char **nw, const char **ne); |
| 44 static GList *irc_status_types(GaimAccount *account); | 44 static GList *irc_status_types(GaimAccount *account); |
| 45 static GList *irc_actions(GaimPlugin *plugin, gpointer context); | 45 static GList *irc_actions(GaimPlugin *plugin, gpointer context); |
| 46 /* static GList *irc_chat_info(GaimConnection *gc); */ | 46 /* static GList *irc_chat_info(GaimConnection *gc); */ |
| 47 static void irc_login(GaimAccount *account); | 47 static void irc_login(GaimAccount *account); |
| 48 static void irc_login_cb_ssl(gpointer data, GaimSslConnection *gsc, GaimInputCondition cond); | |
| 48 static void irc_login_cb(gpointer data, gint source, GaimInputCondition cond); | 49 static void irc_login_cb(gpointer data, gint source, GaimInputCondition cond); |
| 50 static void irc_ssl_connect_failure(GaimSslConnection *gsc, GaimSslErrorType error, gpointer data); | |
| 49 static void irc_close(GaimConnection *gc); | 51 static void irc_close(GaimConnection *gc); |
| 50 static int irc_im_send(GaimConnection *gc, const char *who, const char *what, GaimConvImFlags flags); | 52 static int irc_im_send(GaimConnection *gc, const char *who, const char *what, GaimConvImFlags flags); |
| 51 static int irc_chat_send(GaimConnection *gc, int id, const char *what); | 53 static int irc_chat_send(GaimConnection *gc, int id, const char *what); |
| 52 static void irc_chat_join (GaimConnection *gc, GHashTable *data); | 54 static void irc_chat_join (GaimConnection *gc, GHashTable *data); |
| 53 static void irc_input_cb(gpointer data, gint source, GaimInputCondition cond); | 55 static void irc_input_cb(gpointer data, gint source, GaimInputCondition cond); |
| 56 static void irc_input_cb_ssl(gpointer data, GaimSslConnection *gsc, GaimInputCondition cond); | |
| 54 | 57 |
| 55 static guint irc_nick_hash(const char *nick); | 58 static guint irc_nick_hash(const char *nick); |
| 56 static gboolean irc_nick_equal(const char *nick1, const char *nick2); | 59 static gboolean irc_nick_equal(const char *nick1, const char *nick2); |
| 57 static void irc_buddy_free(struct irc_buddy *ib); | 60 static void irc_buddy_free(struct irc_buddy *ib); |
| 58 | 61 |
| 82 | 85 |
| 83 int irc_send(struct irc_conn *irc, const char *buf) | 86 int irc_send(struct irc_conn *irc, const char *buf) |
| 84 { | 87 { |
| 85 int ret; | 88 int ret; |
| 86 | 89 |
| 87 if (irc->fd < 0) | 90 if (irc->gsc) { |
| 88 return -1; | 91 ret = gaim_ssl_write(irc->gsc, buf, strlen(buf)); |
| 89 | 92 } else { |
| 90 /* gaim_debug(GAIM_DEBUG_MISC, "irc", "sent: %s", buf); */ | 93 if (irc->fd < 0) |
| 91 if ((ret = write(irc->fd, buf, strlen(buf))) < 0) | 94 return -1; |
| 95 ret = write(irc->fd, buf, strlen(buf)); | |
| 96 } | |
| 97 | |
| 98 /* gaim_debug(GAIM_DEBUG_MISC, "irc", "sent%s: %s", | |
| 99 irc->gsc ? " (ssl)" : "", buf); */ | |
| 100 if (ret < 0) { | |
| 92 gaim_connection_error(gaim_account_get_connection(irc->account), | 101 gaim_connection_error(gaim_account_get_connection(irc->account), |
| 93 _("Server has disconnected")); | 102 _("Server has disconnected")); |
| 103 } | |
| 94 | 104 |
| 95 return ret; | 105 return ret; |
| 96 } | 106 } |
| 97 | 107 |
| 98 /* XXX I don't like messing directly with these buddies */ | 108 /* XXX I don't like messing directly with these buddies */ |
| 248 | 258 |
| 249 buf = g_strdup_printf(_("Logging in: %s"), username); | 259 buf = g_strdup_printf(_("Logging in: %s"), username); |
| 250 gaim_connection_update_progress(gc, buf, 1, 2); | 260 gaim_connection_update_progress(gc, buf, 1, 2); |
| 251 g_free(buf); | 261 g_free(buf); |
| 252 | 262 |
| 253 err = gaim_proxy_connect(account, irc->server, | 263 if (gaim_account_get_bool(account, "ssl", FALSE)) { |
| 264 if (gaim_ssl_is_supported()) { | |
| 265 irc->gsc = gaim_ssl_connect(account, irc->server, | |
| 266 gaim_account_get_int(account, "port", IRC_DEFAULT_SSL_PORT), | |
| 267 irc_login_cb_ssl, irc_ssl_connect_failure, gc); | |
| 268 } else { | |
| 269 gaim_connection_error(gc, _("SSL support unavailable")); | |
| 270 } | |
| 271 } | |
| 272 | |
| 273 if (!irc->gsc) { | |
| 274 | |
| 275 err = gaim_proxy_connect(account, irc->server, | |
| 254 gaim_account_get_int(account, "port", IRC_DEFAULT_PORT), | 276 gaim_account_get_int(account, "port", IRC_DEFAULT_PORT), |
| 255 irc_login_cb, gc); | 277 irc_login_cb, gc); |
| 256 | 278 |
| 257 if (err || !account->gc) { | 279 if (err || !account->gc) { |
| 258 gaim_connection_error(gc, _("Couldn't create socket")); | 280 gaim_connection_error(gc, _("Couldn't create socket")); |
| 259 return; | 281 return; |
| 260 } | 282 } |
| 261 } | 283 } |
| 262 | 284 } |
| 263 static void irc_login_cb(gpointer data, gint source, GaimInputCondition cond) | 285 |
| 264 { | 286 static gboolean do_login(GaimConnection *gc) { |
| 265 GaimConnection *gc = data; | 287 char *buf; |
| 266 struct irc_conn *irc = gc->proto_data; | |
| 267 char hostname[256]; | 288 char hostname[256]; |
| 268 char *buf; | |
| 269 const char *username, *realname; | 289 const char *username, *realname; |
| 270 GList *connections = gaim_connections_get_all(); | 290 struct irc_conn *irc = gc->proto_data; |
| 271 | |
| 272 if (source < 0) { | |
| 273 gaim_connection_error(gc, _("Couldn't connect to host")); | |
| 274 return; | |
| 275 } | |
| 276 | |
| 277 if (!g_list_find(connections, gc)) { | |
| 278 close(source); | |
| 279 return; | |
| 280 } | |
| 281 | |
| 282 irc->fd = source; | |
| 283 | 291 |
| 284 if (gc->account->password && *gc->account->password) { | 292 if (gc->account->password && *gc->account->password) { |
| 285 buf = irc_format(irc, "vv", "PASS", gc->account->password); | 293 buf = irc_format(irc, "vv", "PASS", gc->account->password); |
| 286 if (irc_send(irc, buf) < 0) { | 294 if (irc_send(irc, buf) < 0) { |
| 287 gaim_connection_error(gc, "Error sending password"); | 295 gaim_connection_error(gc, "Error sending password"); |
| 288 return; | 296 return FALSE; |
| 289 } | 297 } |
| 290 g_free(buf); | 298 g_free(buf); |
| 291 } | 299 } |
| 292 | 300 |
| 293 gethostname(hostname, sizeof(hostname)); | 301 gethostname(hostname, sizeof(hostname)); |
| 296 realname = gaim_account_get_string(irc->account, "realname", ""); | 304 realname = gaim_account_get_string(irc->account, "realname", ""); |
| 297 buf = irc_format(irc, "vvvv:", "USER", strlen(username) ? username : g_get_user_name(), hostname, irc->server, | 305 buf = irc_format(irc, "vvvv:", "USER", strlen(username) ? username : g_get_user_name(), hostname, irc->server, |
| 298 strlen(realname) ? realname : IRC_DEFAULT_ALIAS); | 306 strlen(realname) ? realname : IRC_DEFAULT_ALIAS); |
| 299 if (irc_send(irc, buf) < 0) { | 307 if (irc_send(irc, buf) < 0) { |
| 300 gaim_connection_error(gc, "Error registering with server"); | 308 gaim_connection_error(gc, "Error registering with server"); |
| 301 return; | 309 return FALSE; |
| 302 } | 310 } |
| 303 g_free(buf); | 311 g_free(buf); |
| 304 buf = irc_format(irc, "vn", "NICK", gaim_connection_get_display_name(gc)); | 312 buf = irc_format(irc, "vn", "NICK", gaim_connection_get_display_name(gc)); |
| 305 if (irc_send(irc, buf) < 0) { | 313 if (irc_send(irc, buf) < 0) { |
| 306 gaim_connection_error(gc, "Error sending nickname"); | 314 gaim_connection_error(gc, "Error sending nickname"); |
| 307 return; | 315 return FALSE; |
| 308 } | 316 } |
| 309 g_free(buf); | 317 g_free(buf); |
| 310 | 318 |
| 311 gc->inpa = gaim_input_add(irc->fd, GAIM_INPUT_READ, irc_input_cb, gc); | 319 return TRUE; |
| 320 } | |
| 321 | |
| 322 static void irc_login_cb_ssl(gpointer data, GaimSslConnection *gsc, | |
| 323 GaimInputCondition cond) | |
| 324 { | |
| 325 GaimConnection *gc = data; | |
| 326 struct irc_conn *irc = gc->proto_data; | |
| 327 | |
| 328 if(!g_list_find(gaim_connections_get_all(), gc)) { | |
| 329 gaim_ssl_close(gsc); | |
| 330 return; | |
| 331 } | |
| 332 | |
| 333 irc->gsc = gsc; | |
| 334 | |
| 335 if (do_login(gc)) { | |
| 336 gaim_ssl_input_add(gsc, irc_input_cb_ssl, gc); | |
| 337 } | |
| 338 } | |
| 339 | |
| 340 static void irc_login_cb(gpointer data, gint source, GaimInputCondition cond) | |
| 341 { | |
| 342 GaimConnection *gc = data; | |
| 343 struct irc_conn *irc = gc->proto_data; | |
| 344 GList *connections = gaim_connections_get_all(); | |
| 345 | |
| 346 if (source < 0) { | |
| 347 gaim_connection_error(gc, _("Couldn't connect to host")); | |
| 348 return; | |
| 349 } | |
| 350 | |
| 351 if (!g_list_find(connections, gc)) { | |
| 352 close(source); | |
| 353 return; | |
| 354 } | |
| 355 | |
| 356 irc->fd = source; | |
| 357 | |
| 358 if (do_login(gc)) { | |
| 359 gc->inpa = gaim_input_add(irc->fd, GAIM_INPUT_READ, irc_input_cb, gc); | |
| 360 } | |
| 361 } | |
| 362 | |
| 363 static void | |
| 364 irc_ssl_connect_failure(GaimSslConnection *gsc, GaimSslErrorType error, | |
| 365 gpointer data) | |
| 366 { | |
| 367 GaimConnection *gc = data; | |
| 368 struct irc_conn *irc = gc->proto_data; | |
| 369 | |
| 370 switch(error) { | |
| 371 case GAIM_SSL_CONNECT_FAILED: | |
| 372 gaim_connection_error(gc, _("Connection Failed")); | |
| 373 break; | |
| 374 case GAIM_SSL_HANDSHAKE_FAILED: | |
| 375 gaim_connection_error(gc, _("SSL Handshake Failed")); | |
| 376 break; | |
| 377 } | |
| 378 | |
| 379 irc->gsc = NULL; | |
| 312 } | 380 } |
| 313 | 381 |
| 314 static void irc_close(GaimConnection *gc) | 382 static void irc_close(GaimConnection *gc) |
| 315 { | 383 { |
| 316 struct irc_conn *irc = gc->proto_data; | 384 struct irc_conn *irc = gc->proto_data; |
| 322 | 390 |
| 323 if (gc->inpa) | 391 if (gc->inpa) |
| 324 gaim_input_remove(gc->inpa); | 392 gaim_input_remove(gc->inpa); |
| 325 | 393 |
| 326 g_free(irc->inbuf); | 394 g_free(irc->inbuf); |
| 327 close(irc->fd); | 395 if (irc->gsc) { |
| 396 gaim_ssl_close(irc->gsc); | |
| 397 } else if (irc->fd > 0) { | |
| 398 close(irc->fd); | |
| 399 } | |
| 328 if (irc->timer) | 400 if (irc->timer) |
| 329 gaim_timeout_remove(irc->timer); | 401 gaim_timeout_remove(irc->timer); |
| 330 g_hash_table_destroy(irc->cmds); | 402 g_hash_table_destroy(irc->cmds); |
| 331 g_hash_table_destroy(irc->msgs); | 403 g_hash_table_destroy(irc->msgs); |
| 332 if (irc->motd) | 404 if (irc->motd) |
| 391 { | 463 { |
| 392 struct irc_conn *irc = (struct irc_conn *)gc->proto_data; | 464 struct irc_conn *irc = (struct irc_conn *)gc->proto_data; |
| 393 g_hash_table_remove(irc->buddies, buddy->name); | 465 g_hash_table_remove(irc->buddies, buddy->name); |
| 394 } | 466 } |
| 395 | 467 |
| 396 static void irc_input_cb(gpointer data, gint source, GaimInputCondition cond) | 468 static void read_input(struct irc_conn *irc, int len) |
| 397 { | 469 { |
| 398 GaimConnection *gc = data; | |
| 399 struct irc_conn *irc = gc->proto_data; | |
| 400 char *cur, *end; | 470 char *cur, *end; |
| 401 int len; | |
| 402 | |
| 403 if (irc->inbuflen < irc->inbufused + IRC_INITIAL_BUFSIZE) { | |
| 404 irc->inbuflen += IRC_INITIAL_BUFSIZE; | |
| 405 irc->inbuf = g_realloc(irc->inbuf, irc->inbuflen); | |
| 406 } | |
| 407 | |
| 408 if ((len = read(irc->fd, irc->inbuf + irc->inbufused, IRC_INITIAL_BUFSIZE - 1)) < 0) { | |
| 409 gaim_connection_error(gc, _("Read error")); | |
| 410 return; | |
| 411 } else if (len == 0) { | |
| 412 gaim_connection_error(gc, _("Server has disconnected")); | |
| 413 return; | |
| 414 } | |
| 415 | 471 |
| 416 irc->inbufused += len; | 472 irc->inbufused += len; |
| 417 irc->inbuf[irc->inbufused] = '\0'; | 473 irc->inbuf[irc->inbufused] = '\0'; |
| 418 | 474 |
| 419 cur = irc->inbuf; | 475 cur = irc->inbuf; |
| 428 irc->inbufused -= (cur - irc->inbuf); | 484 irc->inbufused -= (cur - irc->inbuf); |
| 429 memmove(irc->inbuf, cur, irc->inbufused); | 485 memmove(irc->inbuf, cur, irc->inbufused); |
| 430 } else { | 486 } else { |
| 431 irc->inbufused = 0; | 487 irc->inbufused = 0; |
| 432 } | 488 } |
| 489 } | |
| 490 | |
| 491 static void irc_input_cb_ssl(gpointer data, GaimSslConnection *gsc, | |
| 492 GaimInputCondition cond) | |
| 493 { | |
| 494 | |
| 495 GaimConnection *gc = data; | |
| 496 struct irc_conn *irc = gc->proto_data; | |
| 497 int len; | |
| 498 | |
| 499 if(!g_list_find(gaim_connections_get_all(), gc)) { | |
| 500 gaim_ssl_close(gsc); | |
| 501 return; | |
| 502 } | |
| 503 | |
| 504 if (irc->inbuflen < irc->inbufused + IRC_INITIAL_BUFSIZE) { | |
| 505 irc->inbuflen += IRC_INITIAL_BUFSIZE; | |
| 506 irc->inbuf = g_realloc(irc->inbuf, irc->inbuflen); | |
| 507 } | |
| 508 | |
| 509 if ((len = gaim_ssl_read(gsc, irc->inbuf + irc->inbufused, IRC_INITIAL_BUFSIZE - 1)) < 0) { | |
| 510 gaim_connection_error(gc, _("Read error")); | |
| 511 return; | |
| 512 } else if (len == 0) { | |
| 513 gaim_connection_error(gc, _("Server has disconnected")); | |
| 514 return; | |
| 515 } | |
| 516 | |
| 517 read_input(irc, len); | |
| 518 } | |
| 519 | |
| 520 static void irc_input_cb(gpointer data, gint source, GaimInputCondition cond) | |
| 521 { | |
| 522 GaimConnection *gc = data; | |
| 523 struct irc_conn *irc = gc->proto_data; | |
| 524 int len; | |
| 525 | |
| 526 if (irc->inbuflen < irc->inbufused + IRC_INITIAL_BUFSIZE) { | |
| 527 irc->inbuflen += IRC_INITIAL_BUFSIZE; | |
| 528 irc->inbuf = g_realloc(irc->inbuf, irc->inbuflen); | |
| 529 } | |
| 530 | |
| 531 if ((len = read(irc->fd, irc->inbuf + irc->inbufused, IRC_INITIAL_BUFSIZE - 1)) < 0) { | |
| 532 gaim_connection_error(gc, _("Read error")); | |
| 533 return; | |
| 534 } else if (len == 0) { | |
| 535 gaim_connection_error(gc, _("Server has disconnected")); | |
| 536 return; | |
| 537 } | |
| 538 | |
| 539 read_input(irc, len); | |
| 433 } | 540 } |
| 434 | 541 |
| 435 static void irc_chat_join (GaimConnection *gc, GHashTable *data) | 542 static void irc_chat_join (GaimConnection *gc, GHashTable *data) |
| 436 { | 543 { |
| 437 struct irc_conn *irc = gc->proto_data; | 544 struct irc_conn *irc = gc->proto_data; |
| 704 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | 811 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); |
| 705 | 812 |
| 706 option = gaim_account_option_string_new(_("Real name"), "realname", ""); | 813 option = gaim_account_option_string_new(_("Real name"), "realname", ""); |
| 707 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | 814 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); |
| 708 | 815 |
| 816 option = gaim_account_option_bool_new(_("Use SSL"), "ssl", FALSE); | |
| 817 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
| 818 | |
| 709 _irc_plugin = plugin; | 819 _irc_plugin = plugin; |
| 710 | 820 |
| 711 irc_register_commands(); | 821 irc_register_commands(); |
| 712 } | 822 } |
| 713 | 823 |
