comparison libpurple/protocols/jabber/data.c @ 24058:305fac6af8f9

Updated to use latest spec. in XEP-0231 New namespace. Cache data globally in a running instance based on CID. Set the PNG compression level param when saving a custom smiley from GTKIMHTML.
author Marcus Lundblad <ml@update.uu.se>
date Fri, 05 Sep 2008 21:55:09 +0000
parents 9d83ae2c1a4f
children 7b11072ba907
comparison
equal deleted inserted replaced
24057:8997acd7d143 24058:305fac6af8f9
23 #include "xmlnode.h" 23 #include "xmlnode.h"
24 #include "util.h" 24 #include "util.h"
25 #include "conversation.h" 25 #include "conversation.h"
26 #include "iq.h" 26 #include "iq.h"
27 27
28 /* hash table to store locally supplied data objects, by conversation and 28 static GHashTable *local_data_by_alt = NULL;
29 alt text (smiley shortcut) */ 29 static GHashTable *local_data_by_cid = NULL;
30 static GHashTable *local_datas_by_alt = NULL; 30 static GHashTable *remote_data_by_cid = NULL;
31
32 /* hash table to store locally supplied data objects, by content id */
33 static GHashTable *local_datas_by_cid = NULL;
34
35 /* remote supplied data objects by content id */
36 static GHashTable *remote_datas_by_cid = NULL;
37
38
39 void
40 jabber_data_init(void)
41 {
42 /* setup hash tables for storing data instances here */
43 purple_debug_info("jabber", "Setting up data handling\n");
44
45 local_datas_by_alt = g_hash_table_new(NULL, NULL);
46 local_datas_by_cid = g_hash_table_new(NULL, NULL);
47 remote_datas_by_cid = g_hash_table_new(NULL, NULL);
48 }
49 31
50 JabberData * 32 JabberData *
51 jabber_data_create_from_data(gconstpointer rawdata, gsize size, const char *type, 33 jabber_data_create_from_data(gconstpointer rawdata, gsize size, const char *type,
52 const char *alt) 34 JabberStream *js)
53 { 35 {
54 JabberData *data = g_new0(JabberData, 1); 36 JabberData *data = g_new0(JabberData, 1);
55 gchar *checksum = purple_util_get_image_checksum(rawdata, size); 37 gchar *checksum = purple_util_get_image_checksum(rawdata, size);
56 gchar cid[256]; 38 gchar cid[256];
57 39
58 /* is there some better way to generate a content ID? */ 40 g_snprintf(cid, sizeof(cid), "sha1+%s@bob.xmpp.org", checksum);
59 g_snprintf(cid, sizeof(cid), "%s@%s", checksum, g_get_host_name());
60 g_free(checksum); 41 g_free(checksum);
61 42
62 data->cid = g_strdup(cid); 43 data->cid = g_strdup(cid);
63 data->type = g_strdup(type); 44 data->type = g_strdup(type);
64 data->alt = g_strdup(alt);
65 data->size = size; 45 data->size = size;
66 46
67 data->data = g_memdup(rawdata, size); 47 data->data = g_memdup(rawdata, size);
68 48
69 return data; 49 return data;
89 return NULL; 69 return NULL;
90 } 70 }
91 71
92 data->cid = g_strdup(xmlnode_get_attrib(tag, "cid")); 72 data->cid = g_strdup(xmlnode_get_attrib(tag, "cid"));
93 data->type = g_strdup(xmlnode_get_attrib(tag, "type")); 73 data->type = g_strdup(xmlnode_get_attrib(tag, "type"));
94 data->alt = g_strdup(xmlnode_get_attrib(tag, "alt")); 74
95
96 raw_data = xmlnode_get_data(tag); 75 raw_data = xmlnode_get_data(tag);
97 data->data = purple_base64_decode(raw_data, &size); 76 data->data = purple_base64_decode(raw_data, &size);
98 data->size = size; 77 data->size = size;
99 78
100 g_free(raw_data); 79 g_free(raw_data);
105 84
106 void 85 void
107 jabber_data_delete(JabberData *data) 86 jabber_data_delete(JabberData *data)
108 { 87 {
109 g_free(data->cid); 88 g_free(data->cid);
110 g_free(data->alt);
111 g_free(data->type); 89 g_free(data->type);
112 g_free(data->data); 90 g_free(data->data);
113 g_free(data); 91 g_free(data);
114 } 92 }
115 93
117 jabber_data_get_cid(const JabberData *data) 95 jabber_data_get_cid(const JabberData *data)
118 { 96 {
119 return data->cid; 97 return data->cid;
120 } 98 }
121 99
122 const char *
123 jabber_data_get_alt(const JabberData *data)
124 {
125 return data->alt;
126 }
127 100
128 const char * 101 const char *
129 jabber_data_get_type(const JabberData *data) 102 jabber_data_get_type(const JabberData *data)
130 { 103 {
131 return data->type; 104 return data->type;
148 { 121 {
149 xmlnode *tag = xmlnode_new("data"); 122 xmlnode *tag = xmlnode_new("data");
150 char *base64data = purple_base64_encode(data->data, data->size); 123 char *base64data = purple_base64_encode(data->data, data->size);
151 124
152 xmlnode_set_namespace(tag, XEP_0231_NAMESPACE); 125 xmlnode_set_namespace(tag, XEP_0231_NAMESPACE);
153 xmlnode_set_attrib(tag, "alt", data->alt);
154 xmlnode_set_attrib(tag, "cid", data->cid); 126 xmlnode_set_attrib(tag, "cid", data->cid);
155 xmlnode_set_attrib(tag, "type", data->type); 127 xmlnode_set_attrib(tag, "type", data->type);
156 128
157 xmlnode_insert_data(tag, base64data, -1); 129 xmlnode_insert_data(tag, base64data, -1);
158 130
160 132
161 return tag; 133 return tag;
162 } 134 }
163 135
164 xmlnode * 136 xmlnode *
165 jabber_data_get_xhtml_im(const JabberData *data) 137 jabber_data_get_xhtml_im(const JabberData *data, const gchar *alt)
166 { 138 {
167 xmlnode *img = xmlnode_new("img"); 139 xmlnode *img = xmlnode_new("img");
168 char src[128]; 140 char src[128];
169 141
170 xmlnode_set_attrib(img, "alt", data->alt); 142 xmlnode_set_attrib(img, "alt", alt);
171 g_snprintf(src, sizeof(src), "cid:%s", data->cid); 143 g_snprintf(src, sizeof(src), "cid:%s", data->cid);
172 xmlnode_set_attrib(img, "src", src); 144 xmlnode_set_attrib(img, "src", src);
173 145
174 return img; 146 return img;
175 } 147 }
184 156
185 return tag; 157 return tag;
186 } 158 }
187 159
188 const JabberData * 160 const JabberData *
189 jabber_data_find_local_by_alt(const PurpleConversation *conv, const char *alt) 161 jabber_data_find_local_by_alt(const gchar *alt)
190 { 162 {
191 GHashTable *local_datas = g_hash_table_lookup(local_datas_by_alt, conv); 163 return g_hash_table_lookup(local_data_by_alt, alt);
192 164 }
193 if (local_datas) {
194 return g_hash_table_lookup(local_datas, alt);
195 } else {
196 return NULL;
197 }
198 }
199
200 165
201 const JabberData * 166 const JabberData *
202 jabber_data_find_local_by_cid(const PurpleConversation *conv, const char *cid) 167 jabber_data_find_local_by_cid(const gchar *cid)
203 { 168 {
204 GHashTable *local_datas = g_hash_table_lookup(local_datas_by_cid, conv); 169 return g_hash_table_lookup(local_data_by_cid, cid);
205
206 if (local_datas) {
207 return g_hash_table_lookup(local_datas, cid);
208 } else {
209 return NULL;
210 }
211 } 170 }
212 171
213 const JabberData * 172 const JabberData *
214 jabber_data_find_remote_by_cid(const PurpleConversation *conv, const char *cid) 173 jabber_data_find_remote_by_cid(const gchar *cid)
215 { 174 {
216 GHashTable *remote_datas = g_hash_table_lookup(remote_datas_by_cid, conv); 175 return g_hash_table_lookup(remote_data_by_cid, cid);
217 176 }
218 if (remote_datas) { 177
219 return g_hash_table_lookup(remote_datas, cid); 178 void
220 } else { 179 jabber_data_associate_local(JabberData *data, const gchar *alt)
221 return NULL; 180 {
222 } 181 g_hash_table_insert(local_data_by_alt, g_strdup(alt), data);
223 } 182 g_hash_table_insert(local_data_by_cid, g_strdup(jabber_data_get_cid(data)),
224 183 data);
225 void 184 }
226 jabber_data_associate_local_with_conv(JabberData *data, PurpleConversation *conv) 185
227 { 186 void
228 GHashTable *datas_by_alt = g_hash_table_lookup(local_datas_by_alt, conv); 187 jabber_data_associate_remote(JabberData *data)
229 GHashTable *datas_by_cid = g_hash_table_lookup(local_datas_by_cid, conv); 188 {
230 189 g_hash_table_insert(remote_data_by_cid, g_strdup(jabber_data_get_cid(data)),
231 if (!datas_by_alt) { 190 data);
232 datas_by_alt = g_hash_table_new(g_str_hash, g_str_equal);
233 g_hash_table_insert(local_datas_by_alt, conv, datas_by_alt);
234 }
235
236 if (!datas_by_cid) {
237 datas_by_cid = g_hash_table_new(g_str_hash, g_str_equal);
238 g_hash_table_insert(local_datas_by_cid, conv, datas_by_cid);
239 }
240
241 g_hash_table_insert(datas_by_alt, g_strdup(jabber_data_get_alt(data)), data);
242 g_hash_table_insert(datas_by_cid, g_strdup(jabber_data_get_cid(data)), data);
243 }
244
245 void
246 jabber_data_associate_remote_with_conv(JabberData *data, PurpleConversation *conv)
247 {
248 GHashTable *datas_by_cid = g_hash_table_lookup(remote_datas_by_cid, conv);
249
250 if (!datas_by_cid) {
251 datas_by_cid = g_hash_table_new(g_str_hash, g_str_equal);
252 g_hash_table_insert(remote_datas_by_cid, conv, datas_by_cid);
253 }
254
255 g_hash_table_insert(datas_by_cid, g_strdup(jabber_data_get_cid(data)), data);
256 }
257
258 static void
259 jabber_data_delete_from_hash_table(gpointer key, gpointer value,
260 gpointer user_data)
261 {
262 JabberData *data = (JabberData *) value;
263 jabber_data_delete(data);
264 g_free(key);
265 }
266
267 void
268 jabber_data_delete_associated_with_conv(PurpleConversation *conv)
269 {
270 GHashTable *local_datas = g_hash_table_lookup(local_datas_by_cid, conv);
271 GHashTable *remote_datas = g_hash_table_lookup(remote_datas_by_cid, conv);
272 GHashTable *local_datas_alt = g_hash_table_lookup(local_datas_by_alt, conv);
273
274 if (local_datas) {
275 g_hash_table_foreach(local_datas, jabber_data_delete_from_hash_table,
276 NULL);
277 g_hash_table_destroy(local_datas);
278 g_hash_table_remove(local_datas_by_cid, conv);
279 }
280 if (remote_datas) {
281 g_hash_table_foreach(remote_datas, jabber_data_delete_from_hash_table,
282 NULL);
283 g_hash_table_destroy(remote_datas);
284 g_hash_table_remove(remote_datas_by_cid, conv);
285 }
286 if (local_datas_alt) {
287 g_hash_table_destroy(local_datas_alt);
288 g_hash_table_remove(local_datas_by_alt, conv);
289 }
290 } 191 }
291 192
292 void 193 void
293 jabber_data_parse(JabberStream *js, xmlnode *packet) 194 jabber_data_parse(JabberStream *js, xmlnode *packet)
294 { 195 {
295 JabberIq *result = NULL; 196 JabberIq *result = NULL;
296 const char *who = xmlnode_get_attrib(packet, "from"); 197 const char *who = xmlnode_get_attrib(packet, "from");
297 const PurpleConnection *gc = js->gc;
298 const PurpleAccount *account = purple_connection_get_account(gc);
299 const PurpleConversation *conv =
300 purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, who, account);
301 xmlnode *data_node = xmlnode_get_child(packet, "data"); 198 xmlnode *data_node = xmlnode_get_child(packet, "data");
302 const JabberData *data = 199 const JabberData *data =
303 jabber_data_find_local_by_cid(conv, xmlnode_get_attrib(data_node, "cid")); 200 jabber_data_find_local_by_cid(xmlnode_get_attrib(data_node, "cid"));
304 201
305 if (!conv || !data) { 202 if (!data) {
306 xmlnode *item_not_found = xmlnode_new("item-not-found"); 203 xmlnode *item_not_found = xmlnode_new("item-not-found");
307 204
308 result = jabber_iq_new(js, JABBER_IQ_ERROR); 205 result = jabber_iq_new(js, JABBER_IQ_ERROR);
309 xmlnode_set_attrib(result->node, "to", who); 206 xmlnode_set_attrib(result->node, "to", who);
310 xmlnode_set_attrib(result->node, "id", xmlnode_get_attrib(packet, "id")); 207 xmlnode_set_attrib(result->node, "id", xmlnode_get_attrib(packet, "id"));
316 xmlnode_insert_child(result->node, 213 xmlnode_insert_child(result->node,
317 jabber_data_get_xml_definition(data)); 214 jabber_data_get_xml_definition(data));
318 } 215 }
319 jabber_iq_send(result); 216 jabber_iq_send(result);
320 } 217 }
218
219 void
220 jabber_data_init(void)
221 {
222 purple_debug_info("jabber", "creating hash tables for data objects\n");
223 local_data_by_alt = g_hash_table_new_full(g_str_hash, g_str_equal,
224 g_free, NULL);
225 local_data_by_cid = g_hash_table_new_full(g_str_hash, g_str_equal,
226 g_free, jabber_data_delete);
227 remote_data_by_cid = g_hash_table_new_full(g_str_hash, g_str_equal,
228 g_free, jabber_data_delete);
229 }
230
231 void
232 jabber_data_uninit(void)
233 {
234 purple_debug_info("jabber", "destroying hash tables for data objects\n");
235 g_hash_table_destroy(local_data_by_alt);
236 g_hash_table_destroy(local_data_by_cid);
237 g_hash_table_destroy(remote_data_by_cid);
238 }