comparison libpurple/protocols/jabber/jabber.c @ 24056:1de1494a13e5

propagate from branch 'im.pidgin.pidgin' (head e685599ddcc769d157547685b5498df0662de8a2) to branch 'im.pidgin.xmpp.custom_smiley' (head 110555eba89887adcf842166213ffc82770c0ee4)
author Sadrul Habib Chowdhury <imadil@gmail.com>
date Thu, 04 Sep 2008 21:27:33 +0000
parents c45d05bd58ed 3c3032be12de
children 305fac6af8f9
comparison
equal deleted inserted replaced
23781:c45d05bd58ed 24056:1de1494a13e5
63 63
64 static PurplePlugin *my_protocol = NULL; 64 static PurplePlugin *my_protocol = NULL;
65 GList *jabber_features = NULL; 65 GList *jabber_features = NULL;
66 66
67 static void jabber_unregister_account_cb(JabberStream *js); 67 static void jabber_unregister_account_cb(JabberStream *js);
68 static void try_srv_connect(JabberStream *js);
68 69
69 static void jabber_stream_init(JabberStream *js) 70 static void jabber_stream_init(JabberStream *js)
70 { 71 {
71 char *open_stream; 72 char *open_stream;
72 73
273 } 274 }
274 275
275 purple_circ_buffer_mark_read(js->write_buffer, ret); 276 purple_circ_buffer_mark_read(js->write_buffer, ret);
276 } 277 }
277 278
278 void jabber_send_raw(JabberStream *js, const char *data, int len) 279 static gboolean do_jabber_send_raw(JabberStream *js, const char *data, int len)
279 { 280 {
280 int ret; 281 int ret;
281 282 gboolean success = TRUE;
282 /* because printing a tab to debug every minute gets old */
283 if(strcmp(data, "\t"))
284 purple_debug(PURPLE_DEBUG_MISC, "jabber", "Sending%s: %s\n",
285 js->gsc ? " (ssl)" : "", data);
286
287 /* If we've got a security layer, we need to encode the data,
288 * splitting it on the maximum buffer length negotiated */
289
290 purple_signal_emit(my_protocol, "jabber-sending-text", js->gc, &data);
291 if (data == NULL)
292 return;
293
294 #ifdef HAVE_CYRUS_SASL
295 if (js->sasl_maxbuf>0) {
296 int pos;
297
298 if (!js->gsc && js->fd<0)
299 return;
300 pos = 0;
301 if (len == -1)
302 len = strlen(data);
303 while (pos < len) {
304 int towrite;
305 const char *out;
306 unsigned olen;
307
308 if ((len - pos) < js->sasl_maxbuf)
309 towrite = len - pos;
310 else
311 towrite = js->sasl_maxbuf;
312
313 sasl_encode(js->sasl, &data[pos], towrite, &out, &olen);
314 pos += towrite;
315
316 if (js->writeh == 0)
317 ret = jabber_do_send(js, out, olen);
318 else {
319 ret = -1;
320 errno = EAGAIN;
321 }
322
323 if (ret < 0 && errno != EAGAIN)
324 purple_connection_error_reason (js->gc,
325 PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
326 _("Write error"));
327 else if (ret < olen) {
328 if (ret < 0)
329 ret = 0;
330 if (js->writeh == 0)
331 js->writeh = purple_input_add(
332 js->gsc ? js->gsc->fd : js->fd,
333 PURPLE_INPUT_WRITE,
334 jabber_send_cb, js);
335 purple_circ_buffer_append(js->write_buffer,
336 out + ret, olen - ret);
337 }
338 }
339 return;
340 }
341 #endif
342 283
343 if (len == -1) 284 if (len == -1)
344 len = strlen(data); 285 len = strlen(data);
345 286
346 if (js->writeh == 0) 287 if (js->writeh == 0)
348 else { 289 else {
349 ret = -1; 290 ret = -1;
350 errno = EAGAIN; 291 errno = EAGAIN;
351 } 292 }
352 293
353 if (ret < 0 && errno != EAGAIN) 294 if (ret < 0 && errno != EAGAIN) {
354 purple_connection_error_reason (js->gc, 295 purple_connection_error_reason (js->gc,
355 PURPLE_CONNECTION_ERROR_NETWORK_ERROR, 296 PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
356 _("Write error")); 297 _("Write error"));
357 else if (ret < len) { 298 success = FALSE;
299 } else if (ret < len) {
358 if (ret < 0) 300 if (ret < 0)
359 ret = 0; 301 ret = 0;
360 if (js->writeh == 0) 302 if (js->writeh == 0)
361 js->writeh = purple_input_add( 303 js->writeh = purple_input_add(
362 js->gsc ? js->gsc->fd : js->fd, 304 js->gsc ? js->gsc->fd : js->fd,
363 PURPLE_INPUT_WRITE, jabber_send_cb, js); 305 PURPLE_INPUT_WRITE, jabber_send_cb, js);
364 purple_circ_buffer_append(js->write_buffer, 306 purple_circ_buffer_append(js->write_buffer,
365 data + ret, len - ret); 307 data + ret, len - ret);
366 } 308 }
367 return; 309
310 return success;
311 }
312
313 void jabber_send_raw(JabberStream *js, const char *data, int len)
314 {
315
316 /* because printing a tab to debug every minute gets old */
317 if(strcmp(data, "\t"))
318 purple_debug(PURPLE_DEBUG_MISC, "jabber", "Sending%s: %s\n",
319 js->gsc ? " (ssl)" : "", data);
320
321 /* If we've got a security layer, we need to encode the data,
322 * splitting it on the maximum buffer length negotiated */
323
324 purple_signal_emit(my_protocol, "jabber-sending-text", js->gc, &data);
325 if (data == NULL)
326 return;
327
328 #ifdef HAVE_CYRUS_SASL
329 if (js->sasl_maxbuf>0) {
330 int pos = 0;
331
332 if (!js->gsc && js->fd<0)
333 return;
334
335 if (len == -1)
336 len = strlen(data);
337
338 while (pos < len) {
339 int towrite;
340 const char *out;
341 unsigned olen;
342
343 towrite = MIN((len - pos), js->sasl_maxbuf);
344
345 sasl_encode(js->sasl, &data[pos], towrite, &out, &olen);
346 pos += towrite;
347
348 if (!do_jabber_send_raw(js, out, olen))
349 break;
350 }
351 return;
352 }
353 #endif
354
355 do_jabber_send_raw(js, data, len);
368 } 356 }
369 357
370 int jabber_prpl_send_raw(PurpleConnection *gc, const char *buf, int len) 358 int jabber_prpl_send_raw(PurpleConnection *gc, const char *buf, int len)
371 { 359 {
372 JabberStream *js = (JabberStream*)gc->proto_data; 360 JabberStream *js = (JabberStream*)gc->proto_data;
388 txt = xmlnode_to_str(packet, &len); 376 txt = xmlnode_to_str(packet, &len);
389 jabber_send_raw(js, txt, len); 377 jabber_send_raw(js, txt, len);
390 g_free(txt); 378 g_free(txt);
391 } 379 }
392 380
393 static void jabber_pong_cb(JabberStream *js, xmlnode *packet, gpointer timeout) 381 static void jabber_pong_cb(JabberStream *js, xmlnode *packet, gpointer unused)
394 { 382 {
395 purple_timeout_remove(GPOINTER_TO_INT(timeout)); 383 purple_timeout_remove(js->keepalive_timeout);
396 js->keepalive_timeout = -1; 384 js->keepalive_timeout = -1;
397 } 385 }
398 386
399 static gboolean jabber_pong_timeout(PurpleConnection *gc) 387 static gboolean jabber_pong_timeout(PurpleConnection *gc)
400 { 388 {
414 402
415 xmlnode *ping = xmlnode_new_child(iq->node, "ping"); 403 xmlnode *ping = xmlnode_new_child(iq->node, "ping");
416 xmlnode_set_namespace(ping, "urn:xmpp:ping"); 404 xmlnode_set_namespace(ping, "urn:xmpp:ping");
417 405
418 js->keepalive_timeout = purple_timeout_add_seconds(120, (GSourceFunc)(jabber_pong_timeout), gc); 406 js->keepalive_timeout = purple_timeout_add_seconds(120, (GSourceFunc)(jabber_pong_timeout), gc);
419 jabber_iq_set_callback(iq, jabber_pong_cb, GINT_TO_POINTER(js->keepalive_timeout)); 407 jabber_iq_set_callback(iq, jabber_pong_cb, NULL);
420 jabber_iq_send(iq); 408 jabber_iq_send(iq);
421 } 409 }
422 } 410 }
423 411
424 static void 412 static void
443 jabber_parser_process(js, buf, len); 431 jabber_parser_process(js, buf, len);
444 if(js->reinit) 432 if(js->reinit)
445 jabber_stream_init(js); 433 jabber_stream_init(js);
446 } 434 }
447 435
448 if(errno == EAGAIN) 436 if(len < 0 && errno == EAGAIN)
449 return; 437 return;
450 else 438 else {
439 if (len == 0)
440 purple_debug_info("jabber", "Server closed the connection.\n");
441 else
442 purple_debug_info("jabber", "Disconnected: %s\n", g_strerror(errno));
451 purple_connection_error_reason (js->gc, 443 purple_connection_error_reason (js->gc,
452 PURPLE_CONNECTION_ERROR_NETWORK_ERROR, 444 PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
453 _("Read Error")); 445 _("Read Error"));
446 }
454 } 447 }
455 448
456 static void 449 static void
457 jabber_recv_cb(gpointer data, gint source, PurpleInputCondition condition) 450 jabber_recv_cb(gpointer data, gint source, PurpleInputCondition condition)
458 { 451 {
483 buf[len] = '\0'; 476 buf[len] = '\0';
484 purple_debug(PURPLE_DEBUG_INFO, "jabber", "Recv (%d): %s\n", len, buf); 477 purple_debug(PURPLE_DEBUG_INFO, "jabber", "Recv (%d): %s\n", len, buf);
485 jabber_parser_process(js, buf, len); 478 jabber_parser_process(js, buf, len);
486 if(js->reinit) 479 if(js->reinit)
487 jabber_stream_init(js); 480 jabber_stream_init(js);
488 } else if(errno == EAGAIN) { 481 } else if(len < 0 && errno == EAGAIN) {
489 return; 482 return;
490 } else { 483 } else {
484 if (len == 0)
485 purple_debug_info("jabber", "Server closed the connection.\n");
486 else
487 purple_debug_info("jabber", "Disconnected: %s\n", g_strerror(errno));
491 purple_connection_error_reason (js->gc, 488 purple_connection_error_reason (js->gc,
492 PURPLE_CONNECTION_ERROR_NETWORK_ERROR, 489 PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
493 _("Read Error")); 490 _("Read Error"));
494 } 491 }
495 } 492 }
524 { 521 {
525 PurpleConnection *gc = data; 522 PurpleConnection *gc = data;
526 JabberStream *js = gc->proto_data; 523 JabberStream *js = gc->proto_data;
527 524
528 if (source < 0) { 525 if (source < 0) {
529 gchar *tmp; 526 if (js->srv_rec != NULL) {
530 tmp = g_strdup_printf(_("Could not establish a connection with the server:\n%s"), 527 purple_debug_error("jabber", "Unable to connect to server: %s. Trying next SRV record.\n", error);
531 error); 528 try_srv_connect(js);
532 purple_connection_error_reason (gc, 529 } else {
533 PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp); 530 gchar *tmp;
534 g_free(tmp); 531 tmp = g_strdup_printf(_("Could not establish a connection with the server:\n%s"),
532 error);
533 purple_connection_error_reason(gc,
534 PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
535 g_free(tmp);
536 }
535 return; 537 return;
536 } 538 }
539
540 g_free(js->srv_rec);
541 js->srv_rec = NULL;
537 542
538 js->fd = source; 543 js->fd = source;
539 544
540 if(js->state == JABBER_STREAM_CONNECTING) 545 if(js->state == JABBER_STREAM_CONNECTING)
541 jabber_send_raw(js, "<?xml version='1.0' ?>", -1); 546 jabber_send_raw(js, "<?xml version='1.0' ?>", -1);
567 js->gc->inpa = 0; 572 js->gc->inpa = 0;
568 js->gsc = purple_ssl_connect_with_host_fd(js->gc->account, js->fd, 573 js->gsc = purple_ssl_connect_with_host_fd(js->gc->account, js->fd,
569 jabber_login_callback_ssl, jabber_ssl_connect_failure, js->certificate_CN, js->gc); 574 jabber_login_callback_ssl, jabber_ssl_connect_failure, js->certificate_CN, js->gc);
570 } 575 }
571 576
572 static void jabber_login_connect(JabberStream *js, const char *domain, const char *host, int port) 577 static gboolean jabber_login_connect(JabberStream *js, const char *domain, const char *host, int port,
578 gboolean fatal_failure)
573 { 579 {
574 /* host should be used in preference to domain to 580 /* host should be used in preference to domain to
575 * allow SASL authentication to work with FQDN of the server, 581 * allow SASL authentication to work with FQDN of the server,
576 * but we use domain as fallback for when users enter IP address 582 * but we use domain as fallback for when users enter IP address
577 * in connect server */ 583 * in connect server */
584 g_free(js->serverFQDN);
578 if (purple_ip_address_is_valid(host)) 585 if (purple_ip_address_is_valid(host))
579 js->serverFQDN = g_strdup(domain); 586 js->serverFQDN = g_strdup(domain);
580 else 587 else
581 js->serverFQDN = g_strdup(host); 588 js->serverFQDN = g_strdup(host);
582 589
583 if (purple_proxy_connect(js->gc, js->gc->account, host, 590 if (purple_proxy_connect(js->gc, js->gc->account, host,
584 port, jabber_login_callback, js->gc) == NULL) 591 port, jabber_login_callback, js->gc) == NULL) {
585 purple_connection_error_reason (js->gc, 592 if (fatal_failure) {
586 PURPLE_CONNECTION_ERROR_NETWORK_ERROR, 593 purple_connection_error_reason (js->gc,
587 _("Unable to create socket")); 594 PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
595 _("Unable to create socket"));
596 }
597
598 return FALSE;
599 }
600
601 return TRUE;
602 }
603
604 static void try_srv_connect(JabberStream *js)
605 {
606 while (js->srv_rec != NULL && js->srv_rec_idx < js->max_srv_rec_idx) {
607 PurpleSrvResponse *tmp_resp = js->srv_rec + (js->srv_rec_idx++);
608 if (jabber_login_connect(js, tmp_resp->hostname, tmp_resp->hostname, tmp_resp->port, FALSE))
609 return;
610 }
611
612 g_free(js->srv_rec);
613 js->srv_rec = NULL;
614
615 /* Fall back to the defaults (I'm not sure if we should actually do this) */
616 jabber_login_connect(js, js->user->domain, js->user->domain,
617 purple_account_get_int(js->gc->account, "port", 5222), TRUE);
588 } 618 }
589 619
590 static void srv_resolved_cb(PurpleSrvResponse *resp, int results, gpointer data) 620 static void srv_resolved_cb(PurpleSrvResponse *resp, int results, gpointer data)
591 { 621 {
592 JabberStream *js; 622 JabberStream *js = data;
593
594 js = data;
595 js->srv_query_data = NULL; 623 js->srv_query_data = NULL;
596 624
597 if(results) { 625 if(results) {
598 jabber_login_connect(js, resp->hostname, resp->hostname, resp->port); 626 js->srv_rec = resp;
599 g_free(resp); 627 js->srv_rec_idx = 0;
628 js->max_srv_rec_idx = results;
629 try_srv_connect(js);
600 } else { 630 } else {
601 jabber_login_connect(js, js->user->domain, js->user->domain, 631 jabber_login_connect(js, js->user->domain, js->user->domain,
602 purple_account_get_int(js->gc->account, "port", 5222)); 632 purple_account_get_int(js->gc->account, "port", 5222), TRUE);
603 } 633 }
604 } 634 }
605 635
606 void 636 void
607 jabber_login(PurpleAccount *account) 637 jabber_login(PurpleAccount *account)
680 710
681 /* no old-ssl, so if they've specified a connect server, we'll use that, otherwise we'll 711 /* no old-ssl, so if they've specified a connect server, we'll use that, otherwise we'll
682 * invoke the magic of SRV lookups, to figure out host and port */ 712 * invoke the magic of SRV lookups, to figure out host and port */
683 if(!js->gsc) { 713 if(!js->gsc) {
684 if(connect_server[0]) { 714 if(connect_server[0]) {
685 jabber_login_connect(js, js->user->domain, connect_server, purple_account_get_int(account, "port", 5222)); 715 jabber_login_connect(js, js->user->domain, connect_server, purple_account_get_int(account, "port", 5222), TRUE);
686 } else { 716 } else {
687 js->srv_query_data = purple_srv_resolve("xmpp-client", 717 js->srv_query_data = purple_srv_resolve("xmpp-client",
688 "tcp", js->user->domain, srv_resolved_cb, js); 718 "tcp", js->user->domain, srv_resolved_cb, js);
689 } 719 }
690 } 720 }
1161 1191
1162 if(!js->gsc) { 1192 if(!js->gsc) {
1163 if (connect_server[0]) { 1193 if (connect_server[0]) {
1164 jabber_login_connect(js, js->user->domain, server, 1194 jabber_login_connect(js, js->user->domain, server,
1165 purple_account_get_int(account, 1195 purple_account_get_int(account,
1166 "port", 5222)); 1196 "port", 5222), TRUE);
1167 } else { 1197 } else {
1168 js->srv_query_data = purple_srv_resolve("xmpp-client", 1198 js->srv_query_data = purple_srv_resolve("xmpp-client",
1169 "tcp", 1199 "tcp",
1170 js->user->domain, 1200 js->user->domain,
1171 srv_resolved_cb, 1201 srv_resolved_cb,
1291 g_free(sh->jid); 1321 g_free(sh->jid);
1292 g_free(sh->host); 1322 g_free(sh->host);
1293 g_free(sh->zeroconf); 1323 g_free(sh->zeroconf);
1294 g_free(sh); 1324 g_free(sh);
1295 js->bs_proxies = g_list_delete_link(js->bs_proxies, js->bs_proxies); 1325 js->bs_proxies = g_list_delete_link(js->bs_proxies, js->bs_proxies);
1326 }
1327
1328 while(js->url_datas) {
1329 purple_util_fetch_url_cancel(js->url_datas->data);
1330 js->url_datas = g_slist_delete_link(js->url_datas, js->url_datas);
1296 } 1331 }
1297 1332
1298 g_free(js->stream_id); 1333 g_free(js->stream_id);
1299 if(js->user) 1334 if(js->user)
1300 jabber_id_free(js->user); 1335 jabber_id_free(js->user);
1332 g_free(js->old_track); 1367 g_free(js->old_track);
1333 g_free(js->expected_rspauth); 1368 g_free(js->expected_rspauth);
1334 1369
1335 if (js->keepalive_timeout != -1) 1370 if (js->keepalive_timeout != -1)
1336 purple_timeout_remove(js->keepalive_timeout); 1371 purple_timeout_remove(js->keepalive_timeout);
1337 1372
1373 g_free(js->srv_rec);
1374 js->srv_rec = NULL;
1375
1338 g_free(js); 1376 g_free(js);
1339 1377
1340 gc->proto_data = NULL; 1378 gc->proto_data = NULL;
1341 } 1379 }
1342 1380