8312
+ 鐃緒申 1 /*
+ 鐃緒申 2 * gaim - Jabber Protocol Plugin
+ 鐃緒申 3 *
+ 鐃緒申 4 * Copyright (C) 2003, Nathan Walp <faceprint@faceprint.com>
+ 鐃緒申 5 *
+ 鐃緒申 6 * This program is free software; you can redistribute it and/or modify
+ 鐃緒申 7 * it under the terms of the GNU General Public License as published by
+ 鐃緒申 8 * the Free Software Foundation; either version 2 of the License, or
+ 鐃緒申 9 * (at your option) any later version.
+ 鐃緒申 10 *
+ 鐃緒申 11 * This program is distributed in the hope that it will be useful,
+ 鐃緒申 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ 鐃緒申 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ 鐃緒申 14 * GNU General Public License for more details.
+ 鐃緒申 15 *
+ 鐃緒申 16 * You should have received a copy of the GNU General Public License
+ 鐃緒申 17 * along with this program; if not, write to the Free Software
+ 鐃緒申 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ 鐃緒申 19 *
+ 鐃緒申 20 */
+ 鐃緒申 21
+ 鐃緒申 22 #include "internal.h"
+ 鐃緒申 23 #include "prefs.h"
+ 鐃緒申 24
+ 鐃緒申 25 #include "buddy.h"
+ 鐃緒申 26 #include "iq.h"
+ 鐃緒申 27 #include "disco.h"
+ 鐃緒申 28
+ 鐃緒申 29
+ 鐃緒申 30 struct _jabber_disco_info_cb_data {
+ 鐃緒申 31 gpointer data;
+ 鐃緒申 32 JabberDiscoInfoCallback *callback;
+ 鐃緒申 33 };
+ 鐃緒申 34
+ 鐃緒申 35 #define SUPPORT_FEATURE(x) \
+ 鐃緒申 36 feature = xmlnode_new_child(query, "feature"); \
+ 鐃緒申 37 xmlnode_set_attrib(feature, "var", x);
+ 鐃緒申 38
+ 鐃緒申 39
+ 鐃緒申 40 void jabber_disco_info_parse(JabberStream *js, xmlnode *packet) {
+ 鐃緒申 41 const char *from = xmlnode_get_attrib(packet, "from");
+ 鐃緒申 42 const char *type = xmlnode_get_attrib(packet, "type");
+ 鐃緒申 43
+ 鐃緒申 44 if(!from || !type)
+ 鐃緒申 45 return;
+ 鐃緒申 46
+ 鐃緒申 47 if(!strcmp(type, "get")) {
+ 鐃緒申 48 xmlnode *query, *identity, *feature;
+ 鐃緒申 49 JabberIq *iq = jabber_iq_new_query(js, JABBER_IQ_RESULT,
+ 鐃緒申 50 "http://jabber.org/protocol/disco#info");
+ 鐃緒申 51
+ 鐃緒申 52 jabber_iq_set_id(iq, xmlnode_get_attrib(packet, "id"));
+ 鐃緒申 53
+ 鐃緒申 54 xmlnode_set_attrib(iq->node, "to", from);
+ 鐃緒申 55 query = xmlnode_get_child(iq->node, "query");
+ 鐃緒申 56
+ 鐃緒申 57 identity = xmlnode_new_child(query, "identity");
+ 鐃緒申 58 xmlnode_set_attrib(identity, "category", "client");
+ 鐃緒申 59 xmlnode_set_attrib(identity, "type", "pc"); /* XXX: bot, console,
+ 鐃緒申 60 * handheld, pc, phone,
+ 鐃緒申 61 * web */
+ 鐃緒申 62
+ 鐃緒申 63 SUPPORT_FEATURE("jabber:iq:last")
+ 鐃緒申 64 SUPPORT_FEATURE("jabber:iq:oob")
+ 鐃緒申 65 SUPPORT_FEATURE("jabber:iq:time")
+ 鐃緒申 66 SUPPORT_FEATURE("jabber:iq:version")
+ 鐃緒申 67 SUPPORT_FEATURE("jabber:x:conference")
+ 鐃緒申 68 SUPPORT_FEATURE("http://jabber.org/protocol/bytestreams")
+ 鐃緒申 69 SUPPORT_FEATURE("http://jabber.org/protocol/disco#info")
+ 鐃緒申 70 SUPPORT_FEATURE("http://jabber.org/protocol/disco#items")
+ 鐃緒申 71 #if 0
+ 鐃緒申 72 SUPPORT_FEATURE("http://jabber.org/protocol/ibb")
+ 鐃緒申 73 #endif
+ 鐃緒申 74 SUPPORT_FEATURE("http://jabber.org/protocol/muc")
+ 鐃緒申 75 SUPPORT_FEATURE("http://jabber.org/protocol/muc#user")
+ 鐃緒申 76 SUPPORT_FEATURE("http://jabber.org/protocol/si")
+ 鐃緒申 77 SUPPORT_FEATURE("http://jabber.org/protocol/si/profile/file-transfer")
+ 鐃緒申 78 SUPPORT_FEATURE("http://jabber.org/protocol/xhtml-im")
+ 鐃緒申 79
+ 鐃緒申 80 jabber_iq_send(iq);
+ 鐃緒申 81 } else if(!strcmp(type, "result")) {
+ 鐃緒申 82 xmlnode *query = xmlnode_get_child(packet, "query");
+ 鐃緒申 83 xmlnode *child;
+ 鐃緒申 84 JabberID *jid;
+ 鐃緒申 85 JabberBuddy *jb;
+ 鐃緒申 86 JabberBuddyResource *jbr = NULL;
+ 鐃緒申 87 JabberCapabilities capabilities = JABBER_CAP_NONE;
+ 鐃緒申 88 struct _jabber_disco_info_cb_data *jdicd;
+ 鐃緒申 89
+ 鐃緒申 90 if((jid = jabber_id_new(from))) {
+ 鐃緒申 91 if(jid->resource && (jb = jabber_buddy_find(js, from, TRUE)))
+ 鐃緒申 92 jbr = jabber_buddy_find_resource(jb, jid->resource);
+ 鐃緒申 93 jabber_id_free(jid);
+ 鐃緒申 94 }
+ 鐃緒申 95
+ 鐃緒申 96 if(jbr)
+ 鐃緒申 97 capabilities = jbr->capabilities;
+ 鐃緒申 98
+ 鐃緒申 99 for(child = query->child; child; child = child->next) {
+ 鐃緒申 100 if(child->type != XMLNODE_TYPE_TAG)
+ 鐃緒申 101 continue;
+ 鐃緒申 102
+ 鐃緒申 103 if(!strcmp(child->name, "identity")) {
+ 鐃緒申 104 const char *category = xmlnode_get_attrib(child, "category");
+ 鐃緒申 105 const char *type = xmlnode_get_attrib(child, "type");
+ 鐃緒申 106 if(!category || !type)
+ 鐃緒申 107 continue;
+ 鐃緒申 108
+ 鐃緒申 109 /* we found a groupchat or MUC server, add it to the list */
+ 鐃緒申 110 /* XXX: actually check for protocol/muc or gc-1.0 support */
+ 鐃緒申 111 if(!strcmp(category, "conference") && !strcmp(type, "text"))
+ 鐃緒申 112 js->chat_servers = g_list_append(js->chat_servers, g_strdup(from));
+ 鐃緒申 113
+ 鐃緒申 114 } else if(!strcmp(child->name, "feature")) {
+ 鐃緒申 115 const char *var = xmlnode_get_attrib(child, "var");
+ 鐃緒申 116 if(!var)
+ 鐃緒申 117 continue;
+ 鐃緒申 118
+ 鐃緒申 119 if(!strcmp(var, "http://jabber.org/protocol/si"))
+ 鐃緒申 120 capabilities |= JABBER_CAP_SI;
+ 鐃緒申 121 else if(!strcmp(var, "http://jabber.org/protocol/si/profile/file-transfer"))
+ 鐃緒申 122 capabilities |= JABBER_CAP_SI_FILE_XFER;
+ 鐃緒申 123 else if(!strcmp(var, "http://jabber.org/protocol/bytestreams"))
+ 鐃緒申 124 capabilities |= JABBER_CAP_BYTESTREAMS;
+ 鐃緒申 125 }
+ 鐃緒申 126 }
+ 鐃緒申 127
+ 鐃緒申 128 capabilities |= JABBER_CAP_RETRIEVED;
+ 鐃緒申 129
+ 鐃緒申 130 if(jbr)
+ 鐃緒申 131 jbr->capabilities = capabilities;
+ 鐃緒申 132
+ 鐃緒申 133 if((jdicd = g_hash_table_lookup(js->disco_callbacks, from))) {
+ 鐃緒申 134 jdicd->callback(js, from, capabilities, jdicd->data);
+ 鐃緒申 135 g_hash_table_remove(js->disco_callbacks, from);
+ 鐃緒申 136 }
+ 鐃緒申 137 } else if(!strcmp(type, "error")) {
+ 鐃緒申 138 JabberID *jid;
+ 鐃緒申 139 JabberBuddy *jb;
+ 鐃緒申 140 JabberBuddyResource *jbr = NULL;
+ 鐃緒申 141 JabberCapabilities capabilities = JABBER_CAP_NONE;
+ 鐃緒申 142 struct _jabber_disco_info_cb_data *jdicd;
+ 鐃緒申 143
+ 鐃緒申 144 if(!(jdicd = g_hash_table_lookup(js->disco_callbacks, from)))
+ 鐃緒申 145 return;
+ 鐃緒申 146
+ 鐃緒申 147 if((jid = jabber_id_new(from))) {
+ 鐃緒申 148 if(jid->resource && (jb = jabber_buddy_find(js, from, TRUE)))
+ 鐃緒申 149 jbr = jabber_buddy_find_resource(jb, jid->resource);
+ 鐃緒申 150 jabber_id_free(jid);
+ 鐃緒申 151 }
+ 鐃緒申 152
+ 鐃緒申 153 if(jbr)
+ 鐃緒申 154 capabilities = jbr->capabilities;
+ 鐃緒申 155
+ 鐃緒申 156 jdicd->callback(js, from, capabilities, jdicd->data);
+ 鐃緒申 157 g_hash_table_remove(js->disco_callbacks, from);
+ 鐃緒申 158 }
+ 鐃緒申 159 }
+ 鐃緒申 160
+ 鐃緒申 161 void jabber_disco_items_parse(JabberStream *js, xmlnode *packet) {
+ 鐃緒申 162 const char *from = xmlnode_get_attrib(packet, "from");
+ 鐃緒申 163 const char *type = xmlnode_get_attrib(packet, "type");
+ 鐃緒申 164
+ 鐃緒申 165 if(!strcmp(type, "get")) {
+ 鐃緒申 166 JabberIq *iq = jabber_iq_new_query(js, JABBER_IQ_RESULT,
+ 鐃緒申 167 "http://jabber.org/protocol/disco#items");
+ 鐃緒申 168
+ 鐃緒申 169 jabber_iq_set_id(iq, xmlnode_get_attrib(packet, "id"));
+ 鐃緒申 170
+ 鐃緒申 171 xmlnode_set_attrib(iq->node, "to", from);
+ 鐃緒申 172 jabber_iq_send(iq);
+ 鐃緒申 173 }
+ 鐃緒申 174 }
+ 鐃緒申 175
+ 鐃緒申 176 static void
+ 鐃緒申 177 jabber_disco_server_result_cb(JabberStream *js, xmlnode *packet, gpointer data)
+ 鐃緒申 178 {
+ 鐃緒申 179 xmlnode *query, *child;
+ 鐃緒申 180 const char *from = xmlnode_get_attrib(packet, "from");
+ 鐃緒申 181 const char *type = xmlnode_get_attrib(packet, "type");
+ 鐃緒申 182
+ 鐃緒申 183 if(!from || !type)
+ 鐃緒申 184 return;
+ 鐃緒申 185
+ 鐃緒申 186 if(strcmp(from, js->user->domain))
+ 鐃緒申 187 return;
+ 鐃緒申 188
+ 鐃緒申 189 if(strcmp(type, "result"))
+ 鐃緒申 190 return;
+ 鐃緒申 191
+ 鐃緒申 192 while(js->chat_servers) {
+ 鐃緒申 193 g_free(js->chat_servers->data);
+ 鐃緒申 194 js->chat_servers = g_list_delete_link(js->chat_servers, js->chat_servers);
+ 鐃緒申 195 }
+ 鐃緒申 196
+ 鐃緒申 197 query = xmlnode_get_child(packet, "query");
+ 鐃緒申 198
+ 鐃緒申 199 for(child = xmlnode_get_child(query, "item"); child;
+ 鐃緒申 200 child = xmlnode_get_next_twin(child)) {
+ 鐃緒申 201 JabberIq *iq;
+ 鐃緒申 202 const char *jid;
+ 鐃緒申 203
+ 鐃緒申 204 if(!(jid = xmlnode_get_attrib(child, "jid")))
+ 鐃緒申 205 continue;
+ 鐃緒申 206
+ 鐃緒申 207 iq = jabber_iq_new_query(js, JABBER_IQ_GET, "http://jabber.org/protocol/disco#info");
+ 鐃緒申 208 xmlnode_set_attrib(iq->node, "to", jid);
+ 鐃緒申 209 jabber_iq_send(iq);
+ 鐃緒申 210 }
+ 鐃緒申 211 }
+ 鐃緒申 212
+ 鐃緒申 213 void jabber_disco_items_server(JabberStream *js)
+ 鐃緒申 214 {
+ 鐃緒申 215 JabberIq *iq = jabber_iq_new_query(js, JABBER_IQ_GET,
+ 鐃緒申 216 "http://jabber.org/protocol/disco#items");
+ 鐃緒申 217
+ 鐃緒申 218 xmlnode_set_attrib(iq->node, "to", js->user->domain);
+ 鐃緒申 219
+ 鐃緒申 220 jabber_iq_set_callback(iq, jabber_disco_server_result_cb, NULL);
+ 鐃緒申 221 jabber_iq_send(iq);
+ 鐃緒申 222 }
+ 鐃緒申 223
+ 鐃緒申 224 void jabber_disco_info_do(JabberStream *js, const char *who, JabberDiscoInfoCallback *callback, gpointer data)
+ 鐃緒申 225 {
+ 鐃緒申 226 JabberID *jid;
+ 鐃緒申 227 JabberBuddy *jb;
+ 鐃緒申 228 JabberBuddyResource *jbr = NULL;
+ 鐃緒申 229 struct _jabber_disco_info_cb_data *jdicd;
+ 鐃緒申 230 JabberIq *iq;
+ 鐃緒申 231
+ 鐃緒申 232 if((jid = jabber_id_new(who))) {
+ 鐃緒申 233 if(jid->resource && (jb = jabber_buddy_find(js, who, TRUE)))
+ 鐃緒申 234 jbr = jabber_buddy_find_resource(jb, jid->resource);
+ 鐃緒申 235 jabber_id_free(jid);
+ 鐃緒申 236 }
+ 鐃緒申 237
+ 鐃緒申 238 if(jbr && jbr->capabilities & JABBER_CAP_RETRIEVED) {
+ 鐃緒申 239 callback(js, who, jbr->capabilities, data);
+ 鐃緒申 240 return;
+ 鐃緒申 241 }
+ 鐃緒申 242
+ 鐃緒申 243 jdicd = g_new0(struct _jabber_disco_info_cb_data, 1);
+ 鐃緒申 244 jdicd->data = data;
+ 鐃緒申 245 jdicd->callback = callback;
+ 鐃緒申 246
+ 鐃緒申 247 g_hash_table_insert(js->disco_callbacks, g_strdup(who), jdicd);
+ 鐃緒申 248
+ 鐃緒申 249 iq = jabber_iq_new_query(js, JABBER_IQ_GET, "http://jabber.org/protocol/disco#info");
+ 鐃緒申 250 xmlnode_set_attrib(iq->node, "to", who);
+ 鐃緒申 251
+ 鐃緒申 252 jabber_iq_send(iq);
+ 鐃緒申 253 }
+ 鐃緒申 254
+ 鐃緒申 255