libpurple/protocols/jabber/jabber.c

branch
cpw.malu.xmpp.idle
changeset 26725
fbfc67bd9fd6
parent 26677
04c4a7a7865f
parent 26699
1255f40458d7
child 26796
c2f378bc4183
equal deleted inserted replaced
26677:04c4a7a7865f 26725:fbfc67bd9fd6
86 js->reinit = FALSE; 86 js->reinit = FALSE;
87 g_free(open_stream); 87 g_free(open_stream);
88 } 88 }
89 89
90 static void 90 static void
91 jabber_session_initialized_cb(JabberStream *js, xmlnode *packet, gpointer data) 91 jabber_session_initialized_cb(JabberStream *js, const char *from,
92 { 92 JabberIqType type, const char *id,
93 const char *type = xmlnode_get_attrib(packet, "type"); 93 xmlnode *packet, gpointer data)
94 if(type && !strcmp(type, "result")) { 94 {
95 if (type == JABBER_IQ_RESULT) {
95 jabber_stream_set_state(js, JABBER_STREAM_CONNECTED); 96 jabber_stream_set_state(js, JABBER_STREAM_CONNECTED);
96 if(js->unregistration) 97 if(js->unregistration)
97 jabber_unregister_account_cb(js); 98 jabber_unregister_account_cb(js);
98 } else { 99 } else {
99 purple_connection_error_reason (js->gc, 100 purple_connection_error_reason (js->gc,
113 xmlnode_set_namespace(session, "urn:ietf:params:xml:ns:xmpp-session"); 114 xmlnode_set_namespace(session, "urn:ietf:params:xml:ns:xmpp-session");
114 115
115 jabber_iq_send(iq); 116 jabber_iq_send(iq);
116 } 117 }
117 118
118 static void jabber_bind_result_cb(JabberStream *js, xmlnode *packet, 119 static void jabber_bind_result_cb(JabberStream *js, const char *from,
119 gpointer data) 120 JabberIqType type, const char *id,
120 { 121 xmlnode *packet, gpointer data)
121 const char *type = xmlnode_get_attrib(packet, "type"); 122 {
122 xmlnode *bind; 123 xmlnode *bind;
123 124
124 if(type && !strcmp(type, "result") && 125 if (type == JABBER_IQ_RESULT &&
125 (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"))) {
126 xmlnode *jid; 127 xmlnode *jid;
127 char *full_jid; 128 char *full_jid;
128 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))) {
129 JabberBuddy *my_jb = NULL; 130 JabberBuddy *my_jb = NULL;
447 txt = xmlnode_to_str(packet, &len); 448 txt = xmlnode_to_str(packet, &len);
448 jabber_send_raw(js, txt, len); 449 jabber_send_raw(js, txt, len);
449 g_free(txt); 450 g_free(txt);
450 } 451 }
451 452
452 static void jabber_pong_cb(JabberStream *js, xmlnode *packet, gpointer unused) 453 static gboolean jabber_keepalive_timeout(PurpleConnection *gc)
453 {
454 purple_timeout_remove(js->keepalive_timeout);
455 js->keepalive_timeout = -1;
456 }
457
458 static gboolean jabber_pong_timeout(PurpleConnection *gc)
459 { 454 {
460 JabberStream *js = gc->proto_data; 455 JabberStream *js = gc->proto_data;
461 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, 456 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
462 _("Ping timeout")); 457 _("Ping timeout"));
463 js->keepalive_timeout = -1; 458 js->keepalive_timeout = -1;
467 void jabber_keepalive(PurpleConnection *gc) 462 void jabber_keepalive(PurpleConnection *gc)
468 { 463 {
469 JabberStream *js = gc->proto_data; 464 JabberStream *js = gc->proto_data;
470 465
471 if (js->keepalive_timeout == -1) { 466 if (js->keepalive_timeout == -1) {
472 JabberIq *iq = jabber_iq_new(js, JABBER_IQ_GET); 467 jabber_ping_jid(js, NULL);
473 468 js->keepalive_timeout = purple_timeout_add_seconds(120,
474 xmlnode *ping = xmlnode_new_child(iq->node, "ping"); 469 (GSourceFunc)(jabber_keepalive_timeout), gc);
475 xmlnode_set_namespace(ping, "urn:xmpp:ping");
476
477 js->keepalive_timeout = purple_timeout_add_seconds(120, (GSourceFunc)(jabber_pong_timeout), gc);
478 jabber_iq_set_callback(iq, jabber_pong_cb, NULL);
479 jabber_iq_send(iq);
480 } 470 }
481 } 471 }
482 472
483 static void 473 static void
484 jabber_recv_cb_ssl(gpointer data, PurpleSslConnection *gsc, 474 jabber_recv_cb_ssl(gpointer data, PurpleSslConnection *gsc,
810 { 800 {
811 purple_timeout_add(0, conn_close_cb, js); 801 purple_timeout_add(0, conn_close_cb, js);
812 } 802 }
813 803
814 static void 804 static void
815 jabber_registration_result_cb(JabberStream *js, xmlnode *packet, gpointer data) 805 jabber_registration_result_cb(JabberStream *js, const char *from,
806 JabberIqType type, const char *id,
807 xmlnode *packet, gpointer data)
816 { 808 {
817 PurpleAccount *account = purple_connection_get_account(js->gc); 809 PurpleAccount *account = purple_connection_get_account(js->gc);
818 const char *type = xmlnode_get_attrib(packet, "type");
819 char *buf; 810 char *buf;
820 char *to = data; 811 char *to = data;
821 812
822 if(!strcmp(type, "result")) { 813 if (type == JABBER_IQ_RESULT) {
823 if(js->registration) { 814 if(js->registration) {
824 buf = g_strdup_printf(_("Registration of %s@%s successful"), 815 buf = g_strdup_printf(_("Registration of %s@%s successful"),
825 js->user->node, js->user->domain); 816 js->user->node, js->user->domain);
826 if(account->registration_cb) 817 if(account->registration_cb)
827 (account->registration_cb)(account, TRUE, account->registration_cb_user_data); 818 (account->registration_cb)(account, TRUE, account->registration_cb_user_data);
845 if(account->registration_cb) 836 if(account->registration_cb)
846 (account->registration_cb)(account, FALSE, account->registration_cb_user_data); 837 (account->registration_cb)(account, FALSE, account->registration_cb_user_data);
847 } 838 }
848 g_free(to); 839 g_free(to);
849 if(js->registration) 840 if(js->registration)
850 jabber_connection_schedule_close(js); 841 jabber_connection_schedule_close(js);
851 } 842 }
852 843
853 static void 844 static void
854 jabber_unregistration_result_cb(JabberStream *js, xmlnode *packet, gpointer data) 845 jabber_unregistration_result_cb(JabberStream *js, const char *from,
855 { 846 JabberIqType type, const char *id,
856 const char *type = xmlnode_get_attrib(packet, "type"); 847 xmlnode *packet, gpointer data)
848 {
857 char *buf; 849 char *buf;
858 char *to = data; 850 char *to = data;
859 851
860 /* This function is never called for unregistering our XMPP account from 852 /* This function is never called for unregistering our XMPP account from
861 * the server, so there should always be a 'to' address. */ 853 * the server, so there should always be a 'to' address. */
862 g_return_if_fail(to != NULL); 854 g_return_if_fail(to != NULL);
863 855
864 if(!strcmp(type, "result")) { 856 if (type == JABBER_IQ_RESULT) {
865 buf = g_strdup_printf(_("Registration from %s successfully removed"), 857 buf = g_strdup_printf(_("Registration from %s successfully removed"),
866 to); 858 to);
867 purple_notify_info(NULL, _("Unregistration Successful"), 859 purple_notify_info(NULL, _("Unregistration Successful"),
868 _("Unregistration Successful"), buf); 860 _("Unregistration Successful"), buf);
869 g_free(buf); 861 g_free(buf);
1008 1000
1009 jabber_iq_set_callback(iq, jabber_registration_result_cb, to); 1001 jabber_iq_set_callback(iq, jabber_registration_result_cb, to);
1010 jabber_iq_send(iq); 1002 jabber_iq_send(iq);
1011 } 1003 }
1012 1004
1013 void jabber_register_parse(JabberStream *js, xmlnode *packet) 1005 void jabber_register_parse(JabberStream *js, const char *from, JabberIqType type,
1006 const char *id, xmlnode *query)
1014 { 1007 {
1015 PurpleAccount *account = purple_connection_get_account(js->gc); 1008 PurpleAccount *account = purple_connection_get_account(js->gc);
1016 const char *type;
1017 const char *from;
1018 PurpleRequestFields *fields; 1009 PurpleRequestFields *fields;
1019 PurpleRequestFieldGroup *group; 1010 PurpleRequestFieldGroup *group;
1020 PurpleRequestField *field; 1011 PurpleRequestField *field;
1021 xmlnode *query, *x, *y; 1012 xmlnode *x, *y;
1022 char *instructions; 1013 char *instructions;
1023 JabberRegisterCBData *cbdata; 1014 JabberRegisterCBData *cbdata;
1024 gboolean registered = FALSE; 1015 gboolean registered = FALSE;
1025 1016
1026 if(!(type = xmlnode_get_attrib(packet, "type")) || strcmp(type, "result")) 1017 if (type != JABBER_IQ_RESULT)
1027 return; 1018 return;
1028 1019
1029 from = xmlnode_get_attrib(packet, "from"); 1020 if (!from)
1021 from = js->serverFQDN;
1022 g_return_if_fail(from != NULL);
1030 1023
1031 if(js->registration) { 1024 if(js->registration) {
1032 /* get rid of the login thingy */ 1025 /* get rid of the login thingy */
1033 purple_connection_set_state(js->gc, PURPLE_CONNECTED); 1026 purple_connection_set_state(js->gc, PURPLE_CONNECTED);
1034 } 1027 }
1035
1036 query = xmlnode_get_child(packet, "query");
1037 1028
1038 if(xmlnode_get_child(query, "registered")) { 1029 if(xmlnode_get_child(query, "registered")) {
1039 registered = TRUE; 1030 registered = TRUE;
1040 1031
1041 if(js->registration) { 1032 if(js->registration) {
1270 js); 1261 js);
1271 } 1262 }
1272 } 1263 }
1273 } 1264 }
1274 1265
1275 static void jabber_unregister_account_iq_cb(JabberStream *js, xmlnode *packet, gpointer data) { 1266 static void
1267 jabber_unregister_account_iq_cb(JabberStream *js, const char *from,
1268 JabberIqType type, const char *id,
1269 xmlnode *packet, gpointer data)
1270 {
1276 PurpleAccount *account = purple_connection_get_account(js->gc); 1271 PurpleAccount *account = purple_connection_get_account(js->gc);
1277 const char *type = xmlnode_get_attrib(packet,"type"); 1272
1278 if(!strcmp(type,"error")) { 1273 if (type == JABBER_IQ_ERROR) {
1279 char *msg = jabber_parse_error(js, packet, NULL); 1274 char *msg = jabber_parse_error(js, packet, NULL);
1280 1275
1281 purple_notify_error(js->gc, _("Error unregistering account"), 1276 purple_notify_error(js->gc, _("Error unregistering account"),
1282 _("Error unregistering account"), msg); 1277 _("Error unregistering account"), msg);
1283 g_free(msg); 1278 g_free(msg);
1284 if(js->unregistration_cb) 1279 if(js->unregistration_cb)
1285 js->unregistration_cb(account, FALSE, js->unregistration_user_data); 1280 js->unregistration_cb(account, FALSE, js->unregistration_user_data);
1286 } else if(!strcmp(type,"result")) { 1281 } else {
1287 purple_notify_info(js->gc, _("Account successfully unregistered"), 1282 purple_notify_info(js->gc, _("Account successfully unregistered"),
1288 _("Account successfully unregistered"), NULL); 1283 _("Account successfully unregistered"), NULL);
1289 if(js->unregistration_cb) 1284 if(js->unregistration_cb)
1290 js->unregistration_cb(account, TRUE, js->unregistration_user_data); 1285 js->unregistration_cb(account, TRUE, js->unregistration_user_data);
1291 } 1286 }
1528 /* send out an updated prescence */ 1523 /* send out an updated prescence */
1529 purple_debug_info("jabber", "sending updated presence for idle\n"); 1524 purple_debug_info("jabber", "sending updated presence for idle\n");
1530 jabber_presence_send(account, status); 1525 jabber_presence_send(account, status);
1531 } 1526 }
1532 1527
1533 static void jabber_blocklist_parse(JabberStream *js, xmlnode *packet, gpointer data) 1528 static void jabber_blocklist_parse(JabberStream *js, const char *from,
1529 JabberIqType type, const char *id,
1530 xmlnode *packet, gpointer data)
1534 { 1531 {
1535 xmlnode *blocklist, *item; 1532 xmlnode *blocklist, *item;
1536 PurpleAccount *account; 1533 PurpleAccount *account;
1537 1534
1538 blocklist = xmlnode_get_child_with_namespace(packet, 1535 blocklist = xmlnode_get_child_with_namespace(packet,
1980 1977
1981 return types; 1978 return types;
1982 } 1979 }
1983 1980
1984 static void 1981 static void
1985 jabber_password_change_result_cb(JabberStream *js, xmlnode *packet, 1982 jabber_password_change_result_cb(JabberStream *js, const char *from,
1986 gpointer data) 1983 JabberIqType type, const char *id,
1987 { 1984 xmlnode *packet, gpointer data)
1988 const char *type; 1985 {
1989 1986 if (type == JABBER_IQ_RESULT) {
1990 type = xmlnode_get_attrib(packet, "type");
1991
1992 if(type && !strcmp(type, "result")) {
1993 purple_notify_info(js->gc, _("Password Changed"), _("Password Changed"), 1987 purple_notify_info(js->gc, _("Password Changed"), _("Password Changed"),
1994 _("Your password has been changed.")); 1988 _("Your password has been changed."));
1995 1989
1996 purple_account_set_password(js->gc->account, (char *)data); 1990 purple_account_set_password(js->gc->account, (char *)data);
1997 } else { 1991 } else {
2519 } 2513 }
2520 2514
2521 static PurpleCmdRet jabber_cmd_ping(PurpleConversation *conv, 2515 static PurpleCmdRet jabber_cmd_ping(PurpleConversation *conv,
2522 const char *cmd, char **args, char **error, void *data) 2516 const char *cmd, char **args, char **error, void *data)
2523 { 2517 {
2518 PurpleAccount *account;
2519 PurpleConnection *pc;
2520
2524 if(!args || !args[0]) 2521 if(!args || !args[0])
2525 return PURPLE_CMD_RET_FAILED; 2522 return PURPLE_CMD_RET_FAILED;
2526 2523
2527 if(!jabber_ping_jid(conv, args[0])) { 2524 account = purple_conversation_get_account(conv);
2525 pc = purple_account_get_connection(account);
2526
2527 if(!jabber_ping_jid(purple_connection_get_protocol_data(pc), args[0])) {
2528 *error = g_strdup_printf(_("Unable to ping user %s"), args[0]); 2528 *error = g_strdup_printf(_("Unable to ping user %s"), args[0]);
2529 return PURPLE_CMD_RET_FAILED; 2529 return PURPLE_CMD_RET_FAILED;
2530 } 2530 }
2531 2531
2532 return PURPLE_CMD_RET_OK; 2532 return PURPLE_CMD_RET_OK;
2654 gboolean jabber_offline_message(const PurpleBuddy *buddy) 2654 gboolean jabber_offline_message(const PurpleBuddy *buddy)
2655 { 2655 {
2656 return TRUE; 2656 return TRUE;
2657 } 2657 }
2658 2658
2659 #ifdef USE_VV
2660 typedef struct {
2661 PurpleConnection *pc;
2662 gchar *who;
2663 PurpleMediaSessionType type;
2664
2665 } JabberMediaRequest;
2666
2667 static void
2668 jabber_media_cancel_cb(JabberMediaRequest *request,
2669 PurpleRequestFields *fields)
2670 {
2671 g_free(request->who);
2672 g_free(request);
2673 }
2674
2675 static void
2676 jabber_media_ok_cb(JabberMediaRequest *request, PurpleRequestFields *fields)
2677 {
2678 PurpleRequestField *field =
2679 purple_request_fields_get_field(fields, "resource");
2680 int selected_id = purple_request_field_choice_get_value(field);
2681 GList *labels = purple_request_field_choice_get_labels(field);
2682 gchar *who = g_strdup_printf("%s/%s", request->who,
2683 (gchar*)g_list_nth_data(labels, selected_id));
2684 jabber_initiate_media(request->pc, who, request->type);
2685
2686 g_free(who);
2687 g_free(request->who);
2688 g_free(request);
2689 }
2690 #endif
2691
2659 gboolean 2692 gboolean
2660 jabber_initiate_media(PurpleConnection *gc, const char *who, 2693 jabber_initiate_media(PurpleConnection *gc, const char *who,
2661 PurpleMediaSessionType type) 2694 PurpleMediaSessionType type)
2662 { 2695 {
2663 #ifdef USE_VV 2696 #ifdef USE_VV
2664 JabberStream *js = (JabberStream *) gc->proto_data; 2697 JabberStream *js = (JabberStream *) gc->proto_data;
2665 JabberBuddy *jb; 2698 JabberBuddy *jb;
2699 JabberBuddyResource *jbr = NULL;
2700 char *resource;
2666 2701
2667 if (!js) { 2702 if (!js) {
2668 purple_debug_error("jabber", 2703 purple_debug_error("jabber",
2669 "jabber_initiate_media: NULL stream\n"); 2704 "jabber_initiate_media: NULL stream\n");
2670 return FALSE; 2705 return FALSE;
2671 } 2706 }
2672 2707
2708
2709 if((resource = jabber_get_resource(who)) != NULL) {
2710 /* they've specified a resource, no need to ask or
2711 * default or anything, just do it */
2712
2713 jb = jabber_buddy_find(js, who, FALSE);
2714 jbr = jabber_buddy_find_resource(jb, resource);
2715 g_free(resource);
2716
2717 if (type & PURPLE_MEDIA_AUDIO &&
2718 !jabber_resource_has_capability(jbr,
2719 JINGLE_APP_RTP_SUPPORT_AUDIO) &&
2720 jabber_resource_has_capability(jbr,
2721 GOOGLE_VOICE_CAP))
2722 return jabber_google_session_initiate(
2723 gc->proto_data, who, type);
2724 else
2725 return jingle_rtp_initiate_media(
2726 gc->proto_data, who, type);
2727 }
2728
2673 jb = jabber_buddy_find(js, who, FALSE); 2729 jb = jabber_buddy_find(js, who, FALSE);
2674 2730
2675 if (!jb) { 2731 if(!jb || !jb->resources) {
2676 purple_debug_error("jabber", "Could not find buddy\n"); 2732 /* no resources online, we're trying to initiate with someone
2733 * whose presence we're not subscribed to, or
2734 * someone who is offline. Let's inform the user */
2735 char *msg;
2736
2737 if(!jb) {
2738 msg = g_strdup_printf(_("Unable to initiate media with %s: invalid JID"), who);
2739 } else if(jb->subscription & JABBER_SUB_TO) {
2740 msg = g_strdup_printf(_("Unable to initiate media with %s: user is not online"), who);
2741 } else {
2742 msg = g_strdup_printf(_("Unable to initiate media with %s: not subscribed to user presence"), who);
2743 }
2744
2745 purple_notify_error(js->gc, _("Media Initiation Failed"),
2746 _("Media Initiation Failed"), msg);
2747 g_free(msg);
2677 return FALSE; 2748 return FALSE;
2678 } 2749 } else if(!jb->resources->next) {
2679 2750 /* only 1 resource online (probably our most common case)
2680 if (type & PURPLE_MEDIA_AUDIO && 2751 * so no need to ask who to initiate with */
2681 !jabber_buddy_has_capability(jb, 2752 gchar *name;
2682 JINGLE_APP_RTP_SUPPORT_AUDIO) && 2753 gboolean result;
2683 jabber_buddy_has_capability(jb, GOOGLE_VOICE_CAP)) 2754 jbr = jb->resources->data;
2684 return jabber_google_session_initiate(gc->proto_data, who, type); 2755 name = g_strdup_printf("%s/%s", who, jbr->name);
2685 else 2756 result = jabber_initiate_media(gc, name, type);
2686 return jingle_rtp_initiate_media(gc->proto_data, who, type); 2757 g_free(name);
2687 #else 2758 return result;
2759 } else {
2760 /* we've got multiple resources,
2761 * we need to pick one to initiate with */
2762 GList *l;
2763 char *msg;
2764 PurpleRequestFields *fields;
2765 PurpleRequestField *field = purple_request_field_choice_new(
2766 "resource", _("Resource"), 0);
2767 PurpleRequestFieldGroup *group;
2768 JabberMediaRequest *request;
2769
2770 for(l = jb->resources; l; l = l->next)
2771 {
2772 JabberBuddyResource *ljbr = l->data;
2773 PurpleMediaCaps caps;
2774 gchar *name;
2775 name = g_strdup_printf("%s/%s", who, ljbr->name);
2776 caps = jabber_get_media_caps(gc, name);
2777 g_free(name);
2778
2779 if ((type & PURPLE_MEDIA_AUDIO) &&
2780 (type & PURPLE_MEDIA_VIDEO)) {
2781 if (caps & PURPLE_MEDIA_CAPS_AUDIO_VIDEO) {
2782 jbr = ljbr;
2783 purple_request_field_choice_add(
2784 field, jbr->name);
2785 }
2786 } else if (type & (PURPLE_MEDIA_AUDIO) &&
2787 (caps & PURPLE_MEDIA_CAPS_AUDIO)) {
2788 jbr = ljbr;
2789 purple_request_field_choice_add(
2790 field, jbr->name);
2791 }else if (type & (PURPLE_MEDIA_VIDEO) &&
2792 (caps & PURPLE_MEDIA_CAPS_VIDEO)) {
2793 jbr = ljbr;
2794 purple_request_field_choice_add(
2795 field, jbr->name);
2796 }
2797 }
2798
2799 if (jbr == NULL) {
2800 purple_debug_error("jabber",
2801 "No resources available\n");
2802 return FALSE;
2803 }
2804
2805 if (g_list_length(purple_request_field_choice_get_labels(
2806 field)) <= 1) {
2807 gchar *name;
2808 gboolean result;
2809 purple_request_field_destroy(field);
2810 name = g_strdup_printf("%s/%s", who, jbr->name);
2811 result = jabber_initiate_media(gc, name, type);
2812 g_free(name);
2813 return result;
2814 }
2815
2816 msg = g_strdup_printf(_("Please select the resource of %s with which you would like to start a media session."), who);
2817 fields = purple_request_fields_new();
2818 group = purple_request_field_group_new(NULL);
2819 request = g_new0(JabberMediaRequest, 1);
2820 request->pc = gc;
2821 request->who = g_strdup(who);
2822 request->type = type;
2823
2824 purple_request_field_group_add_field(group, field);
2825 purple_request_fields_add_group(fields, group);
2826 purple_request_fields(gc, _("Select a Resource"), msg, NULL,
2827 fields, _("Initiate Media"),
2828 G_CALLBACK(jabber_media_ok_cb), _("Cancel"),
2829 G_CALLBACK(jabber_media_cancel_cb),
2830 gc->account, who, NULL, request);
2831
2832 g_free(msg);
2833 return TRUE;
2834 }
2835 #endif
2688 return FALSE; 2836 return FALSE;
2689 #endif
2690 } 2837 }
2691 2838
2692 PurpleMediaCaps jabber_get_media_caps(PurpleConnection *gc, const char *who) 2839 PurpleMediaCaps jabber_get_media_caps(PurpleConnection *gc, const char *who)
2693 { 2840 {
2694 #ifdef USE_VV 2841 #ifdef USE_VV
2695 JabberStream *js = (JabberStream *) gc->proto_data; 2842 JabberStream *js = (JabberStream *) gc->proto_data;
2696 JabberBuddy *jb; 2843 JabberBuddy *jb;
2844 JabberBuddyResource *jbr;
2697 PurpleMediaCaps caps = PURPLE_MEDIA_CAPS_NONE; 2845 PurpleMediaCaps caps = PURPLE_MEDIA_CAPS_NONE;
2846 gchar *resource;
2698 2847
2699 if (!js) { 2848 if (!js) {
2700 purple_debug_info("jabber", 2849 purple_debug_info("jabber",
2701 "jabber_can_do_media: NULL stream\n"); 2850 "jabber_can_do_media: NULL stream\n");
2702 return FALSE; 2851 return FALSE;
2703 } 2852 }
2704 2853
2854 if ((resource = jabber_get_resource(who)) != NULL) {
2855 /* they've specified a resource, no need to ask or
2856 * default or anything, just do it */
2857
2858 jb = jabber_buddy_find(js, who, FALSE);
2859 jbr = jabber_buddy_find_resource(jb, resource);
2860 g_free(resource);
2861
2862 if (!jbr) {
2863 purple_debug_error("jabber", "jabber_get_media_caps:"
2864 " Can't find resource %s\n", who);
2865 return caps;
2866 }
2867
2868 if (jabber_resource_has_capability(jbr,
2869 JINGLE_APP_RTP_SUPPORT_AUDIO))
2870 caps |= PURPLE_MEDIA_CAPS_AUDIO_SINGLE_DIRECTION |
2871 PURPLE_MEDIA_CAPS_AUDIO;
2872 if (jabber_resource_has_capability(jbr,
2873 JINGLE_APP_RTP_SUPPORT_VIDEO))
2874 caps |= PURPLE_MEDIA_CAPS_VIDEO_SINGLE_DIRECTION |
2875 PURPLE_MEDIA_CAPS_VIDEO;
2876 if (caps & PURPLE_MEDIA_CAPS_AUDIO && caps &
2877 PURPLE_MEDIA_CAPS_VIDEO)
2878 caps |= PURPLE_MEDIA_CAPS_AUDIO_VIDEO;
2879 if (caps != PURPLE_MEDIA_CAPS_NONE) {
2880 if (!jabber_resource_has_capability(jbr,
2881 JINGLE_TRANSPORT_ICEUDP) &&
2882 !jabber_resource_has_capability(jbr,
2883 JINGLE_TRANSPORT_RAWUDP)) {
2884 purple_debug_info("jingle-rtp", "Buddy doesn't "
2885 "support the same transport types\n");
2886 caps = PURPLE_MEDIA_CAPS_NONE;
2887 } else
2888 caps |= PURPLE_MEDIA_CAPS_MODIFY_SESSION |
2889 PURPLE_MEDIA_CAPS_CHANGE_DIRECTION;
2890 }
2891 if (jabber_resource_has_capability(jbr, GOOGLE_VOICE_CAP))
2892 caps |= PURPLE_MEDIA_CAPS_AUDIO;
2893 return caps;
2894 }
2895
2705 jb = jabber_buddy_find(js, who, FALSE); 2896 jb = jabber_buddy_find(js, who, FALSE);
2706 2897
2707 if (!jb) { 2898 if(!jb || !jb->resources) {
2708 purple_debug_error("jabber", "Could not find buddy\n"); 2899 /* no resources online, we're trying to get caps for someone
2709 return FALSE; 2900 * whose presence we're not subscribed to, or
2710 } 2901 * someone who is offline. */
2711 2902 return caps;
2712 if (jabber_buddy_has_capability(jb, JINGLE_APP_RTP_SUPPORT_AUDIO)) 2903 } else if(!jb->resources->next) {
2713 caps |= PURPLE_MEDIA_CAPS_AUDIO | 2904 /* only 1 resource online (probably our most common case) */
2714 PURPLE_MEDIA_CAPS_AUDIO_SINGLE_DIRECTION; 2905 gchar *name;
2715 if (jabber_buddy_has_capability(jb, JINGLE_APP_RTP_SUPPORT_VIDEO)) 2906 jbr = jb->resources->data;
2716 caps |= PURPLE_MEDIA_CAPS_VIDEO | 2907 name = g_strdup_printf("%s/%s", who, jbr->name);
2717 PURPLE_MEDIA_CAPS_VIDEO_SINGLE_DIRECTION; 2908 caps = jabber_get_media_caps(gc, name);
2718 if (caps & PURPLE_MEDIA_CAPS_AUDIO && caps & PURPLE_MEDIA_CAPS_VIDEO) 2909 g_free(name);
2719 caps |= PURPLE_MEDIA_CAPS_AUDIO_VIDEO; 2910 } else {
2720 if (caps != PURPLE_MEDIA_CAPS_NONE) { 2911 /* we've got multiple resources, combine their caps */
2721 if (!jabber_buddy_has_capability(jb, 2912 GList *l;
2722 JINGLE_TRANSPORT_ICEUDP) && 2913
2723 !jabber_buddy_has_capability(jb, 2914 for(l = jb->resources; l; l = l->next)
2724 JINGLE_TRANSPORT_RAWUDP)) { 2915 {
2725 purple_debug_info("jingle-rtp", "Buddy doesn't " 2916 gchar *name;
2726 "support the same transport types\n"); 2917 jbr = l->data;
2727 caps = PURPLE_MEDIA_CAPS_NONE; 2918 name = g_strdup_printf("%s/%s", who, jbr->name);
2728 } else 2919 caps |= jabber_get_media_caps(gc, name);
2729 caps |= PURPLE_MEDIA_CAPS_MODIFY_SESSION | 2920 g_free(name);
2730 PURPLE_MEDIA_CAPS_CHANGE_DIRECTION; 2921 }
2731 } 2922 }
2732 if (jabber_buddy_has_capability(jb, GOOGLE_VOICE_CAP))
2733 caps |= PURPLE_MEDIA_CAPS_AUDIO;
2734 2923
2735 return caps; 2924 return caps;
2736 #else 2925 #else
2737 return PURPLE_MEDIA_CAPS_NONE; 2926 return PURPLE_MEDIA_CAPS_NONE;
2738 #endif 2927 #endif

mercurial