| 33 typedef struct _JabberDataFormField { |
33 typedef struct _JabberDataFormField { |
| 34 gchar *var; |
34 gchar *var; |
| 35 GList *values; |
35 GList *values; |
| 36 } JabberDataFormField; |
36 } JabberDataFormField; |
| 37 |
37 |
| 38 typedef struct _JabberCapsKey { |
38 static GHashTable *capstable = NULL; /* JabberCapsTuple -> JabberCapsClientInfo */ |
| 39 char *node; |
|
| 40 char *ver; |
|
| 41 char *hash; |
|
| 42 } JabberCapsKey; |
|
| 43 |
|
| 44 static GHashTable *capstable = NULL; /* JabberCapsKey -> JabberCapsClientInfo */ |
|
| 45 static GHashTable *nodetable = NULL; /* char *node -> JabberCapsNodeExts */ |
39 static GHashTable *nodetable = NULL; /* char *node -> JabberCapsNodeExts */ |
| 46 static guint save_timer = 0; |
40 static guint save_timer = 0; |
| 47 |
41 |
| 48 /** |
42 /** |
| 49 * Processes a query-node and returns a JabberCapsClientInfo object with all relevant info. |
43 * Processes a query-node and returns a JabberCapsClientInfo object with all relevant info. |
| 84 g_hash_table_destroy(exts->exts); |
78 g_hash_table_destroy(exts->exts); |
| 85 g_free(exts); |
79 g_free(exts); |
| 86 } |
80 } |
| 87 |
81 |
| 88 static guint jabber_caps_hash(gconstpointer data) { |
82 static guint jabber_caps_hash(gconstpointer data) { |
| 89 const JabberCapsKey *key = data; |
83 const JabberCapsTuple *key = data; |
| 90 guint nodehash = g_str_hash(key->node); |
84 guint nodehash = g_str_hash(key->node); |
| 91 guint verhash = g_str_hash(key->ver); |
85 guint verhash = g_str_hash(key->ver); |
| 92 /* |
86 /* |
| 93 * 'hash' was optional in XEP-0115 v1.4 and g_str_hash crashes on NULL >:O. |
87 * 'hash' was optional in XEP-0115 v1.4 and g_str_hash crashes on NULL >:O. |
| 94 * Okay, maybe I've played too much Zelda, but that looks like |
88 * Okay, maybe I've played too much Zelda, but that looks like |
| 97 guint hashhash = (key->hash ? g_str_hash(key->hash) : 0); |
91 guint hashhash = (key->hash ? g_str_hash(key->hash) : 0); |
| 98 return nodehash ^ verhash ^ hashhash; |
92 return nodehash ^ verhash ^ hashhash; |
| 99 } |
93 } |
| 100 |
94 |
| 101 static gboolean jabber_caps_compare(gconstpointer v1, gconstpointer v2) { |
95 static gboolean jabber_caps_compare(gconstpointer v1, gconstpointer v2) { |
| 102 const JabberCapsKey *name1 = v1; |
96 const JabberCapsTuple *name1 = v1; |
| 103 const JabberCapsKey *name2 = v2; |
97 const JabberCapsTuple *name2 = v2; |
| 104 |
98 |
| 105 return g_str_equal(name1->node, name2->node) && |
99 return g_str_equal(name1->node, name2->node) && |
| 106 g_str_equal(name1->ver, name2->ver) && |
100 g_str_equal(name1->ver, name2->ver) && |
| 107 purple_strequal(name1->hash, name2->hash); |
101 purple_strequal(name1->hash, name2->hash); |
| 108 } |
|
| 109 |
|
| 110 void jabber_caps_destroy_key(gpointer data) { |
|
| 111 JabberCapsKey *key = data; |
|
| 112 g_free(key->node); |
|
| 113 g_free(key->ver); |
|
| 114 g_free(key->hash); |
|
| 115 g_free(key); |
|
| 116 } |
102 } |
| 117 |
103 |
| 118 static void |
104 static void |
| 119 jabber_caps_client_info_destroy(JabberCapsClientInfo *info) |
105 jabber_caps_client_info_destroy(JabberCapsClientInfo *info) |
| 120 { |
106 { |
| 138 info->forms = g_list_delete_link(info->forms, info->forms); |
124 info->forms = g_list_delete_link(info->forms, info->forms); |
| 139 } |
125 } |
| 140 |
126 |
| 141 jabber_caps_node_exts_unref(info->exts); |
127 jabber_caps_node_exts_unref(info->exts); |
| 142 |
128 |
| |
129 g_free((char *)info->tuple.node); |
| |
130 g_free((char *)info->tuple.ver); |
| |
131 g_free((char *)info->tuple.hash); |
| |
132 |
| 143 g_free(info); |
133 g_free(info); |
| 144 } |
134 } |
| 145 |
135 |
| 146 /* NOTE: Takes a reference to the exts, unref it if you don't really want to |
136 /* NOTE: Takes a reference to the exts, unref it if you don't really want to |
| 147 * keep it around. */ |
137 * keep it around. */ |
| 174 xmlnode_set_attrib(feature, "var", (const gchar *)node->data); |
164 xmlnode_set_attrib(feature, "var", (const gchar *)node->data); |
| 175 } |
165 } |
| 176 } |
166 } |
| 177 |
167 |
| 178 static void jabber_caps_store_client(gpointer key, gpointer value, gpointer user_data) { |
168 static void jabber_caps_store_client(gpointer key, gpointer value, gpointer user_data) { |
| 179 JabberCapsKey *clientinfo = key; |
169 const JabberCapsTuple *tuple = key; |
| 180 JabberCapsClientInfo *props = value; |
170 const JabberCapsClientInfo *props = value; |
| 181 xmlnode *root = user_data; |
171 xmlnode *root = user_data; |
| 182 xmlnode *client = xmlnode_new_child(root, "client"); |
172 xmlnode *client = xmlnode_new_child(root, "client"); |
| 183 GList *iter; |
173 GList *iter; |
| 184 |
174 |
| 185 xmlnode_set_attrib(client, "node", clientinfo->node); |
175 xmlnode_set_attrib(client, "node", tuple->node); |
| 186 xmlnode_set_attrib(client, "ver", clientinfo->ver); |
176 xmlnode_set_attrib(client, "ver", tuple->ver); |
| 187 if (clientinfo->hash) |
177 if (tuple->hash) |
| 188 xmlnode_set_attrib(client, "hash", clientinfo->hash); |
178 xmlnode_set_attrib(client, "hash", tuple->hash); |
| 189 for(iter = props->identities; iter; iter = g_list_next(iter)) { |
179 for(iter = props->identities; iter; iter = g_list_next(iter)) { |
| 190 JabberIdentity *id = iter->data; |
180 JabberIdentity *id = iter->data; |
| 191 xmlnode *identity = xmlnode_new_child(client, "identity"); |
181 xmlnode *identity = xmlnode_new_child(client, "identity"); |
| 192 xmlnode_set_attrib(identity, "category", id->category); |
182 xmlnode_set_attrib(identity, "category", id->category); |
| 193 xmlnode_set_attrib(identity, "type", id->type); |
183 xmlnode_set_attrib(identity, "type", id->type); |
| 253 |
243 |
| 254 for(client = capsdata->child; client; client = client->next) { |
244 for(client = capsdata->child; client; client = client->next) { |
| 255 if(client->type != XMLNODE_TYPE_TAG) |
245 if(client->type != XMLNODE_TYPE_TAG) |
| 256 continue; |
246 continue; |
| 257 if(!strcmp(client->name, "client")) { |
247 if(!strcmp(client->name, "client")) { |
| 258 JabberCapsKey *key = g_new0(JabberCapsKey, 1); |
|
| 259 JabberCapsClientInfo *value = g_new0(JabberCapsClientInfo, 1); |
248 JabberCapsClientInfo *value = g_new0(JabberCapsClientInfo, 1); |
| |
249 JabberCapsTuple *key = (JabberCapsTuple*)&value->tuple; |
| 260 xmlnode *child; |
250 xmlnode *child; |
| 261 JabberCapsNodeExts *exts = NULL; |
251 JabberCapsNodeExts *exts = NULL; |
| 262 key->node = g_strdup(xmlnode_get_attrib(client,"node")); |
252 key->node = g_strdup(xmlnode_get_attrib(client,"node")); |
| 263 key->ver = g_strdup(xmlnode_get_attrib(client,"ver")); |
253 key->ver = g_strdup(xmlnode_get_attrib(client,"ver")); |
| 264 key->hash = g_strdup(xmlnode_get_attrib(client,"hash")); |
254 key->hash = g_strdup(xmlnode_get_attrib(client,"hash")); |
| 338 } |
328 } |
| 339 |
329 |
| 340 void jabber_caps_init(void) |
330 void jabber_caps_init(void) |
| 341 { |
331 { |
| 342 nodetable = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)jabber_caps_node_exts_unref); |
332 nodetable = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)jabber_caps_node_exts_unref); |
| 343 capstable = g_hash_table_new_full(jabber_caps_hash, jabber_caps_compare, jabber_caps_destroy_key, (GDestroyNotify)jabber_caps_client_info_destroy); |
333 capstable = g_hash_table_new_full(jabber_caps_hash, jabber_caps_compare, NULL, (GDestroyNotify)jabber_caps_client_info_destroy); |
| 344 jabber_caps_load(); |
334 jabber_caps_load(); |
| 345 } |
335 } |
| 346 |
336 |
| 347 void jabber_caps_uninit(void) |
337 void jabber_caps_uninit(void) |
| 348 { |
338 { |
| 427 { |
417 { |
| 428 xmlnode *query = xmlnode_get_child_with_namespace(packet, "query", |
418 xmlnode *query = xmlnode_get_child_with_namespace(packet, "query", |
| 429 "http://jabber.org/protocol/disco#info"); |
419 "http://jabber.org/protocol/disco#info"); |
| 430 jabber_caps_cbplususerdata *userdata = data; |
420 jabber_caps_cbplususerdata *userdata = data; |
| 431 JabberCapsClientInfo *info = NULL, *value; |
421 JabberCapsClientInfo *info = NULL, *value; |
| 432 JabberCapsKey key; |
422 JabberCapsTuple key; |
| 433 |
423 |
| 434 if (!query || type == JABBER_IQ_ERROR) { |
424 if (!query || type == JABBER_IQ_ERROR) { |
| 435 /* Any outstanding exts will be dealt with via ref-counting */ |
425 /* Any outstanding exts will be dealt with via ref-counting */ |
| 436 userdata->cb(NULL, NULL, userdata->cb_data); |
426 userdata->cb(NULL, NULL, userdata->cb_data); |
| 437 cbplususerdata_unref(userdata); |
427 cbplususerdata_unref(userdata); |
| 479 * a new one if we need to */ |
469 * a new one if we need to */ |
| 480 if ((value = g_hash_table_lookup(capstable, &key))) { |
470 if ((value = g_hash_table_lookup(capstable, &key))) { |
| 481 jabber_caps_client_info_destroy(info); |
471 jabber_caps_client_info_destroy(info); |
| 482 info = value; |
472 info = value; |
| 483 } else { |
473 } else { |
| 484 JabberCapsKey *n_key = g_new(JabberCapsKey, 1); |
474 JabberCapsTuple *n_key = (JabberCapsTuple *)&info->tuple; |
| 485 n_key->node = userdata->node; |
475 n_key->node = userdata->node; |
| 486 n_key->ver = userdata->ver; |
476 n_key->ver = userdata->ver; |
| 487 n_key->hash = userdata->hash; |
477 n_key->hash = userdata->hash; |
| 488 userdata->node = userdata->ver = userdata->hash = NULL; |
478 userdata->node = userdata->ver = userdata->hash = NULL; |
| 489 |
479 |
| 551 void jabber_caps_get_info(JabberStream *js, const char *who, const char *node, |
541 void jabber_caps_get_info(JabberStream *js, const char *who, const char *node, |
| 552 const char *ver, const char *hash, const char *ext, |
542 const char *ver, const char *hash, const char *ext, |
| 553 jabber_caps_get_info_cb cb, gpointer user_data) |
543 jabber_caps_get_info_cb cb, gpointer user_data) |
| 554 { |
544 { |
| 555 JabberCapsClientInfo *info; |
545 JabberCapsClientInfo *info; |
| 556 JabberCapsKey key; |
546 JabberCapsTuple key; |
| 557 jabber_caps_cbplususerdata *userdata; |
547 jabber_caps_cbplususerdata *userdata; |
| 558 |
548 |
| 559 if (ext && *ext && hash) |
549 if (ext && *ext && hash) |
| 560 purple_debug_info("jabber", "Ignoring exts in new-style caps from %s\n", |
550 purple_debug_info("jabber", "Ignoring exts in new-style caps from %s\n", |
| 561 who); |
551 who); |