comparison libpurple/protocols/jabber/jabber.c @ 25982:7e020fbe2cdb

propagate from branch 'im.pidgin.pidgin' (head 303af74a38e7b313d4fb0be4d4054a16cb13d819) to branch 'im.pidgin.cpw.darkrain42.xmpp.avatars' (head 11e989f3ac36a0f958f031d55245db093923ea76)
author Paul Aurich <paul@darkrain42.org>
date Sat, 07 Mar 2009 01:32:29 +0000
parents 2d92bbe6807b 5f9a24d1c25e
children 7027cc42e56c
comparison
equal deleted inserted replaced
25832:2d92bbe6807b 25982:7e020fbe2cdb
147 147
148 jabber_session_init(js); 148 jabber_session_init(js);
149 } 149 }
150 150
151 static char *jabber_prep_resource(char *input) { 151 static char *jabber_prep_resource(char *input) {
152 char hostname[256]; /* current hostname */ 152 char hostname[256], /* current hostname */
153 *dot = NULL;
153 154
154 /* Empty resource == don't send any */ 155 /* Empty resource == don't send any */
155 if (input == NULL || *input == '\0') 156 if (input == NULL || *input == '\0')
156 return NULL; 157 return NULL;
157 158
169 */ 170 */
170 strcpy(hostname, "localhost"); 171 strcpy(hostname, "localhost");
171 } 172 }
172 hostname[sizeof(hostname) - 1] = '\0'; 173 hostname[sizeof(hostname) - 1] = '\0';
173 174
175 /* We want only the short hostname, not the FQDN - this will prevent the
176 * resource string from being unreasonably long on systems which stuff the
177 * whole FQDN in the hostname */
178 if((dot = strchr(hostname, '.')))
179 dot = '\0';
180
174 return purple_strreplace(input, "__HOSTNAME__", hostname); 181 return purple_strreplace(input, "__HOSTNAME__", hostname);
175 } 182 }
176 183
177 static void jabber_stream_features_parse(JabberStream *js, xmlnode *packet) 184 static void jabber_stream_features_parse(JabberStream *js, xmlnode *packet)
178 { 185 {
179 if(xmlnode_get_child(packet, "starttls")) { 186 if(xmlnode_get_child(packet, "starttls")) {
180 if(jabber_process_starttls(js, packet)) 187 if(jabber_process_starttls(js, packet))
181 188
182 return; 189 return;
183 } else if(purple_account_get_bool(js->gc->account, "require_tls", FALSE) && !js->gsc) { 190 } else if(purple_account_get_bool(js->gc->account, "require_tls", FALSE) && !js->gsc) {
184 purple_connection_error_reason (js->gc, 191 purple_connection_error_reason (js->gc,
185 PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR, 192 PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR,
186 _("You require encryption, but it is not available on this server.")); 193 _("You require encryption, but it is not available on this server."));
459 { 466 {
460 JabberStream *js = gc->proto_data; 467 JabberStream *js = gc->proto_data;
461 468
462 if (js->keepalive_timeout == -1) { 469 if (js->keepalive_timeout == -1) {
463 JabberIq *iq = jabber_iq_new(js, JABBER_IQ_GET); 470 JabberIq *iq = jabber_iq_new(js, JABBER_IQ_GET);
464 471
465 xmlnode *ping = xmlnode_new_child(iq->node, "ping"); 472 xmlnode *ping = xmlnode_new_child(iq->node, "ping");
466 xmlnode_set_namespace(ping, "urn:xmpp:ping"); 473 xmlnode_set_namespace(ping, "urn:xmpp:ping");
467 474
468 js->keepalive_timeout = purple_timeout_add_seconds(120, (GSourceFunc)(jabber_pong_timeout), gc); 475 js->keepalive_timeout = purple_timeout_add_seconds(120, (GSourceFunc)(jabber_pong_timeout), gc);
469 jabber_iq_set_callback(iq, jabber_pong_cb, NULL); 476 jabber_iq_set_callback(iq, jabber_pong_cb, NULL);
470 jabber_iq_send(iq); 477 jabber_iq_send(iq);
471 } 478 }
472 } 479 }
570 577
571 if(js->state == JABBER_STREAM_CONNECTING) 578 if(js->state == JABBER_STREAM_CONNECTING)
572 jabber_send_raw(js, "<?xml version='1.0' ?>", -1); 579 jabber_send_raw(js, "<?xml version='1.0' ?>", -1);
573 jabber_stream_set_state(js, JABBER_STREAM_INITIALIZING); 580 jabber_stream_set_state(js, JABBER_STREAM_INITIALIZING);
574 purple_ssl_input_add(gsc, jabber_recv_cb_ssl, gc); 581 purple_ssl_input_add(gsc, jabber_recv_cb_ssl, gc);
575 582
576 /* Tell the app that we're doing encryption */ 583 /* Tell the app that we're doing encryption */
577 jabber_stream_set_state(js, JABBER_STREAM_INITIALIZING_ENCRYPTION); 584 jabber_stream_set_state(js, JABBER_STREAM_INITIALIZING_ENCRYPTION);
578 } 585 }
579 586
580 587
729 purple_connection_error_reason (gc, 736 purple_connection_error_reason (gc,
730 PURPLE_CONNECTION_ERROR_INVALID_SETTINGS, 737 PURPLE_CONNECTION_ERROR_INVALID_SETTINGS,
731 _("Invalid XMPP ID")); 738 _("Invalid XMPP ID"));
732 return; 739 return;
733 } 740 }
734 741
735 if (!js->user->domain || *(js->user->domain) == '\0') { 742 if (!js->user->domain || *(js->user->domain) == '\0') {
736 purple_connection_error_reason (gc, 743 purple_connection_error_reason (gc,
737 PURPLE_CONNECTION_ERROR_INVALID_SETTINGS, 744 PURPLE_CONNECTION_ERROR_INVALID_SETTINGS,
738 _("Invalid XMPP ID. Domain must be set.")); 745 _("Invalid XMPP ID. Domain must be set."));
739 return; 746 return;
813 if(js->registration) { 820 if(js->registration) {
814 buf = g_strdup_printf(_("Registration of %s@%s successful"), 821 buf = g_strdup_printf(_("Registration of %s@%s successful"),
815 js->user->node, js->user->domain); 822 js->user->node, js->user->domain);
816 if(account->registration_cb) 823 if(account->registration_cb)
817 (account->registration_cb)(account, TRUE, account->registration_cb_user_data); 824 (account->registration_cb)(account, TRUE, account->registration_cb_user_data);
818 } 825 } else {
819 else 826 g_return_if_fail(to != NULL);
820 buf = g_strdup_printf(_("Registration to %s successful"), 827 buf = g_strdup_printf(_("Registration to %s successful"),
821 to); 828 to);
829 }
822 purple_notify_info(NULL, _("Registration Successful"), 830 purple_notify_info(NULL, _("Registration Successful"),
823 _("Registration Successful"), buf); 831 _("Registration Successful"), buf);
824 g_free(buf); 832 g_free(buf);
825 } else { 833 } else {
826 char *msg = jabber_parse_error(js, packet, NULL); 834 char *msg = jabber_parse_error(js, packet, NULL);
843 jabber_unregistration_result_cb(JabberStream *js, xmlnode *packet, gpointer data) 851 jabber_unregistration_result_cb(JabberStream *js, xmlnode *packet, gpointer data)
844 { 852 {
845 const char *type = xmlnode_get_attrib(packet, "type"); 853 const char *type = xmlnode_get_attrib(packet, "type");
846 char *buf; 854 char *buf;
847 char *to = data; 855 char *to = data;
848 856
857 /* This function is never called for unregistering our XMPP account from
858 * the server, so there should always be a 'to' address. */
859 g_return_if_fail(to != NULL);
860
849 if(!strcmp(type, "result")) { 861 if(!strcmp(type, "result")) {
850 buf = g_strdup_printf(_("Registration from %s successfully removed"), 862 buf = g_strdup_printf(_("Registration from %s successfully removed"),
851 to); 863 to);
852 purple_notify_info(NULL, _("Unregistration Successful"), 864 purple_notify_info(NULL, _("Unregistration Successful"),
853 _("Unregistration Successful"), buf); 865 _("Unregistration Successful"), buf);
854 g_free(buf); 866 g_free(buf);
855 } else { 867 } else {
856 char *msg = jabber_parse_error(js, packet, NULL); 868 char *msg = jabber_parse_error(js, packet, NULL);
857 869
858 if(!msg) 870 if(!msg)
859 msg = g_strdup(_("Unknown Error")); 871 msg = g_strdup(_("Unknown Error"));
860 872
861 purple_notify_error(NULL, _("Unregistration Failed"), 873 purple_notify_error(NULL, _("Unregistration Failed"),
862 _("Unregistration Failed"), msg); 874 _("Unregistration Failed"), msg);
863 g_free(msg); 875 g_free(msg);
864 } 876 }
865 g_free(to); 877 g_free(to);
878 JabberIq *iq; 890 JabberIq *iq;
879 char *username; 891 char *username;
880 892
881 iq = jabber_iq_new_query(cbdata->js, JABBER_IQ_SET, "jabber:iq:register"); 893 iq = jabber_iq_new_query(cbdata->js, JABBER_IQ_SET, "jabber:iq:register");
882 query = xmlnode_get_child(iq->node, "query"); 894 query = xmlnode_get_child(iq->node, "query");
883 xmlnode_set_attrib(iq->node, "to", cbdata->who); 895 if (cbdata->who)
896 xmlnode_set_attrib(iq->node, "to", cbdata->who);
884 897
885 for(groups = purple_request_fields_get_groups(fields); groups; 898 for(groups = purple_request_fields_get_groups(fields); groups;
886 groups = groups->next) { 899 groups = groups->next) {
887 for(flds = purple_request_field_group_get_fields(groups->data); 900 for(flds = purple_request_field_group_get_fields(groups->data);
888 flds; flds = flds->next) { 901 flds; flds = flds->next) {
894 /* unregister from service. this doesn't include any of the fields, so remove them from the stanza by recreating it 907 /* unregister from service. this doesn't include any of the fields, so remove them from the stanza by recreating it
895 (there's no "remove child" function for xmlnode) */ 908 (there's no "remove child" function for xmlnode) */
896 jabber_iq_free(iq); 909 jabber_iq_free(iq);
897 iq = jabber_iq_new_query(cbdata->js, JABBER_IQ_SET, "jabber:iq:register"); 910 iq = jabber_iq_new_query(cbdata->js, JABBER_IQ_SET, "jabber:iq:register");
898 query = xmlnode_get_child(iq->node, "query"); 911 query = xmlnode_get_child(iq->node, "query");
899 xmlnode_set_attrib(iq->node,"to",cbdata->who); 912 if (cbdata->who)
913 xmlnode_set_attrib(iq->node,"to",cbdata->who);
900 xmlnode_new_child(query, "remove"); 914 xmlnode_new_child(query, "remove");
901 915
902 jabber_iq_set_callback(iq, jabber_unregistration_result_cb, cbdata->who); 916 jabber_iq_set_callback(iq, jabber_unregistration_result_cb, cbdata->who);
903 917
904 jabber_iq_send(iq); 918 jabber_iq_send(iq);
905 g_free(cbdata); 919 g_free(cbdata);
906 return; 920 return;
907 } 921 }
908 } else { 922 } else {
939 } else { 953 } else {
940 continue; 954 continue;
941 } 955 }
942 xmlnode_insert_data(y, value, -1); 956 xmlnode_insert_data(y, value, -1);
943 if(cbdata->js->registration && !strcmp(id, "username")) { 957 if(cbdata->js->registration && !strcmp(id, "username")) {
944 if(cbdata->js->user->node) 958 g_free(cbdata->js->user->node);
945 g_free(cbdata->js->user->node);
946 cbdata->js->user->node = g_strdup(value); 959 cbdata->js->user->node = g_strdup(value);
947 } 960 }
948 if(cbdata->js->registration && !strcmp(id, "password")) 961 if(cbdata->js->registration && !strcmp(id, "password"))
949 purple_account_set_password(cbdata->js->gc->account, value); 962 purple_account_set_password(cbdata->js->gc->account, value);
950 } 963 }
983 JabberIq *iq; 996 JabberIq *iq;
984 char *to = data; 997 char *to = data;
985 998
986 iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:register"); 999 iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:register");
987 query = xmlnode_get_child(iq->node, "query"); 1000 query = xmlnode_get_child(iq->node, "query");
988 xmlnode_set_attrib(iq->node,"to",to); 1001 if (to)
1002 xmlnode_set_attrib(iq->node,"to",to);
989 1003
990 xmlnode_insert_child(query, result); 1004 xmlnode_insert_child(query, result);
991 1005
992 jabber_iq_set_callback(iq, jabber_registration_result_cb, to); 1006 jabber_iq_set_callback(iq, jabber_registration_result_cb, to);
993 jabber_iq_send(iq); 1007 jabber_iq_send(iq);
1008 1022
1009 if(!(type = xmlnode_get_attrib(packet, "type")) || strcmp(type, "result")) 1023 if(!(type = xmlnode_get_attrib(packet, "type")) || strcmp(type, "result"))
1010 return; 1024 return;
1011 1025
1012 from = xmlnode_get_attrib(packet, "from"); 1026 from = xmlnode_get_attrib(packet, "from");
1013 if (!from) 1027
1014 from = js->serverFQDN;
1015 g_return_if_fail(from != NULL);
1016
1017 if(js->registration) { 1028 if(js->registration) {
1018 /* get rid of the login thingy */ 1029 /* get rid of the login thingy */
1019 purple_connection_set_state(js->gc, PURPLE_CONNECTED); 1030 purple_connection_set_state(js->gc, PURPLE_CONNECTED);
1020 } 1031 }
1021 1032
1031 (account->registration_cb)(account, FALSE, account->registration_cb_user_data); 1042 (account->registration_cb)(account, FALSE, account->registration_cb_user_data);
1032 jabber_connection_schedule_close(js); 1043 jabber_connection_schedule_close(js);
1033 return; 1044 return;
1034 } 1045 }
1035 } 1046 }
1036 1047
1037 if((x = xmlnode_get_child_with_namespace(packet, "x", "jabber:x:data"))) { 1048 if((x = xmlnode_get_child_with_namespace(query, "x", "jabber:x:data"))) {
1038 jabber_x_data_request(js, x, jabber_register_x_data_cb, g_strdup(from)); 1049 jabber_x_data_request(js, x, jabber_register_x_data_cb, g_strdup(from));
1039 return; 1050 return;
1040 1051
1041 } else if((x = xmlnode_get_child_with_namespace(packet, "x", "jabber:x:oob"))) { 1052 } else if((x = xmlnode_get_child_with_namespace(query, "x", "jabber:x:oob"))) {
1042 xmlnode *url; 1053 xmlnode *url;
1043 1054
1044 if((url = xmlnode_get_child(x, "url"))) { 1055 if((url = xmlnode_get_child(x, "url"))) {
1045 char *href; 1056 char *href;
1046 if((href = xmlnode_get_data(url))) { 1057 if((href = xmlnode_get_data(url))) {
1156 _("Register"), G_CALLBACK(jabber_register_cb), 1167 _("Register"), G_CALLBACK(jabber_register_cb),
1157 _("Cancel"), G_CALLBACK(jabber_register_cancel_cb), 1168 _("Cancel"), G_CALLBACK(jabber_register_cancel_cb),
1158 purple_connection_get_account(js->gc), NULL, NULL, 1169 purple_connection_get_account(js->gc), NULL, NULL,
1159 cbdata); 1170 cbdata);
1160 else { 1171 else {
1161 char *title = registered?g_strdup_printf(_("Change Account Registration at %s"), from) 1172 char *title;
1173 g_return_if_fail(from != NULL);
1174 title = registered ? g_strdup_printf(_("Change Account Registration at %s"), from)
1162 :g_strdup_printf(_("Register New Account at %s"), from); 1175 :g_strdup_printf(_("Register New Account at %s"), from);
1163 purple_request_fields(js->gc, title, 1176 purple_request_fields(js->gc, title,
1164 title, instructions, fields, 1177 title, instructions, fields,
1165 (registered ? _("Change Registration") : _("Register")), G_CALLBACK(jabber_register_cb), 1178 (registered ? _("Change Registration") : _("Register")), G_CALLBACK(jabber_register_cb),
1166 _("Cancel"), G_CALLBACK(jabber_register_cancel_cb), 1179 _("Cancel"), G_CALLBACK(jabber_register_cancel_cb),
1180 jabber_iq_send(iq); 1193 jabber_iq_send(iq);
1181 } 1194 }
1182 1195
1183 void jabber_register_gateway(JabberStream *js, const char *gateway) { 1196 void jabber_register_gateway(JabberStream *js, const char *gateway) {
1184 JabberIq *iq; 1197 JabberIq *iq;
1185 1198
1186 iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:register"); 1199 iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:register");
1187 xmlnode_set_attrib(iq->node, "to", gateway); 1200 xmlnode_set_attrib(iq->node, "to", gateway);
1188 jabber_iq_send(iq); 1201 jabber_iq_send(iq);
1189 } 1202 }
1190 1203
1255 static void jabber_unregister_account_iq_cb(JabberStream *js, xmlnode *packet, gpointer data) { 1268 static void jabber_unregister_account_iq_cb(JabberStream *js, xmlnode *packet, gpointer data) {
1256 PurpleAccount *account = purple_connection_get_account(js->gc); 1269 PurpleAccount *account = purple_connection_get_account(js->gc);
1257 const char *type = xmlnode_get_attrib(packet,"type"); 1270 const char *type = xmlnode_get_attrib(packet,"type");
1258 if(!strcmp(type,"error")) { 1271 if(!strcmp(type,"error")) {
1259 char *msg = jabber_parse_error(js, packet, NULL); 1272 char *msg = jabber_parse_error(js, packet, NULL);
1260 1273
1261 purple_notify_error(js->gc, _("Error unregistering account"), 1274 purple_notify_error(js->gc, _("Error unregistering account"),
1262 _("Error unregistering account"), msg); 1275 _("Error unregistering account"), msg);
1263 g_free(msg); 1276 g_free(msg);
1264 if(js->unregistration_cb) 1277 if(js->unregistration_cb)
1265 js->unregistration_cb(account, FALSE, js->unregistration_user_data); 1278 js->unregistration_cb(account, FALSE, js->unregistration_user_data);
1289 } 1302 }
1290 1303
1291 void jabber_unregister_account(PurpleAccount *account, PurpleAccountUnregistrationCb cb, void *user_data) { 1304 void jabber_unregister_account(PurpleAccount *account, PurpleAccountUnregistrationCb cb, void *user_data) {
1292 PurpleConnection *gc = purple_account_get_connection(account); 1305 PurpleConnection *gc = purple_account_get_connection(account);
1293 JabberStream *js; 1306 JabberStream *js;
1294 1307
1295 if(gc->state != PURPLE_CONNECTED) { 1308 if(gc->state != PURPLE_CONNECTED) {
1296 if(gc->state != PURPLE_CONNECTING) 1309 if(gc->state != PURPLE_CONNECTING)
1297 jabber_login(account); 1310 jabber_login(account);
1298 js = gc->proto_data; 1311 js = gc->proto_data;
1299 js->unregistration = TRUE; 1312 js->unregistration = TRUE;
1300 js->unregistration_cb = cb; 1313 js->unregistration_cb = cb;
1301 js->unregistration_user_data = user_data; 1314 js->unregistration_user_data = user_data;
1302 return; 1315 return;
1303 } 1316 }
1304 1317
1305 js = gc->proto_data; 1318 js = gc->proto_data;
1306 1319
1307 if (js->unregistration) { 1320 if (js->unregistration) {
1308 purple_debug_error("jabber", "Unregistration in process; ignoring duplicate request.\n"); 1321 purple_debug_error("jabber", "Unregistration in process; ignoring duplicate request.\n");
1309 return; 1322 return;
1601 1614
1602 feat = g_new0(JabberFeature,1); 1615 feat = g_new0(JabberFeature,1);
1603 feat->shortname = g_strdup(shortname); 1616 feat->shortname = g_strdup(shortname);
1604 feat->namespace = g_strdup(namespace); 1617 feat->namespace = g_strdup(namespace);
1605 feat->is_enabled = cb; 1618 feat->is_enabled = cb;
1606 1619
1607 /* try to remove just in case it already exists in the list */ 1620 /* try to remove just in case it already exists in the list */
1608 jabber_remove_feature(shortname); 1621 jabber_remove_feature(shortname);
1609 1622
1610 jabber_features = g_list_append(jabber_features, feat); 1623 jabber_features = g_list_append(jabber_features, feat);
1611 } 1624 }
1612 1625
1613 void jabber_remove_feature(const char *shortname) { 1626 void jabber_remove_feature(const char *shortname) {
1614 GList *feature; 1627 GList *feature;
1615 for(feature = jabber_features; feature; feature = feature->next) { 1628 for(feature = jabber_features; feature; feature = feature->next) {
1616 JabberFeature *feat = (JabberFeature*)feature->data; 1629 JabberFeature *feat = (JabberFeature*)feature->data;
1617 if(!strcmp(feat->shortname, shortname)) { 1630 if(!strcmp(feat->shortname, shortname)) {
1618 g_free(feat->shortname); 1631 g_free(feat->shortname);
1619 g_free(feat->namespace); 1632 g_free(feat->namespace);
1620 1633
1621 g_free(feature->data); 1634 g_free(feature->data);
1622 jabber_features = g_list_delete_link(jabber_features, feature); 1635 jabber_features = g_list_delete_link(jabber_features, feature);
1623 break; 1636 break;
1624 } 1637 }
1625 } 1638 }
1632 1645
1633 const char* jabber_list_emblem(PurpleBuddy *b) 1646 const char* jabber_list_emblem(PurpleBuddy *b)
1634 { 1647 {
1635 JabberStream *js; 1648 JabberStream *js;
1636 JabberBuddy *jb = NULL; 1649 JabberBuddy *jb = NULL;
1637 1650 PurpleConnection *gc = purple_account_get_connection(purple_buddy_get_account(b));
1638 if(!b->account->gc) 1651
1652 if(!gc)
1639 return NULL; 1653 return NULL;
1640 1654
1641 js = b->account->gc->proto_data; 1655 js = gc->proto_data;
1642 if(js) 1656 if(js)
1643 jb = jabber_buddy_find(js, b->name, FALSE); 1657 jb = jabber_buddy_find(js, purple_buddy_get_name(b), FALSE);
1644 1658
1645 if(!PURPLE_BUDDY_IS_ONLINE(b)) { 1659 if(!PURPLE_BUDDY_IS_ONLINE(b)) {
1646 if(jb && (jb->subscription & JABBER_SUB_PENDING || 1660 if(jb && (jb->subscription & JABBER_SUB_PENDING ||
1647 !(jb->subscription & JABBER_SUB_TO))) 1661 !(jb->subscription & JABBER_SUB_TO)))
1648 return "not-authorized"; 1662 return "not-authorized";
1652 1666
1653 char *jabber_status_text(PurpleBuddy *b) 1667 char *jabber_status_text(PurpleBuddy *b)
1654 { 1668 {
1655 char *ret = NULL; 1669 char *ret = NULL;
1656 JabberBuddy *jb = NULL; 1670 JabberBuddy *jb = NULL;
1657 1671 PurpleAccount *account = purple_buddy_get_account(b);
1658 if (b->account->gc && b->account->gc->proto_data) 1672 PurpleConnection *gc = purple_account_get_connection(account);
1659 jb = jabber_buddy_find(b->account->gc->proto_data, b->name, FALSE); 1673
1674 if (gc && gc->proto_data)
1675 jb = jabber_buddy_find(gc->proto_data, purple_buddy_get_name(b), FALSE);
1660 1676
1661 if(jb && !PURPLE_BUDDY_IS_ONLINE(b) && (jb->subscription & JABBER_SUB_PENDING || !(jb->subscription & JABBER_SUB_TO))) { 1677 if(jb && !PURPLE_BUDDY_IS_ONLINE(b) && (jb->subscription & JABBER_SUB_PENDING || !(jb->subscription & JABBER_SUB_TO))) {
1662 ret = g_strdup(_("Not Authorized")); 1678 ret = g_strdup(_("Not Authorized"));
1663 } else if(jb && !PURPLE_BUDDY_IS_ONLINE(b) && jb->error_msg) { 1679 } else if(jb && !PURPLE_BUDDY_IS_ONLINE(b) && jb->error_msg) {
1664 ret = g_strdup(jb->error_msg); 1680 ret = g_strdup(jb->error_msg);
1683 } 1699 }
1684 1700
1685 void jabber_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full) 1701 void jabber_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full)
1686 { 1702 {
1687 JabberBuddy *jb; 1703 JabberBuddy *jb;
1704 PurpleAccount *account;
1705 PurpleConnection *gc;
1688 1706
1689 g_return_if_fail(b != NULL); 1707 g_return_if_fail(b != NULL);
1690 g_return_if_fail(b->account != NULL); 1708
1691 g_return_if_fail(b->account->gc != NULL); 1709 account = purple_buddy_get_account(b);
1692 g_return_if_fail(b->account->gc->proto_data != NULL); 1710 g_return_if_fail(account != NULL);
1693 1711
1694 jb = jabber_buddy_find(b->account->gc->proto_data, b->name, 1712 gc = purple_account_get_connection(account);
1695 FALSE); 1713 g_return_if_fail(gc != NULL);
1714 g_return_if_fail(gc->proto_data != NULL);
1715
1716 jb = jabber_buddy_find(gc->proto_data, purple_buddy_get_name(b), FALSE);
1696 1717
1697 if(jb) { 1718 if(jb) {
1698 JabberBuddyResource *jbr = NULL; 1719 JabberBuddyResource *jbr = NULL;
1699 PurplePresence *presence = purple_buddy_get_presence(b); 1720 PurplePresence *presence = purple_buddy_get_presence(b);
1700 const char *sub; 1721 const char *sub;
1798 GList *jabber_status_types(PurpleAccount *account) 1819 GList *jabber_status_types(PurpleAccount *account)
1799 { 1820 {
1800 PurpleStatusType *type; 1821 PurpleStatusType *type;
1801 GList *types = NULL; 1822 GList *types = NULL;
1802 PurpleValue *priority_value; 1823 PurpleValue *priority_value;
1824 PurpleValue *buzz_enabled;
1803 1825
1804 priority_value = purple_value_new(PURPLE_TYPE_INT); 1826 priority_value = purple_value_new(PURPLE_TYPE_INT);
1805 purple_value_set_int(priority_value, 1); 1827 purple_value_set_int(priority_value, 1);
1828 buzz_enabled = purple_value_new(PURPLE_TYPE_BOOLEAN);
1829 purple_value_set_boolean(buzz_enabled, TRUE);
1806 type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE, 1830 type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE,
1807 jabber_buddy_state_get_status_id(JABBER_BUDDY_STATE_ONLINE), 1831 jabber_buddy_state_get_status_id(JABBER_BUDDY_STATE_ONLINE),
1808 NULL, TRUE, TRUE, FALSE, 1832 NULL, TRUE, TRUE, FALSE,
1809 "priority", _("Priority"), priority_value, 1833 "priority", _("Priority"), priority_value,
1810 "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), 1834 "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
1811 "mood", _("Mood"), purple_value_new(PURPLE_TYPE_STRING), 1835 "mood", _("Mood"), purple_value_new(PURPLE_TYPE_STRING),
1812 "moodtext", _("Mood Text"), purple_value_new(PURPLE_TYPE_STRING), 1836 "moodtext", _("Mood Text"), purple_value_new(PURPLE_TYPE_STRING),
1813 "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING), 1837 "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING),
1814 "buzz", _("Allow Buzz"), purple_value_new(PURPLE_TYPE_BOOLEAN), 1838 "buzz", _("Allow Buzz"), buzz_enabled,
1815 NULL); 1839 NULL);
1816 types = g_list_append(types, type); 1840 types = g_list_append(types, type);
1817 1841
1818 priority_value = purple_value_new(PURPLE_TYPE_INT); 1842 priority_value = purple_value_new(PURPLE_TYPE_INT);
1819 purple_value_set_int(priority_value, 1); 1843 purple_value_set_int(priority_value, 1);
1844 buzz_enabled = purple_value_new(PURPLE_TYPE_BOOLEAN);
1845 purple_value_set_boolean(buzz_enabled, TRUE);
1820 type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE, 1846 type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE,
1821 jabber_buddy_state_get_status_id(JABBER_BUDDY_STATE_CHAT), 1847 jabber_buddy_state_get_status_id(JABBER_BUDDY_STATE_CHAT),
1822 _("Chatty"), TRUE, TRUE, FALSE, 1848 _("Chatty"), TRUE, TRUE, FALSE,
1823 "priority", _("Priority"), priority_value, 1849 "priority", _("Priority"), priority_value,
1824 "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), 1850 "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
1825 "mood", _("Mood"), purple_value_new(PURPLE_TYPE_STRING), 1851 "mood", _("Mood"), purple_value_new(PURPLE_TYPE_STRING),
1826 "moodtext", _("Mood Text"), purple_value_new(PURPLE_TYPE_STRING), 1852 "moodtext", _("Mood Text"), purple_value_new(PURPLE_TYPE_STRING),
1827 "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING), 1853 "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING),
1828 "buzz", _("Allow Buzz"), purple_value_new(PURPLE_TYPE_BOOLEAN), 1854 "buzz", _("Allow Buzz"), buzz_enabled,
1829 NULL); 1855 NULL);
1830 types = g_list_append(types, type); 1856 types = g_list_append(types, type);
1831 1857
1832 priority_value = purple_value_new(PURPLE_TYPE_INT); 1858 priority_value = purple_value_new(PURPLE_TYPE_INT);
1833 purple_value_set_int(priority_value, 0); 1859 purple_value_set_int(priority_value, 0);
1860 buzz_enabled = purple_value_new(PURPLE_TYPE_BOOLEAN);
1861 purple_value_set_boolean(buzz_enabled, TRUE);
1834 type = purple_status_type_new_with_attrs(PURPLE_STATUS_AWAY, 1862 type = purple_status_type_new_with_attrs(PURPLE_STATUS_AWAY,
1835 jabber_buddy_state_get_status_id(JABBER_BUDDY_STATE_AWAY), 1863 jabber_buddy_state_get_status_id(JABBER_BUDDY_STATE_AWAY),
1836 NULL, TRUE, TRUE, FALSE, 1864 NULL, TRUE, TRUE, FALSE,
1837 "priority", _("Priority"), priority_value, 1865 "priority", _("Priority"), priority_value,
1838 "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), 1866 "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
1839 "mood", _("Mood"), purple_value_new(PURPLE_TYPE_STRING), 1867 "mood", _("Mood"), purple_value_new(PURPLE_TYPE_STRING),
1840 "moodtext", _("Mood Text"), purple_value_new(PURPLE_TYPE_STRING), 1868 "moodtext", _("Mood Text"), purple_value_new(PURPLE_TYPE_STRING),
1841 "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING), 1869 "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING),
1842 "buzz", _("Allow Buzz"), purple_value_new(PURPLE_TYPE_BOOLEAN), 1870 "buzz", _("Allow Buzz"), buzz_enabled,
1843 NULL); 1871 NULL);
1844 types = g_list_append(types, type); 1872 types = g_list_append(types, type);
1845 1873
1846 priority_value = purple_value_new(PURPLE_TYPE_INT); 1874 priority_value = purple_value_new(PURPLE_TYPE_INT);
1847 purple_value_set_int(priority_value, 0); 1875 purple_value_set_int(priority_value, 0);
1876 buzz_enabled = purple_value_new(PURPLE_TYPE_BOOLEAN);
1877 purple_value_set_boolean(buzz_enabled, TRUE);
1848 type = purple_status_type_new_with_attrs(PURPLE_STATUS_EXTENDED_AWAY, 1878 type = purple_status_type_new_with_attrs(PURPLE_STATUS_EXTENDED_AWAY,
1849 jabber_buddy_state_get_status_id(JABBER_BUDDY_STATE_XA), 1879 jabber_buddy_state_get_status_id(JABBER_BUDDY_STATE_XA),
1850 NULL, TRUE, TRUE, FALSE, 1880 NULL, TRUE, TRUE, FALSE,
1851 "priority", _("Priority"), priority_value, 1881 "priority", _("Priority"), priority_value,
1852 "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), 1882 "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
1853 "mood", _("Mood"), purple_value_new(PURPLE_TYPE_STRING), 1883 "mood", _("Mood"), purple_value_new(PURPLE_TYPE_STRING),
1854 "moodtext", _("Mood Text"), purple_value_new(PURPLE_TYPE_STRING), 1884 "moodtext", _("Mood Text"), purple_value_new(PURPLE_TYPE_STRING),
1855 "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING), 1885 "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING),
1856 "buzz", _("Allow Buzz"), purple_value_new(PURPLE_TYPE_BOOLEAN), 1886 "buzz", _("Allow Buzz"), buzz_enabled,
1857 NULL); 1887 NULL);
1858 types = g_list_append(types, type); 1888 types = g_list_append(types, type);
1859 1889
1860 priority_value = purple_value_new(PURPLE_TYPE_INT); 1890 priority_value = purple_value_new(PURPLE_TYPE_INT);
1861 purple_value_set_int(priority_value, 0); 1891 purple_value_set_int(priority_value, 0);
1865 "priority", _("Priority"), priority_value, 1895 "priority", _("Priority"), priority_value,
1866 "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), 1896 "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
1867 "mood", _("Mood"), purple_value_new(PURPLE_TYPE_STRING), 1897 "mood", _("Mood"), purple_value_new(PURPLE_TYPE_STRING),
1868 "moodtext", _("Mood Text"), purple_value_new(PURPLE_TYPE_STRING), 1898 "moodtext", _("Mood Text"), purple_value_new(PURPLE_TYPE_STRING),
1869 "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING), 1899 "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING),
1870 "buzz", _("Allow Buzz"), purple_value_new(PURPLE_TYPE_BOOLEAN),
1871 NULL); 1900 NULL);
1872 types = g_list_append(types, type); 1901 types = g_list_append(types, type);
1873 1902
1874 /* 1903 /*
1875 if(js->protocol_version == JABBER_PROTO_0_9) 1904 if(js->protocol_version == JABBER_PROTO_0_9)
2011 2040
2012 purple_debug_info("jabber", "jabber_actions: have pep: %s\n", js->pep?"YES":"NO"); 2041 purple_debug_info("jabber", "jabber_actions: have pep: %s\n", js->pep?"YES":"NO");
2013 2042
2014 if(js->pep) 2043 if(js->pep)
2015 jabber_pep_init_actions(&m); 2044 jabber_pep_init_actions(&m);
2016 2045
2017 if(js->commands) 2046 if(js->commands)
2018 jabber_adhoc_init_server_commands(js, &m); 2047 jabber_adhoc_init_server_commands(js, &m);
2019 2048
2020 return m; 2049 return m;
2021 } 2050 }
2026 JabberID *jid; 2055 JabberID *jid;
2027 2056
2028 if(!(jid = jabber_id_new(name))) 2057 if(!(jid = jabber_id_new(name)))
2029 return NULL; 2058 return NULL;
2030 2059
2031 for(gnode = purple_get_blist()->root; gnode; gnode = gnode->next) { 2060 for(gnode = purple_blist_get_root(); gnode;
2032 for(cnode = gnode->child; cnode; cnode = cnode->next) { 2061 gnode = purple_blist_node_get_sibling_next(gnode)) {
2062 for(cnode = purple_blist_node_get_first_child(gnode);
2063 cnode;
2064 cnode = purple_blist_node_get_sibling_next(cnode)) {
2033 PurpleChat *chat = (PurpleChat*)cnode; 2065 PurpleChat *chat = (PurpleChat*)cnode;
2034 const char *room, *server; 2066 const char *room, *server;
2067 GHashTable *components;
2035 if(!PURPLE_BLIST_NODE_IS_CHAT(cnode)) 2068 if(!PURPLE_BLIST_NODE_IS_CHAT(cnode))
2036 continue; 2069 continue;
2037 2070
2038 if(chat->account != account) 2071 if (purple_chat_get_account(chat) != account)
2039 continue; 2072 continue;
2040 2073
2041 if(!(room = g_hash_table_lookup(chat->components, "room"))) 2074 components = purple_chat_get_components(chat);
2075 if(!(room = g_hash_table_lookup(components, "room")))
2042 continue; 2076 continue;
2043 if(!(server = g_hash_table_lookup(chat->components, "server"))) 2077 if(!(server = g_hash_table_lookup(components, "server")))
2044 continue; 2078 continue;
2045 2079
2046 if(jid->node && jid->domain && 2080 if(jid->node && jid->domain &&
2047 !g_utf8_collate(room, jid->node) && !g_utf8_collate(server, jid->domain)) { 2081 !g_utf8_collate(room, jid->node) && !g_utf8_collate(server, jid->domain)) {
2048 jabber_id_free(jid); 2082 jabber_id_free(jid);
2058 { 2092 {
2059 JabberStream *js = gc->proto_data; 2093 JabberStream *js = gc->proto_data;
2060 JabberID *jid; 2094 JabberID *jid;
2061 JabberBuddy *jb; 2095 JabberBuddy *jb;
2062 JabberBuddyResource *jbr; 2096 JabberBuddyResource *jbr;
2063 2097
2064 if(!(jid = jabber_id_new(who))) 2098 if(!(jid = jabber_id_new(who)))
2065 return; 2099 return;
2066 2100
2067 if((jb = jabber_buddy_find(js, who, TRUE)) && 2101 if((jb = jabber_buddy_find(js, who, TRUE)) &&
2068 (jbr = jabber_buddy_find_resource(jb, jid->resource))) { 2102 (jbr = jabber_buddy_find_resource(jb, jid->resource))) {
2319 JabberChat *chat = jabber_chat_find_by_conv(conv); 2353 JabberChat *chat = jabber_chat_find_by_conv(conv);
2320 2354
2321 if (!chat || !args || !args[0] || !args[1]) 2355 if (!chat || !args || !args[0] || !args[1])
2322 return PURPLE_CMD_RET_FAILED; 2356 return PURPLE_CMD_RET_FAILED;
2323 2357
2324 if (strcmp(args[1], "owner") != 0 && 2358 if (strcmp(args[1], "owner") != 0 &&
2325 strcmp(args[1], "admin") != 0 && 2359 strcmp(args[1], "admin") != 0 &&
2326 strcmp(args[1], "member") != 0 && 2360 strcmp(args[1], "member") != 0 &&
2327 strcmp(args[1], "outcast") != 0 && 2361 strcmp(args[1], "outcast") != 0 &&
2328 strcmp(args[1], "none") != 0) { 2362 strcmp(args[1], "none") != 0) {
2329 *error = g_strdup_printf(_("Unknown affiliation: \"%s\""), args[1]); 2363 *error = g_strdup_printf(_("Unknown affiliation: \"%s\""), args[1]);
2448 2482
2449 static gboolean _jabber_send_buzz(JabberStream *js, const char *username, char **error) { 2483 static gboolean _jabber_send_buzz(JabberStream *js, const char *username, char **error) {
2450 2484
2451 JabberBuddy *jb; 2485 JabberBuddy *jb;
2452 JabberBuddyResource *jbr; 2486 JabberBuddyResource *jbr;
2453 GList *iter; 2487 PurpleConnection *gc = js->gc;
2488 PurpleBuddy *buddy =
2489 purple_find_buddy(purple_connection_get_account(gc), username);
2490 const gchar *alias =
2491 buddy ? purple_buddy_get_contact_alias(buddy) : username;
2454 2492
2455 if(!username) 2493 if(!username)
2456 return FALSE; 2494 return FALSE;
2457 2495
2458 jb = jabber_buddy_find(js, username, FALSE); 2496 jb = jabber_buddy_find(js, username, FALSE);
2459 if(!jb) { 2497 if(!jb) {
2460 *error = g_strdup_printf(_("Unable to buzz, because there is nothing known about user %s."), username); 2498 *error = g_strdup_printf(_("Unable to buzz, because there is nothing "
2499 "known about %s."), alias);
2461 return FALSE; 2500 return FALSE;
2462 } 2501 }
2463 2502
2464 jbr = jabber_buddy_find_resource(jb, NULL); 2503 jbr = jabber_buddy_find_resource(jb, NULL);
2465 if(!jbr) { 2504 if (!jbr) {
2466 *error = g_strdup_printf(_("Unable to buzz, because user %s might be offline."), username); 2505 *error = g_strdup_printf(_("Unable to buzz, because %s might be offline."),
2506 alias);
2467 return FALSE; 2507 return FALSE;
2468 } 2508 }
2469 2509
2470 if(!jbr->caps) { 2510 if (jabber_resource_has_capability(jbr, XEP_0224_NAMESPACE)) {
2471 *error = g_strdup_printf(_("Unable to buzz, because there is nothing known about user %s."), username); 2511 xmlnode *buzz, *msg = xmlnode_new("message");
2512 gchar *to;
2513
2514 to = g_strdup_printf("%s/%s", username, jbr->name);
2515 xmlnode_set_attrib(msg, "to", to);
2516 g_free(to);
2517
2518 /* avoid offline storage */
2519 xmlnode_set_attrib(msg, "type", "headline");
2520
2521 buzz = xmlnode_new_child(msg, "attention");
2522 xmlnode_set_namespace(buzz, XEP_0224_NAMESPACE);
2523
2524 jabber_send(js, msg);
2525 xmlnode_free(msg);
2526
2527 return TRUE;
2528 } else {
2529 *error = g_strdup_printf(_("Unable to buzz, because %s does "
2530 "not support it or do not wish to receive buzzes now."), alias);
2472 return FALSE; 2531 return FALSE;
2473 } 2532 }
2474
2475 for(iter = jbr->caps->features; iter; iter = g_list_next(iter)) {
2476 if(!strcmp(iter->data, "http://www.xmpp.org/extensions/xep-0224.html#ns")) {
2477 xmlnode *buzz, *msg = xmlnode_new("message");
2478 gchar *to;
2479
2480 to = g_strdup_printf("%s/%s", username, jbr->name);
2481 xmlnode_set_attrib(msg, "to", to);
2482 g_free(to);
2483
2484 /* avoid offline storage */
2485 xmlnode_set_attrib(msg, "type", "headline");
2486
2487 buzz = xmlnode_new_child(msg, "attention");
2488 xmlnode_set_namespace(buzz, "http://www.xmpp.org/extensions/xep-0224.html#ns");
2489
2490 jabber_send(js, msg);
2491 xmlnode_free(msg);
2492
2493 return TRUE;
2494 }
2495 }
2496
2497 *error = g_strdup_printf(_("Unable to buzz, because the user %s does not support it."), username);
2498 return FALSE;
2499 } 2533 }
2500 2534
2501 static PurpleCmdRet jabber_cmd_buzz(PurpleConversation *conv, 2535 static PurpleCmdRet jabber_cmd_buzz(PurpleConversation *conv,
2502 const char *cmd, char **args, char **error, void *data) 2536 const char *cmd, char **args, char **error, void *data)
2503 { 2537 {
2504 JabberStream *js = conv->account->gc->proto_data; 2538 JabberStream *js = conv->account->gc->proto_data;
2505 2539 const gchar *who;
2506 if(!args || !args[0]) 2540
2541 if (!args || !args[0]) {
2542 /* use the buddy from conversation, if it's a one-to-one conversation */
2543 if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) {
2544 who = purple_conversation_get_name(conv);
2545 } else {
2546 return PURPLE_CMD_RET_FAILED;
2547 }
2548 } else {
2549 who = args[0];
2550 }
2551
2552 if (_jabber_send_buzz(js, who, error)) {
2553 const gchar *alias;
2554 gchar *str;
2555 PurpleBuddy *buddy =
2556 purple_find_buddy(purple_connection_get_account(conv->account->gc),
2557 who);
2558
2559 if (buddy != NULL)
2560 alias = purple_buddy_get_contact_alias(buddy);
2561 else
2562 alias = who;
2563
2564 str = g_strdup_printf(_("Buzzing %s..."), alias);
2565 purple_conversation_write(conv, NULL, str,
2566 PURPLE_MESSAGE_SYSTEM|PURPLE_MESSAGE_NOTIFY, time(NULL));
2567 g_free(str);
2568
2569 return PURPLE_CMD_RET_OK;
2570 } else {
2507 return PURPLE_CMD_RET_FAILED; 2571 return PURPLE_CMD_RET_FAILED;
2508 2572 }
2509 return _jabber_send_buzz(js, args[0], error) ? PURPLE_CMD_RET_OK : PURPLE_CMD_RET_FAILED;
2510 } 2573 }
2511 2574
2512 GList *jabber_attention_types(PurpleAccount *account) 2575 GList *jabber_attention_types(PurpleAccount *account)
2513 { 2576 {
2514 static GList *types = NULL; 2577 static GList *types = NULL;
2617 PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_IM | 2680 PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_IM |
2618 PURPLE_CMD_FLAG_PRPL_ONLY, 2681 PURPLE_CMD_FLAG_PRPL_ONLY,
2619 "prpl-jabber", jabber_cmd_ping, 2682 "prpl-jabber", jabber_cmd_ping,
2620 _("ping &lt;jid&gt;: Ping a user/component/server."), 2683 _("ping &lt;jid&gt;: Ping a user/component/server."),
2621 NULL); 2684 NULL);
2622 purple_cmd_register("buzz", "s", PURPLE_CMD_P_PRPL, 2685 purple_cmd_register("buzz", "w", PURPLE_CMD_P_PRPL,
2623 PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_PRPL_ONLY, 2686 PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_PRPL_ONLY |
2687 PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS,
2624 "prpl-jabber", jabber_cmd_buzz, 2688 "prpl-jabber", jabber_cmd_buzz,
2625 _("buzz: Buzz a user to get their attention"), NULL); 2689 _("buzz: Buzz a user to get their attention"), NULL);
2626 } 2690 }
2627 2691
2628 void 2692 void