Mercurial > pidgin
comparison libpurple/protocols/jabber/jabber.c @ 26485:242a8c97270b
propagate from branch 'im.pidgin.pidgin' (head f144c6bda9daf701aa891c875fce7a4dedd611ae)
to branch 'im.pidgin.cpw.darkrain42.xmpp.avatars' (head 94d20f2f1d6e10ad1543c226dc01fb5c518bcea0)
author | Paul Aurich <paul@darkrain42.org> |
---|---|
date | Sun, 05 Apr 2009 21:49:01 +0000 |
parents | 7027cc42e56c 2b8c161c9d7b |
children | d6a863df7884 |
comparison
equal
deleted
inserted
replaced
26278:14e1f9af369f | 26485:242a8c97270b |
---|---|
58 #include "si.h" | 58 #include "si.h" |
59 #include "xdata.h" | 59 #include "xdata.h" |
60 #include "pep.h" | 60 #include "pep.h" |
61 #include "adhoccommands.h" | 61 #include "adhoccommands.h" |
62 | 62 |
63 #include "jingle/jingle.h" | |
64 #include "jingle/rtp.h" | |
63 | 65 |
64 #define JABBER_CONNECT_STEPS (js->gsc ? 9 : 5) | 66 #define JABBER_CONNECT_STEPS (js->gsc ? 9 : 5) |
65 | 67 |
66 static PurplePlugin *my_protocol = NULL; | 68 static PurplePlugin *my_protocol = NULL; |
67 GList *jabber_features = NULL; | 69 GList *jabber_features = NULL; |
84 js->reinit = FALSE; | 86 js->reinit = FALSE; |
85 g_free(open_stream); | 87 g_free(open_stream); |
86 } | 88 } |
87 | 89 |
88 static void | 90 static void |
89 jabber_session_initialized_cb(JabberStream *js, xmlnode *packet, gpointer data) | 91 jabber_session_initialized_cb(JabberStream *js, const char *from, |
90 { | 92 JabberIqType type, const char *id, |
91 const char *type = xmlnode_get_attrib(packet, "type"); | 93 xmlnode *packet, gpointer data) |
92 if(type && !strcmp(type, "result")) { | 94 { |
95 if (type == JABBER_IQ_RESULT) { | |
93 jabber_stream_set_state(js, JABBER_STREAM_CONNECTED); | 96 jabber_stream_set_state(js, JABBER_STREAM_CONNECTED); |
94 if(js->unregistration) | 97 if(js->unregistration) |
95 jabber_unregister_account_cb(js); | 98 jabber_unregister_account_cb(js); |
96 } else { | 99 } else { |
97 purple_connection_error_reason (js->gc, | 100 purple_connection_error_reason (js->gc, |
111 xmlnode_set_namespace(session, "urn:ietf:params:xml:ns:xmpp-session"); | 114 xmlnode_set_namespace(session, "urn:ietf:params:xml:ns:xmpp-session"); |
112 | 115 |
113 jabber_iq_send(iq); | 116 jabber_iq_send(iq); |
114 } | 117 } |
115 | 118 |
116 static void jabber_bind_result_cb(JabberStream *js, xmlnode *packet, | 119 static void jabber_bind_result_cb(JabberStream *js, const char *from, |
117 gpointer data) | 120 JabberIqType type, const char *id, |
118 { | 121 xmlnode *packet, gpointer data) |
119 const char *type = xmlnode_get_attrib(packet, "type"); | 122 { |
120 xmlnode *bind; | 123 xmlnode *bind; |
121 | 124 |
122 if(type && !strcmp(type, "result") && | 125 if (type == JABBER_IQ_RESULT && |
123 (bind = xmlnode_get_child_with_namespace(packet, "bind", "urn:ietf:params:xml:ns:xmpp-bind"))) { | 126 (bind = xmlnode_get_child_with_namespace(packet, "bind", "urn:ietf:params:xml:ns:xmpp-bind"))) { |
124 xmlnode *jid; | 127 xmlnode *jid; |
125 char *full_jid; | 128 char *full_jid; |
126 if((jid = xmlnode_get_child(bind, "jid")) && (full_jid = xmlnode_get_data(jid))) { | 129 if((jid = xmlnode_get_child(bind, "jid")) && (full_jid = xmlnode_get_data(jid))) { |
127 JabberBuddy *my_jb = NULL; | 130 JabberBuddy *my_jb = NULL; |
445 txt = xmlnode_to_str(packet, &len); | 448 txt = xmlnode_to_str(packet, &len); |
446 jabber_send_raw(js, txt, len); | 449 jabber_send_raw(js, txt, len); |
447 g_free(txt); | 450 g_free(txt); |
448 } | 451 } |
449 | 452 |
450 static void jabber_pong_cb(JabberStream *js, xmlnode *packet, gpointer unused) | 453 static gboolean jabber_keepalive_timeout(PurpleConnection *gc) |
451 { | |
452 purple_timeout_remove(js->keepalive_timeout); | |
453 js->keepalive_timeout = -1; | |
454 } | |
455 | |
456 static gboolean jabber_pong_timeout(PurpleConnection *gc) | |
457 { | 454 { |
458 JabberStream *js = gc->proto_data; | 455 JabberStream *js = gc->proto_data; |
459 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, | 456 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, |
460 _("Ping timeout")); | 457 _("Ping timeout")); |
461 js->keepalive_timeout = -1; | 458 js->keepalive_timeout = -1; |
465 void jabber_keepalive(PurpleConnection *gc) | 462 void jabber_keepalive(PurpleConnection *gc) |
466 { | 463 { |
467 JabberStream *js = gc->proto_data; | 464 JabberStream *js = gc->proto_data; |
468 | 465 |
469 if (js->keepalive_timeout == -1) { | 466 if (js->keepalive_timeout == -1) { |
470 JabberIq *iq = jabber_iq_new(js, JABBER_IQ_GET); | 467 jabber_ping_jid(js, NULL); |
471 | 468 js->keepalive_timeout = purple_timeout_add_seconds(120, |
472 xmlnode *ping = xmlnode_new_child(iq->node, "ping"); | 469 (GSourceFunc)(jabber_keepalive_timeout), gc); |
473 xmlnode_set_namespace(ping, "urn:xmpp:ping"); | |
474 | |
475 js->keepalive_timeout = purple_timeout_add_seconds(120, (GSourceFunc)(jabber_pong_timeout), gc); | |
476 jabber_iq_set_callback(iq, jabber_pong_cb, NULL); | |
477 jabber_iq_send(iq); | |
478 } | 470 } |
479 } | 471 } |
480 | 472 |
481 static void | 473 static void |
482 jabber_recv_cb_ssl(gpointer data, PurpleSslConnection *gsc, | 474 jabber_recv_cb_ssl(gpointer data, PurpleSslConnection *gsc, |
729 js->next_id = g_random_int(); | 721 js->next_id = g_random_int(); |
730 js->write_buffer = purple_circ_buffer_new(512); | 722 js->write_buffer = purple_circ_buffer_new(512); |
731 js->old_length = 0; | 723 js->old_length = 0; |
732 js->keepalive_timeout = -1; | 724 js->keepalive_timeout = -1; |
733 js->certificate_CN = g_strdup(connect_server[0] ? connect_server : js->user ? js->user->domain : NULL); | 725 js->certificate_CN = g_strdup(connect_server[0] ? connect_server : js->user ? js->user->domain : NULL); |
726 js->sessions = NULL; | |
727 js->stun_ip = NULL; | |
728 js->stun_port = 0; | |
729 js->stun_query = NULL; | |
734 | 730 |
735 if(!js->user) { | 731 if(!js->user) { |
736 purple_connection_error_reason (gc, | 732 purple_connection_error_reason (gc, |
737 PURPLE_CONNECTION_ERROR_INVALID_SETTINGS, | 733 PURPLE_CONNECTION_ERROR_INVALID_SETTINGS, |
738 _("Invalid XMPP ID")); | 734 _("Invalid XMPP ID")); |
807 { | 803 { |
808 purple_timeout_add(0, conn_close_cb, js); | 804 purple_timeout_add(0, conn_close_cb, js); |
809 } | 805 } |
810 | 806 |
811 static void | 807 static void |
812 jabber_registration_result_cb(JabberStream *js, xmlnode *packet, gpointer data) | 808 jabber_registration_result_cb(JabberStream *js, const char *from, |
809 JabberIqType type, const char *id, | |
810 xmlnode *packet, gpointer data) | |
813 { | 811 { |
814 PurpleAccount *account = purple_connection_get_account(js->gc); | 812 PurpleAccount *account = purple_connection_get_account(js->gc); |
815 const char *type = xmlnode_get_attrib(packet, "type"); | |
816 char *buf; | 813 char *buf; |
817 char *to = data; | 814 char *to = data; |
818 | 815 |
819 if(!strcmp(type, "result")) { | 816 if (type == JABBER_IQ_RESULT) { |
820 if(js->registration) { | 817 if(js->registration) { |
821 buf = g_strdup_printf(_("Registration of %s@%s successful"), | 818 buf = g_strdup_printf(_("Registration of %s@%s successful"), |
822 js->user->node, js->user->domain); | 819 js->user->node, js->user->domain); |
823 if(account->registration_cb) | 820 if(account->registration_cb) |
824 (account->registration_cb)(account, TRUE, account->registration_cb_user_data); | 821 (account->registration_cb)(account, TRUE, account->registration_cb_user_data); |
842 if(account->registration_cb) | 839 if(account->registration_cb) |
843 (account->registration_cb)(account, FALSE, account->registration_cb_user_data); | 840 (account->registration_cb)(account, FALSE, account->registration_cb_user_data); |
844 } | 841 } |
845 g_free(to); | 842 g_free(to); |
846 if(js->registration) | 843 if(js->registration) |
847 jabber_connection_schedule_close(js); | 844 jabber_connection_schedule_close(js); |
848 } | 845 } |
849 | 846 |
850 static void | 847 static void |
851 jabber_unregistration_result_cb(JabberStream *js, xmlnode *packet, gpointer data) | 848 jabber_unregistration_result_cb(JabberStream *js, const char *from, |
852 { | 849 JabberIqType type, const char *id, |
853 const char *type = xmlnode_get_attrib(packet, "type"); | 850 xmlnode *packet, gpointer data) |
851 { | |
854 char *buf; | 852 char *buf; |
855 char *to = data; | 853 char *to = data; |
856 | 854 |
857 /* This function is never called for unregistering our XMPP account from | 855 /* This function is never called for unregistering our XMPP account from |
858 * the server, so there should always be a 'to' address. */ | 856 * the server, so there should always be a 'to' address. */ |
859 g_return_if_fail(to != NULL); | 857 g_return_if_fail(to != NULL); |
860 | 858 |
861 if(!strcmp(type, "result")) { | 859 if (type == JABBER_IQ_RESULT) { |
862 buf = g_strdup_printf(_("Registration from %s successfully removed"), | 860 buf = g_strdup_printf(_("Registration from %s successfully removed"), |
863 to); | 861 to); |
864 purple_notify_info(NULL, _("Unregistration Successful"), | 862 purple_notify_info(NULL, _("Unregistration Successful"), |
865 _("Unregistration Successful"), buf); | 863 _("Unregistration Successful"), buf); |
866 g_free(buf); | 864 g_free(buf); |
1005 | 1003 |
1006 jabber_iq_set_callback(iq, jabber_registration_result_cb, to); | 1004 jabber_iq_set_callback(iq, jabber_registration_result_cb, to); |
1007 jabber_iq_send(iq); | 1005 jabber_iq_send(iq); |
1008 } | 1006 } |
1009 | 1007 |
1010 void jabber_register_parse(JabberStream *js, xmlnode *packet) | 1008 void jabber_register_parse(JabberStream *js, const char *from, JabberIqType type, |
1009 const char *id, xmlnode *query) | |
1011 { | 1010 { |
1012 PurpleAccount *account = purple_connection_get_account(js->gc); | 1011 PurpleAccount *account = purple_connection_get_account(js->gc); |
1013 const char *type; | |
1014 const char *from; | |
1015 PurpleRequestFields *fields; | 1012 PurpleRequestFields *fields; |
1016 PurpleRequestFieldGroup *group; | 1013 PurpleRequestFieldGroup *group; |
1017 PurpleRequestField *field; | 1014 PurpleRequestField *field; |
1018 xmlnode *query, *x, *y; | 1015 xmlnode *x, *y; |
1019 char *instructions; | 1016 char *instructions; |
1020 JabberRegisterCBData *cbdata; | 1017 JabberRegisterCBData *cbdata; |
1021 gboolean registered = FALSE; | 1018 gboolean registered = FALSE; |
1022 | 1019 |
1023 if(!(type = xmlnode_get_attrib(packet, "type")) || strcmp(type, "result")) | 1020 if (type != JABBER_IQ_RESULT) |
1024 return; | 1021 return; |
1025 | 1022 |
1026 from = xmlnode_get_attrib(packet, "from"); | 1023 if (!from) |
1024 from = js->serverFQDN; | |
1025 g_return_if_fail(from != NULL); | |
1027 | 1026 |
1028 if(js->registration) { | 1027 if(js->registration) { |
1029 /* get rid of the login thingy */ | 1028 /* get rid of the login thingy */ |
1030 purple_connection_set_state(js->gc, PURPLE_CONNECTED); | 1029 purple_connection_set_state(js->gc, PURPLE_CONNECTED); |
1031 } | 1030 } |
1032 | |
1033 query = xmlnode_get_child(packet, "query"); | |
1034 | 1031 |
1035 if(xmlnode_get_child(query, "registered")) { | 1032 if(xmlnode_get_child(query, "registered")) { |
1036 registered = TRUE; | 1033 registered = TRUE; |
1037 | 1034 |
1038 if(js->registration) { | 1035 if(js->registration) { |
1234 my_jb->subscription |= JABBER_SUB_BOTH; | 1231 my_jb->subscription |= JABBER_SUB_BOTH; |
1235 | 1232 |
1236 server = connect_server[0] ? connect_server : js->user->domain; | 1233 server = connect_server[0] ? connect_server : js->user->domain; |
1237 js->certificate_CN = g_strdup(server); | 1234 js->certificate_CN = g_strdup(server); |
1238 | 1235 |
1236 js->stun_ip = NULL; | |
1237 js->stun_port = 0; | |
1238 js->stun_query = NULL; | |
1239 | |
1239 jabber_stream_set_state(js, JABBER_STREAM_CONNECTING); | 1240 jabber_stream_set_state(js, JABBER_STREAM_CONNECTING); |
1240 | 1241 |
1241 if(purple_account_get_bool(account, "old_ssl", FALSE)) { | 1242 if(purple_account_get_bool(account, "old_ssl", FALSE)) { |
1242 if(purple_ssl_is_supported()) { | 1243 if(purple_ssl_is_supported()) { |
1243 js->gsc = purple_ssl_connect(account, server, | 1244 js->gsc = purple_ssl_connect(account, server, |
1263 js); | 1264 js); |
1264 } | 1265 } |
1265 } | 1266 } |
1266 } | 1267 } |
1267 | 1268 |
1268 static void jabber_unregister_account_iq_cb(JabberStream *js, xmlnode *packet, gpointer data) { | 1269 static void |
1270 jabber_unregister_account_iq_cb(JabberStream *js, const char *from, | |
1271 JabberIqType type, const char *id, | |
1272 xmlnode *packet, gpointer data) | |
1273 { | |
1269 PurpleAccount *account = purple_connection_get_account(js->gc); | 1274 PurpleAccount *account = purple_connection_get_account(js->gc); |
1270 const char *type = xmlnode_get_attrib(packet,"type"); | 1275 |
1271 if(!strcmp(type,"error")) { | 1276 if (type == JABBER_IQ_ERROR) { |
1272 char *msg = jabber_parse_error(js, packet, NULL); | 1277 char *msg = jabber_parse_error(js, packet, NULL); |
1273 | 1278 |
1274 purple_notify_error(js->gc, _("Error unregistering account"), | 1279 purple_notify_error(js->gc, _("Error unregistering account"), |
1275 _("Error unregistering account"), msg); | 1280 _("Error unregistering account"), msg); |
1276 g_free(msg); | 1281 g_free(msg); |
1277 if(js->unregistration_cb) | 1282 if(js->unregistration_cb) |
1278 js->unregistration_cb(account, FALSE, js->unregistration_user_data); | 1283 js->unregistration_cb(account, FALSE, js->unregistration_user_data); |
1279 } else if(!strcmp(type,"result")) { | 1284 } else { |
1280 purple_notify_info(js->gc, _("Account successfully unregistered"), | 1285 purple_notify_info(js->gc, _("Account successfully unregistered"), |
1281 _("Account successfully unregistered"), NULL); | 1286 _("Account successfully unregistered"), NULL); |
1282 if(js->unregistration_cb) | 1287 if(js->unregistration_cb) |
1283 js->unregistration_cb(account, TRUE, js->unregistration_user_data); | 1288 js->unregistration_cb(account, TRUE, js->unregistration_user_data); |
1284 } | 1289 } |
1330 } | 1335 } |
1331 | 1336 |
1332 void jabber_close(PurpleConnection *gc) | 1337 void jabber_close(PurpleConnection *gc) |
1333 { | 1338 { |
1334 JabberStream *js = gc->proto_data; | 1339 JabberStream *js = gc->proto_data; |
1340 | |
1341 /* Close all of the open Jingle sessions on this stream */ | |
1342 jingle_terminate_sessions(js); | |
1335 | 1343 |
1336 /* Don't perform any actions on the ssl connection | 1344 /* Don't perform any actions on the ssl connection |
1337 * if we were forcibly disconnected because it will crash | 1345 * if we were forcibly disconnected because it will crash |
1338 * on some SSL backends. | 1346 * on some SSL backends. |
1339 */ | 1347 */ |
1433 purple_timeout_remove(js->keepalive_timeout); | 1441 purple_timeout_remove(js->keepalive_timeout); |
1434 | 1442 |
1435 g_free(js->srv_rec); | 1443 g_free(js->srv_rec); |
1436 js->srv_rec = NULL; | 1444 js->srv_rec = NULL; |
1437 | 1445 |
1446 g_free(js->stun_ip); | |
1447 js->stun_ip = NULL; | |
1448 | |
1449 /* cancel DNS query for STUN, if one is ongoing */ | |
1450 if (js->stun_query) { | |
1451 purple_dnsquery_destroy(js->stun_query); | |
1452 js->stun_query = NULL; | |
1453 } | |
1454 | |
1438 g_free(js); | 1455 g_free(js); |
1439 | 1456 |
1440 gc->proto_data = NULL; | 1457 gc->proto_data = NULL; |
1441 } | 1458 } |
1442 | 1459 |
1504 JabberStream *js = gc->proto_data; | 1521 JabberStream *js = gc->proto_data; |
1505 | 1522 |
1506 js->idle = idle ? time(NULL) - idle : idle; | 1523 js->idle = idle ? time(NULL) - idle : idle; |
1507 } | 1524 } |
1508 | 1525 |
1509 static void jabber_blocklist_parse(JabberStream *js, xmlnode *packet, gpointer data) | 1526 static void jabber_blocklist_parse(JabberStream *js, const char *from, |
1527 JabberIqType type, const char *id, | |
1528 xmlnode *packet, gpointer data) | |
1510 { | 1529 { |
1511 xmlnode *blocklist, *item; | 1530 xmlnode *blocklist, *item; |
1512 PurpleAccount *account; | 1531 PurpleAccount *account; |
1513 | 1532 |
1514 blocklist = xmlnode_get_child_with_namespace(packet, | 1533 blocklist = xmlnode_get_child_with_namespace(packet, |
1928 | 1947 |
1929 return types; | 1948 return types; |
1930 } | 1949 } |
1931 | 1950 |
1932 static void | 1951 static void |
1933 jabber_password_change_result_cb(JabberStream *js, xmlnode *packet, | 1952 jabber_password_change_result_cb(JabberStream *js, const char *from, |
1934 gpointer data) | 1953 JabberIqType type, const char *id, |
1935 { | 1954 xmlnode *packet, gpointer data) |
1936 const char *type; | 1955 { |
1937 | 1956 if (type == JABBER_IQ_RESULT) { |
1938 type = xmlnode_get_attrib(packet, "type"); | |
1939 | |
1940 if(type && !strcmp(type, "result")) { | |
1941 purple_notify_info(js->gc, _("Password Changed"), _("Password Changed"), | 1957 purple_notify_info(js->gc, _("Password Changed"), _("Password Changed"), |
1942 _("Your password has been changed.")); | 1958 _("Your password has been changed.")); |
1943 | 1959 |
1944 purple_account_set_password(js->gc->account, (char *)data); | 1960 purple_account_set_password(js->gc->account, (char *)data); |
1945 } else { | 1961 } else { |
2467 } | 2483 } |
2468 | 2484 |
2469 static PurpleCmdRet jabber_cmd_ping(PurpleConversation *conv, | 2485 static PurpleCmdRet jabber_cmd_ping(PurpleConversation *conv, |
2470 const char *cmd, char **args, char **error, void *data) | 2486 const char *cmd, char **args, char **error, void *data) |
2471 { | 2487 { |
2488 PurpleAccount *account; | |
2489 PurpleConnection *pc; | |
2490 | |
2472 if(!args || !args[0]) | 2491 if(!args || !args[0]) |
2473 return PURPLE_CMD_RET_FAILED; | 2492 return PURPLE_CMD_RET_FAILED; |
2474 | 2493 |
2475 if(!jabber_ping_jid(conv, args[0])) { | 2494 account = purple_conversation_get_account(conv); |
2495 pc = purple_account_get_connection(account); | |
2496 | |
2497 if(!jabber_ping_jid(purple_connection_get_protocol_data(pc), args[0])) { | |
2476 *error = g_strdup_printf(_("Unable to ping user %s"), args[0]); | 2498 *error = g_strdup_printf(_("Unable to ping user %s"), args[0]); |
2477 return PURPLE_CMD_RET_FAILED; | 2499 return PURPLE_CMD_RET_FAILED; |
2478 } | 2500 } |
2479 | 2501 |
2480 return PURPLE_CMD_RET_OK; | 2502 return PURPLE_CMD_RET_OK; |
2600 | 2622 |
2601 | 2623 |
2602 gboolean jabber_offline_message(const PurpleBuddy *buddy) | 2624 gboolean jabber_offline_message(const PurpleBuddy *buddy) |
2603 { | 2625 { |
2604 return TRUE; | 2626 return TRUE; |
2627 } | |
2628 | |
2629 #ifdef USE_VV | |
2630 typedef struct { | |
2631 PurpleConnection *pc; | |
2632 gchar *who; | |
2633 PurpleMediaSessionType type; | |
2634 | |
2635 } JabberMediaRequest; | |
2636 | |
2637 static void | |
2638 jabber_media_cancel_cb(JabberMediaRequest *request, | |
2639 PurpleRequestFields *fields) | |
2640 { | |
2641 g_free(request->who); | |
2642 g_free(request); | |
2643 } | |
2644 | |
2645 static void | |
2646 jabber_media_ok_cb(JabberMediaRequest *request, PurpleRequestFields *fields) | |
2647 { | |
2648 PurpleRequestField *field = | |
2649 purple_request_fields_get_field(fields, "resource"); | |
2650 int selected_id = purple_request_field_choice_get_value(field); | |
2651 GList *labels = purple_request_field_choice_get_labels(field); | |
2652 gchar *who = g_strdup_printf("%s/%s", request->who, | |
2653 (gchar*)g_list_nth_data(labels, selected_id)); | |
2654 jabber_initiate_media(request->pc, who, request->type); | |
2655 | |
2656 g_free(who); | |
2657 g_free(request->who); | |
2658 g_free(request); | |
2659 } | |
2660 #endif | |
2661 | |
2662 gboolean | |
2663 jabber_initiate_media(PurpleConnection *gc, const char *who, | |
2664 PurpleMediaSessionType type) | |
2665 { | |
2666 #ifdef USE_VV | |
2667 JabberStream *js = (JabberStream *) gc->proto_data; | |
2668 JabberBuddy *jb; | |
2669 JabberBuddyResource *jbr = NULL; | |
2670 char *resource; | |
2671 | |
2672 if (!js) { | |
2673 purple_debug_error("jabber", | |
2674 "jabber_initiate_media: NULL stream\n"); | |
2675 return FALSE; | |
2676 } | |
2677 | |
2678 | |
2679 if((resource = jabber_get_resource(who)) != NULL) { | |
2680 /* they've specified a resource, no need to ask or | |
2681 * default or anything, just do it */ | |
2682 | |
2683 jb = jabber_buddy_find(js, who, FALSE); | |
2684 jbr = jabber_buddy_find_resource(jb, resource); | |
2685 g_free(resource); | |
2686 | |
2687 if (type & PURPLE_MEDIA_AUDIO && | |
2688 !jabber_resource_has_capability(jbr, | |
2689 JINGLE_APP_RTP_SUPPORT_AUDIO) && | |
2690 jabber_resource_has_capability(jbr, | |
2691 GOOGLE_VOICE_CAP)) | |
2692 return jabber_google_session_initiate( | |
2693 gc->proto_data, who, type); | |
2694 else | |
2695 return jingle_rtp_initiate_media( | |
2696 gc->proto_data, who, type); | |
2697 } | |
2698 | |
2699 jb = jabber_buddy_find(js, who, FALSE); | |
2700 | |
2701 if(!jb || !jb->resources) { | |
2702 /* no resources online, we're trying to initiate with someone | |
2703 * whose presence we're not subscribed to, or | |
2704 * someone who is offline. Let's inform the user */ | |
2705 char *msg; | |
2706 | |
2707 if(!jb) { | |
2708 msg = g_strdup_printf(_("Unable to initiate media with %s: invalid JID"), who); | |
2709 } else if(jb->subscription & JABBER_SUB_TO) { | |
2710 msg = g_strdup_printf(_("Unable to initiate media with %s: user is not online"), who); | |
2711 } else { | |
2712 msg = g_strdup_printf(_("Unable to initiate media with %s: not subscribed to user presence"), who); | |
2713 } | |
2714 | |
2715 purple_notify_error(js->gc, _("Media Initiation Failed"), | |
2716 _("Media Initiation Failed"), msg); | |
2717 g_free(msg); | |
2718 return FALSE; | |
2719 } else if(!jb->resources->next) { | |
2720 /* only 1 resource online (probably our most common case) | |
2721 * so no need to ask who to initiate with */ | |
2722 gchar *name; | |
2723 gboolean result; | |
2724 jbr = jb->resources->data; | |
2725 name = g_strdup_printf("%s/%s", who, jbr->name); | |
2726 result = jabber_initiate_media(gc, name, type); | |
2727 g_free(name); | |
2728 return result; | |
2729 } else { | |
2730 /* we've got multiple resources, | |
2731 * we need to pick one to initiate with */ | |
2732 GList *l; | |
2733 char *msg; | |
2734 PurpleRequestFields *fields; | |
2735 PurpleRequestField *field = purple_request_field_choice_new( | |
2736 "resource", _("Resource"), 0); | |
2737 PurpleRequestFieldGroup *group; | |
2738 JabberMediaRequest *request; | |
2739 | |
2740 for(l = jb->resources; l; l = l->next) | |
2741 { | |
2742 JabberBuddyResource *ljbr = l->data; | |
2743 PurpleMediaCaps caps; | |
2744 gchar *name; | |
2745 name = g_strdup_printf("%s/%s", who, ljbr->name); | |
2746 caps = jabber_get_media_caps(gc, name); | |
2747 g_free(name); | |
2748 | |
2749 if ((type & PURPLE_MEDIA_AUDIO) && | |
2750 (type & PURPLE_MEDIA_VIDEO)) { | |
2751 if (caps & PURPLE_MEDIA_CAPS_AUDIO_VIDEO) { | |
2752 jbr = ljbr; | |
2753 purple_request_field_choice_add( | |
2754 field, jbr->name); | |
2755 } | |
2756 } else if (type & (PURPLE_MEDIA_AUDIO) && | |
2757 (caps & PURPLE_MEDIA_CAPS_AUDIO)) { | |
2758 jbr = ljbr; | |
2759 purple_request_field_choice_add( | |
2760 field, jbr->name); | |
2761 }else if (type & (PURPLE_MEDIA_VIDEO) && | |
2762 (caps & PURPLE_MEDIA_CAPS_VIDEO)) { | |
2763 jbr = ljbr; | |
2764 purple_request_field_choice_add( | |
2765 field, jbr->name); | |
2766 } | |
2767 } | |
2768 | |
2769 if (jbr == NULL) { | |
2770 purple_debug_error("jabber", | |
2771 "No resources available\n"); | |
2772 return FALSE; | |
2773 } | |
2774 | |
2775 if (g_list_length(purple_request_field_choice_get_labels( | |
2776 field)) <= 1) { | |
2777 gchar *name; | |
2778 gboolean result; | |
2779 purple_request_field_destroy(field); | |
2780 name = g_strdup_printf("%s/%s", who, jbr->name); | |
2781 result = jabber_initiate_media(gc, name, type); | |
2782 g_free(name); | |
2783 return result; | |
2784 } | |
2785 | |
2786 msg = g_strdup_printf(_("Please select the resource of %s with which you would like to start a media session."), who); | |
2787 fields = purple_request_fields_new(); | |
2788 group = purple_request_field_group_new(NULL); | |
2789 request = g_new0(JabberMediaRequest, 1); | |
2790 request->pc = gc; | |
2791 request->who = g_strdup(who); | |
2792 request->type = type; | |
2793 | |
2794 purple_request_field_group_add_field(group, field); | |
2795 purple_request_fields_add_group(fields, group); | |
2796 purple_request_fields(gc, _("Select a Resource"), msg, NULL, | |
2797 fields, _("Initiate Media"), | |
2798 G_CALLBACK(jabber_media_ok_cb), _("Cancel"), | |
2799 G_CALLBACK(jabber_media_cancel_cb), | |
2800 gc->account, who, NULL, request); | |
2801 | |
2802 g_free(msg); | |
2803 return TRUE; | |
2804 } | |
2805 #endif | |
2806 return FALSE; | |
2807 } | |
2808 | |
2809 PurpleMediaCaps jabber_get_media_caps(PurpleConnection *gc, const char *who) | |
2810 { | |
2811 #ifdef USE_VV | |
2812 JabberStream *js = (JabberStream *) gc->proto_data; | |
2813 JabberBuddy *jb; | |
2814 JabberBuddyResource *jbr; | |
2815 PurpleMediaCaps caps = PURPLE_MEDIA_CAPS_NONE; | |
2816 gchar *resource; | |
2817 | |
2818 if (!js) { | |
2819 purple_debug_info("jabber", | |
2820 "jabber_can_do_media: NULL stream\n"); | |
2821 return FALSE; | |
2822 } | |
2823 | |
2824 if ((resource = jabber_get_resource(who)) != NULL) { | |
2825 /* they've specified a resource, no need to ask or | |
2826 * default or anything, just do it */ | |
2827 | |
2828 jb = jabber_buddy_find(js, who, FALSE); | |
2829 jbr = jabber_buddy_find_resource(jb, resource); | |
2830 g_free(resource); | |
2831 | |
2832 if (!jbr) { | |
2833 purple_debug_error("jabber", "jabber_get_media_caps:" | |
2834 " Can't find resource %s\n", who); | |
2835 return caps; | |
2836 } | |
2837 | |
2838 if (jabber_resource_has_capability(jbr, | |
2839 JINGLE_APP_RTP_SUPPORT_AUDIO)) | |
2840 caps |= PURPLE_MEDIA_CAPS_AUDIO_SINGLE_DIRECTION | | |
2841 PURPLE_MEDIA_CAPS_AUDIO; | |
2842 if (jabber_resource_has_capability(jbr, | |
2843 JINGLE_APP_RTP_SUPPORT_VIDEO)) | |
2844 caps |= PURPLE_MEDIA_CAPS_VIDEO_SINGLE_DIRECTION | | |
2845 PURPLE_MEDIA_CAPS_VIDEO; | |
2846 if (caps & PURPLE_MEDIA_CAPS_AUDIO && caps & | |
2847 PURPLE_MEDIA_CAPS_VIDEO) | |
2848 caps |= PURPLE_MEDIA_CAPS_AUDIO_VIDEO; | |
2849 if (caps != PURPLE_MEDIA_CAPS_NONE) { | |
2850 if (!jabber_resource_has_capability(jbr, | |
2851 JINGLE_TRANSPORT_ICEUDP) && | |
2852 !jabber_resource_has_capability(jbr, | |
2853 JINGLE_TRANSPORT_RAWUDP)) { | |
2854 purple_debug_info("jingle-rtp", "Buddy doesn't " | |
2855 "support the same transport types\n"); | |
2856 caps = PURPLE_MEDIA_CAPS_NONE; | |
2857 } else | |
2858 caps |= PURPLE_MEDIA_CAPS_MODIFY_SESSION | | |
2859 PURPLE_MEDIA_CAPS_CHANGE_DIRECTION; | |
2860 } | |
2861 if (jabber_resource_has_capability(jbr, GOOGLE_VOICE_CAP)) | |
2862 caps |= PURPLE_MEDIA_CAPS_AUDIO; | |
2863 return caps; | |
2864 } | |
2865 | |
2866 jb = jabber_buddy_find(js, who, FALSE); | |
2867 | |
2868 if(!jb || !jb->resources) { | |
2869 /* no resources online, we're trying to get caps for someone | |
2870 * whose presence we're not subscribed to, or | |
2871 * someone who is offline. */ | |
2872 return caps; | |
2873 } else if(!jb->resources->next) { | |
2874 /* only 1 resource online (probably our most common case) */ | |
2875 gchar *name; | |
2876 jbr = jb->resources->data; | |
2877 name = g_strdup_printf("%s/%s", who, jbr->name); | |
2878 caps = jabber_get_media_caps(gc, name); | |
2879 g_free(name); | |
2880 } else { | |
2881 /* we've got multiple resources, combine their caps */ | |
2882 GList *l; | |
2883 | |
2884 for(l = jb->resources; l; l = l->next) | |
2885 { | |
2886 gchar *name; | |
2887 jbr = l->data; | |
2888 name = g_strdup_printf("%s/%s", who, jbr->name); | |
2889 caps |= jabber_get_media_caps(gc, name); | |
2890 g_free(name); | |
2891 } | |
2892 } | |
2893 | |
2894 return caps; | |
2895 #else | |
2896 return PURPLE_MEDIA_CAPS_NONE; | |
2897 #endif | |
2605 } | 2898 } |
2606 | 2899 |
2607 void jabber_register_commands(void) | 2900 void jabber_register_commands(void) |
2608 { | 2901 { |
2609 purple_cmd_register("config", "", PURPLE_CMD_P_PRPL, | 2902 purple_cmd_register("config", "", PURPLE_CMD_P_PRPL, |