Mercurial > pidgin
comparison libpurple/buddyicon.c @ 16375:391a79778f89
Rework the buddy icon subsystem to use the imgstore subsystem, and modify the
imgstore subsystem to not require IDs for everything.
author | Richard Laager <rlaager@wiktel.com> |
---|---|
date | Tue, 24 Apr 2007 03:57:07 +0000 |
parents | c9b4ff420140 |
children | dd47fa8ba3e4 |
comparison
equal
deleted
inserted
replaced
16374:2a19bbc743ed | 16375:391a79778f89 |
---|---|
26 #include "buddyicon.h" | 26 #include "buddyicon.h" |
27 #include "cipher.h" | 27 #include "cipher.h" |
28 #include "conversation.h" | 28 #include "conversation.h" |
29 #include "dbus-maybe.h" | 29 #include "dbus-maybe.h" |
30 #include "debug.h" | 30 #include "debug.h" |
31 #include "imgstore.h" | |
31 #include "util.h" | 32 #include "util.h" |
32 | 33 |
33 typedef struct _PurpleBuddyIconData PurpleBuddyIconData; | 34 typedef struct _PurpleBuddyIconData PurpleBuddyIconData; |
34 | 35 |
36 /* NOTE: Instances of this struct are allocated without zeroing the memory, so | |
37 * NOTE: be sure to update purple_buddy_icon_new() if you add members. */ | |
35 struct _PurpleBuddyIcon | 38 struct _PurpleBuddyIcon |
36 { | 39 { |
37 PurpleAccount *account; /**< The account the user is on. */ | 40 PurpleAccount *account; /**< The account the user is on. */ |
38 char *username; /**< The username the icon belongs to. */ | 41 char *username; /**< The username the icon belongs to. */ |
39 PurpleBuddyIconData *protocol_icon; /**< The icon data. */ | 42 PurpleStoredImage *img; /**< The id of the stored image with the |
40 PurpleBuddyIconData *custom_icon; /**< The data for a user-set custom icon. */ | 43 the icon data. */ |
41 int ref_count; /**< The buddy icon reference count. */ | 44 int ref_count; /**< The buddy icon reference count. */ |
42 }; | |
43 | |
44 struct _PurpleBuddyIconData | |
45 { | |
46 guchar *image_data; /**< The buddy icon data. */ | |
47 size_t len; /**< The length of the buddy icon data. */ | |
48 char *filename; /**< The filename of the cache file. */ | |
49 int ref_count; /**< The buddy icon reference count. */ | |
50 }; | 45 }; |
51 | 46 |
52 static GHashTable *account_cache = NULL; | 47 static GHashTable *account_cache = NULL; |
53 static GHashTable *icon_data_cache = NULL; | 48 static GHashTable *icon_data_cache = NULL; |
54 static GHashTable *icon_file_cache = NULL; | 49 static GHashTable *icon_file_cache = NULL; |
50 static GHashTable *custom_icon_cache = NULL; | |
55 static char *cache_dir = NULL; | 51 static char *cache_dir = NULL; |
56 static gboolean icon_caching = TRUE; | 52 static gboolean icon_caching = TRUE; |
57 | 53 |
58 /* For ~/.gaim to ~/.purple migration. */ | 54 /* For ~/.gaim to ~/.purple migration. */ |
59 static char *old_icons_dir = NULL; | 55 static char *old_icons_dir = NULL; |
88 else | 84 else |
89 { | 85 { |
90 g_hash_table_insert(icon_file_cache, g_strdup(filename), | 86 g_hash_table_insert(icon_file_cache, g_strdup(filename), |
91 GINT_TO_POINTER(refs - 1)); | 87 GINT_TO_POINTER(refs - 1)); |
92 } | 88 } |
93 } | |
94 | |
95 static const char * | |
96 get_icon_type(guchar *icon_data, size_t icon_len) | |
97 { | |
98 g_return_val_if_fail(icon_data != NULL, NULL); | |
99 g_return_val_if_fail(icon_len > 0, NULL); | |
100 | |
101 if (icon_len >= 4) | |
102 { | |
103 if (!strncmp((char *)icon_data, "BM", 2)) | |
104 return "bmp"; | |
105 else if (!strncmp((char *)icon_data, "GIF8", 4)) | |
106 return "gif"; | |
107 else if (!strncmp((char *)icon_data, "\xff\xd8\xff\xe0", 4)) | |
108 return "jpg"; | |
109 else if (!strncmp((char *)icon_data, "\x89PNG", 4)) | |
110 return "png"; | |
111 } | |
112 | |
113 return "icon"; | |
114 } | |
115 | |
116 static const char * | |
117 purple_buddy_icon_data_get_type(PurpleBuddyIconData *data) | |
118 { | |
119 return get_icon_type(data->image_data, data->len); | |
120 } | 89 } |
121 | 90 |
122 static char * | 91 static char * |
123 purple_buddy_icon_data_calculate_filename(guchar *icon_data, size_t icon_len) | 92 purple_buddy_icon_data_calculate_filename(guchar *icon_data, size_t icon_len) |
124 { | 93 { |
141 } | 110 } |
142 purple_cipher_context_destroy(context); | 111 purple_cipher_context_destroy(context); |
143 | 112 |
144 /* Return the filename */ | 113 /* Return the filename */ |
145 return g_strdup_printf("%s.%s", digest, | 114 return g_strdup_printf("%s.%s", digest, |
146 get_icon_type(icon_data, icon_len)); | 115 purple_util_get_image_extension(icon_data, icon_len)); |
147 } | 116 } |
148 | 117 |
149 static void | 118 static void |
150 purple_buddy_icon_data_cache(PurpleBuddyIconData *data) | 119 purple_buddy_icon_data_cache(PurpleStoredImage *img) |
151 { | 120 { |
152 const char *dirname; | 121 const char *dirname; |
153 char *path; | 122 char *path; |
154 FILE *file = NULL; | 123 FILE *file = NULL; |
155 | 124 |
125 g_return_if_fail(img != NULL); | |
126 | |
156 if (!purple_buddy_icons_is_caching()) | 127 if (!purple_buddy_icons_is_caching()) |
157 return; | 128 return; |
158 | 129 |
159 dirname = purple_buddy_icons_get_cache_dir(); | 130 dirname = purple_buddy_icons_get_cache_dir(); |
160 path = g_build_filename(dirname, data->filename, NULL); | 131 path = g_build_filename(dirname, purple_imgstore_get_filename(img), NULL); |
161 | 132 |
162 if (!g_file_test(dirname, G_FILE_TEST_IS_DIR)) | 133 if (!g_file_test(dirname, G_FILE_TEST_IS_DIR)) |
163 { | 134 { |
164 purple_debug_info("buddyicon", "Creating icon cache directory.\n"); | 135 purple_debug_info("buddyicon", "Creating icon cache directory.\n"); |
165 | 136 |
171 } | 142 } |
172 } | 143 } |
173 | 144 |
174 if ((file = g_fopen(path, "wb")) != NULL) | 145 if ((file = g_fopen(path, "wb")) != NULL) |
175 { | 146 { |
176 if (!fwrite(data->image_data, data->len, 1, file)) | 147 if (!fwrite(purple_imgstore_get_data(img), purple_imgstore_get_size(img), 1, file)) |
177 { | 148 { |
178 purple_debug_error("buddyicon", "Error writing %s: %s\n", | 149 purple_debug_error("buddyicon", "Error writing %s: %s\n", |
179 path, strerror(errno)); | 150 path, strerror(errno)); |
180 } | 151 } |
181 else | 152 else |
192 } | 163 } |
193 g_free(path); | 164 g_free(path); |
194 } | 165 } |
195 | 166 |
196 static void | 167 static void |
197 purple_buddy_icon_data_uncache(PurpleBuddyIconData *data) | 168 purple_buddy_icon_data_uncache_file(const char *filename) |
198 { | 169 { |
199 const char *dirname; | 170 const char *dirname; |
200 char *path; | 171 char *path; |
201 | 172 |
202 g_return_if_fail(data != NULL); | 173 g_return_if_fail(filename != NULL); |
203 | 174 |
204 /* It's possible that there are other references to this icon | 175 /* It's possible that there are other references to this icon |
205 * cache file that are not currently loaded into memory. */ | 176 * cache file that are not currently loaded into memory. */ |
206 if (g_hash_table_lookup(icon_file_cache, data->filename)) | 177 if (g_hash_table_lookup(icon_file_cache, filename)) |
207 return; | 178 return; |
208 | 179 |
209 dirname = purple_buddy_icons_get_cache_dir(); | 180 dirname = purple_buddy_icons_get_cache_dir(); |
210 path = g_build_filename(dirname, data->filename, NULL); | 181 path = g_build_filename(dirname, filename, NULL); |
211 | 182 |
212 if (g_file_test(path, G_FILE_TEST_EXISTS)) | 183 if (g_file_test(path, G_FILE_TEST_EXISTS)) |
213 { | 184 { |
214 if (g_unlink(path)) | 185 if (g_unlink(path)) |
215 { | 186 { |
221 } | 192 } |
222 | 193 |
223 g_free(path); | 194 g_free(path); |
224 } | 195 } |
225 | 196 |
226 static PurpleBuddyIconData * | 197 static void |
227 purple_buddy_icon_data_ref(PurpleBuddyIconData *data) | 198 image_deleting_cb(PurpleStoredImage *img, gpointer data) |
228 { | 199 { |
229 g_return_val_if_fail(data != NULL, NULL); | 200 const char *filename = purple_imgstore_get_filename(img); |
230 | 201 |
231 data->ref_count++; | 202 if (img == g_hash_table_lookup(icon_data_cache, filename)) |
232 | 203 { |
233 return data; | 204 purple_buddy_icon_data_uncache_file(filename); |
234 } | 205 g_hash_table_remove(icon_data_cache, filename); |
235 | 206 } |
236 static PurpleBuddyIconData * | 207 } |
237 purple_buddy_icon_data_unref(PurpleBuddyIconData *data) | 208 |
238 { | 209 static PurpleStoredImage * |
239 if (data == NULL) | 210 purple_buddy_icon_data_new(guchar *icon_data, size_t icon_len, const char *filename) |
240 return NULL; | 211 { |
241 | 212 char *file; |
242 g_return_val_if_fail(data->ref_count > 0, NULL); | 213 PurpleStoredImage *img; |
243 | |
244 data->ref_count--; | |
245 | |
246 if (data->ref_count == 0) | |
247 { | |
248 g_hash_table_remove(icon_data_cache, data->filename); | |
249 | |
250 purple_buddy_icon_data_uncache(data); | |
251 | |
252 g_free(data->image_data); | |
253 g_free(data->filename); | |
254 g_free(data); | |
255 | |
256 return NULL; | |
257 } | |
258 | |
259 return data; | |
260 } | |
261 | |
262 static PurpleBuddyIconData * | |
263 purple_buddy_icon_data_new(guchar *icon_data, size_t icon_len) | |
264 { | |
265 PurpleBuddyIconData *data; | |
266 char *filename; | |
267 | 214 |
268 g_return_val_if_fail(icon_data != NULL, NULL); | 215 g_return_val_if_fail(icon_data != NULL, NULL); |
269 g_return_val_if_fail(icon_len > 0, NULL); | 216 g_return_val_if_fail(icon_len > 0, NULL); |
270 | 217 |
271 filename = purple_buddy_icon_data_calculate_filename(icon_data, icon_len); | |
272 if (filename == NULL) | 218 if (filename == NULL) |
273 return NULL; | 219 { |
274 | 220 file = purple_buddy_icon_data_calculate_filename(icon_data, icon_len); |
275 if ((data = g_hash_table_lookup(icon_data_cache, filename))) | 221 if (file == NULL) |
276 { | 222 return NULL; |
277 g_free(filename); | 223 } |
278 return purple_buddy_icon_data_ref(data); | 224 else |
279 } | 225 file = g_strdup(filename); |
280 | 226 |
281 data = g_new0(PurpleBuddyIconData, 1); | 227 if ((img = g_hash_table_lookup(icon_data_cache, file))) |
282 data->image_data = g_memdup(icon_data, icon_len); | 228 { |
283 data->len = icon_len; | 229 g_free(file); |
284 data->filename = filename; | 230 return purple_imgstore_ref(img); |
285 | 231 } |
286 purple_buddy_icon_data_cache(data); | 232 |
287 | 233 img = purple_imgstore_add(icon_data, icon_len, file); |
288 return data; | 234 |
235 /* This will take ownership of file and g_free it either now or later. */ | |
236 g_hash_table_insert(icon_data_cache, file, img); | |
237 | |
238 purple_buddy_icon_data_cache(img); | |
239 | |
240 return img; | |
289 } | 241 } |
290 | 242 |
291 static PurpleBuddyIcon * | 243 static PurpleBuddyIcon * |
292 purple_buddy_icon_create(PurpleAccount *account, const char *username) | 244 purple_buddy_icon_create(PurpleAccount *account, const char *username) |
293 { | 245 { |
294 PurpleBuddyIcon *icon; | 246 PurpleBuddyIcon *icon; |
295 GHashTable *icon_cache; | 247 GHashTable *icon_cache; |
296 | 248 |
297 icon = g_new0(PurpleBuddyIcon, 1); | 249 /* This does not zero. See purple_buddy_icon_new() for |
250 * information on which function allocates which member. */ | |
251 icon = g_slice_new(PurpleBuddyIcon); | |
298 PURPLE_DBUS_REGISTER_POINTER(icon, PurpleBuddyIcon); | 252 PURPLE_DBUS_REGISTER_POINTER(icon, PurpleBuddyIcon); |
299 | 253 |
300 icon->account = account; | 254 icon->account = account; |
301 icon->username = g_strdup(username); | 255 icon->username = g_strdup(username); |
302 | 256 |
314 return icon; | 268 return icon; |
315 } | 269 } |
316 | 270 |
317 PurpleBuddyIcon * | 271 PurpleBuddyIcon * |
318 purple_buddy_icon_new(PurpleAccount *account, const char *username, | 272 purple_buddy_icon_new(PurpleAccount *account, const char *username, |
319 void *protocol_icon_data, size_t protocol_icon_len, | 273 void *icon_data, size_t icon_len) |
320 void *custom_icon_data, size_t custom_icon_len) | |
321 { | 274 { |
322 PurpleBuddyIcon *icon; | 275 PurpleBuddyIcon *icon; |
323 | 276 |
324 g_return_val_if_fail(account != NULL, NULL); | 277 g_return_val_if_fail(account != NULL, NULL); |
325 g_return_val_if_fail(username != NULL, NULL); | 278 g_return_val_if_fail(username != NULL, NULL); |
326 g_return_val_if_fail((protocol_icon_data != NULL && protocol_icon_len > 0) || | 279 g_return_val_if_fail(icon_data != NULL, NULL); |
327 (custom_icon_data != NULL && custom_icon_len > 0), NULL); | 280 g_return_val_if_fail(icon_len > 0, NULL); |
328 | 281 |
329 icon = purple_buddy_icons_find(account, username); | 282 icon = purple_buddy_icons_find(account, username); |
330 | 283 |
284 /* purple_buddy_icon_create() sets account & username */ | |
331 if (icon == NULL) | 285 if (icon == NULL) |
332 icon = purple_buddy_icon_create(account, username); | 286 icon = purple_buddy_icon_create(account, username); |
333 | 287 |
334 /* Take a reference for the caller of this function. */ | 288 /* Take a reference for the caller of this function. */ |
335 purple_buddy_icon_ref(icon); | 289 icon->ref_count = 1; |
336 | 290 |
337 if (protocol_icon_data != NULL && protocol_icon_len > 0) | 291 /* purple_buddy_icon_set_data() sets img */ |
338 purple_buddy_icon_set_protocol_data(icon, protocol_icon_data, protocol_icon_len); | 292 purple_buddy_icon_set_data(icon, icon_data, icon_len); |
339 | |
340 if (custom_icon_data != NULL && custom_icon_len > 0) | |
341 purple_buddy_icon_set_custom_data(icon, custom_icon_data, custom_icon_len); | |
342 | 293 |
343 return icon; | 294 return icon; |
344 } | 295 } |
345 | 296 |
346 PurpleBuddyIcon * | 297 PurpleBuddyIcon * |
369 | 320 |
370 if (icon_cache != NULL) | 321 if (icon_cache != NULL) |
371 g_hash_table_remove(icon_cache, purple_buddy_icon_get_username(icon)); | 322 g_hash_table_remove(icon_cache, purple_buddy_icon_get_username(icon)); |
372 | 323 |
373 g_free(icon->username); | 324 g_free(icon->username); |
374 purple_buddy_icon_data_unref(icon->protocol_icon); | 325 purple_imgstore_unref(icon->img); |
375 purple_buddy_icon_data_unref(icon->custom_icon); | |
376 | 326 |
377 PURPLE_DBUS_UNREGISTER_POINTER(icon); | 327 PURPLE_DBUS_UNREGISTER_POINTER(icon); |
378 g_free(icon); | 328 g_slice_free(PurpleBuddyIcon, icon); |
379 | 329 |
380 return NULL; | 330 return NULL; |
381 } | 331 } |
382 | 332 |
383 return icon; | 333 return icon; |
395 g_return_if_fail(icon != NULL); | 345 g_return_if_fail(icon != NULL); |
396 | 346 |
397 account = purple_buddy_icon_get_account(icon); | 347 account = purple_buddy_icon_get_account(icon); |
398 username = purple_buddy_icon_get_username(icon); | 348 username = purple_buddy_icon_get_username(icon); |
399 | 349 |
400 /* If neither type of data exists, then call the functions below with | 350 /* If no data exists, then call the functions below with NULL to |
401 * NULL to unset the icon. They will then unref the icon and it | 351 * unset the icon. They will then unref the icon and it should be |
402 * should be destroyed. The only way it wouldn't be destroyed is if | 352 * destroyed. The only way it wouldn't be destroyed is if someone |
403 * someone else is holding a reference to it, in which case they can | 353 * else is holding a reference to it, in which case they can kill |
404 * kill the icon when they realize it has no data any more. */ | 354 * the icon when they realize it has no data. */ |
405 icon_to_set = (icon->protocol_icon || icon->custom_icon) ? icon : NULL; | 355 icon_to_set = icon->img ? icon : NULL; |
406 | 356 |
407 for (list = sl = purple_find_buddies(account, username); | 357 for (list = sl = purple_find_buddies(account, username); |
408 sl != NULL; | 358 sl != NULL; |
409 sl = sl->next) | 359 sl = sl->next) |
410 { | 360 { |
411 PurpleBuddy *buddy = (PurpleBuddy *)sl->data; | 361 PurpleBuddy *buddy = (PurpleBuddy *)sl->data; |
412 const char *old_icon; | 362 char *old_icon; |
413 | 363 |
414 purple_buddy_set_icon(buddy, icon_to_set); | 364 purple_buddy_set_icon(buddy, icon_to_set); |
415 | 365 |
416 | 366 |
417 old_icon = purple_blist_node_get_string((PurpleBlistNode *)buddy, | 367 old_icon = g_strdup(purple_blist_node_get_string((PurpleBlistNode *)buddy, |
418 "buddy_icon"); | 368 "buddy_icon")); |
419 if (icon->protocol_icon) | 369 if (icon->img) |
420 { | 370 { |
421 old_icon = purple_blist_node_get_string((PurpleBlistNode *)buddy, | 371 const char *filename = purple_imgstore_get_filename(icon->img); |
422 "buddy_icon"); | |
423 purple_blist_node_set_string((PurpleBlistNode *)buddy, | 372 purple_blist_node_set_string((PurpleBlistNode *)buddy, |
424 "buddy_icon", | 373 "buddy_icon", |
425 icon->protocol_icon->filename); | 374 filename); |
426 ref_filename(icon->protocol_icon->filename); | 375 ref_filename(filename); |
427 } | 376 } |
428 else | 377 else |
429 { | 378 { |
430 purple_blist_node_remove_setting((PurpleBlistNode *)buddy, "buddy_icon"); | 379 purple_blist_node_remove_setting((PurpleBlistNode *)buddy, "buddy_icon"); |
431 } | 380 } |
432 unref_filename(old_icon); | 381 unref_filename(old_icon); |
433 | 382 g_free(old_icon); |
434 | |
435 old_icon = purple_blist_node_get_string((PurpleBlistNode *)buddy, | |
436 "custom_buddy_icon"); | |
437 if (icon->custom_icon) | |
438 { | |
439 old_icon = purple_blist_node_get_string((PurpleBlistNode *)buddy, | |
440 "custom_buddy_icon"); | |
441 purple_blist_node_set_string((PurpleBlistNode *)buddy, | |
442 "custom_buddy_icon", | |
443 icon->custom_icon->filename); | |
444 ref_filename(icon->custom_icon->filename); | |
445 } | |
446 else | |
447 { | |
448 purple_blist_node_remove_setting((PurpleBlistNode *)buddy, | |
449 "custom_buddy_icon"); | |
450 } | |
451 unref_filename(old_icon); | |
452 } | 383 } |
453 | 384 |
454 g_slist_free(list); | 385 g_slist_free(list); |
455 | 386 |
456 conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, username, account); | 387 conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, username, account); |
458 if (conv != NULL) | 389 if (conv != NULL) |
459 purple_conv_im_set_icon(PURPLE_CONV_IM(conv), icon_to_set); | 390 purple_conv_im_set_icon(PURPLE_CONV_IM(conv), icon_to_set); |
460 } | 391 } |
461 | 392 |
462 void | 393 void |
463 purple_buddy_icon_set_custom_data(PurpleBuddyIcon *icon, guchar *data, size_t len) | 394 purple_buddy_icon_set_data(PurpleBuddyIcon *icon, guchar *data, size_t len) |
464 { | 395 { |
465 PurpleBuddyIconData *old_data; | 396 PurpleStoredImage *old_img; |
466 | 397 |
467 g_return_if_fail(icon != NULL); | 398 g_return_if_fail(icon != NULL); |
468 | 399 |
469 old_data = icon->custom_icon; | 400 old_img = icon->img; |
470 icon->custom_icon = NULL; | 401 icon->img = NULL; |
471 | 402 |
472 if (data != NULL && len > 0) | 403 if (data != NULL && len > 0) |
473 icon->custom_icon = purple_buddy_icon_data_new(data, len); | 404 icon->img = purple_buddy_icon_data_new(data, len, NULL); |
474 | 405 |
475 purple_buddy_icon_update(icon); | 406 purple_buddy_icon_update(icon); |
476 | 407 |
477 purple_buddy_icon_data_unref(icon->custom_icon); | 408 purple_imgstore_unref(old_img); |
478 } | |
479 | |
480 void | |
481 purple_buddy_icon_set_protocol_data(PurpleBuddyIcon *icon, guchar *data, size_t len) | |
482 { | |
483 PurpleBuddyIconData *old_data; | |
484 | |
485 g_return_if_fail(icon != NULL); | |
486 | |
487 old_data = icon->protocol_icon; | |
488 icon->protocol_icon = NULL; | |
489 | |
490 if (data != NULL && len > 0) | |
491 icon->protocol_icon = purple_buddy_icon_data_new(data, len); | |
492 | |
493 purple_buddy_icon_update(icon); | |
494 | |
495 purple_buddy_icon_data_unref(old_data); | |
496 } | 409 } |
497 | 410 |
498 PurpleAccount * | 411 PurpleAccount * |
499 purple_buddy_icon_get_account(const PurpleBuddyIcon *icon) | 412 purple_buddy_icon_get_account(const PurpleBuddyIcon *icon) |
500 { | 413 { |
509 g_return_val_if_fail(icon != NULL, NULL); | 422 g_return_val_if_fail(icon != NULL, NULL); |
510 | 423 |
511 return icon->username; | 424 return icon->username; |
512 } | 425 } |
513 | 426 |
514 const guchar * | 427 gconstpointer |
515 purple_buddy_icon_get_data(const PurpleBuddyIcon *icon, size_t *len) | 428 purple_buddy_icon_get_data(const PurpleBuddyIcon *icon, size_t *len) |
516 { | 429 { |
517 g_return_val_if_fail(icon != NULL, NULL); | 430 g_return_val_if_fail(icon != NULL, NULL); |
518 | 431 |
519 if (icon->custom_icon) | 432 if (icon->img) |
520 { | 433 { |
521 if (len != NULL) | 434 if (len != NULL) |
522 *len = icon->custom_icon->len; | 435 *len = purple_imgstore_get_size(icon->img); |
523 | 436 |
524 return icon->custom_icon->image_data; | 437 return purple_imgstore_get_data(icon->img); |
525 } | |
526 | |
527 if (icon->protocol_icon) | |
528 { | |
529 if (len != NULL) | |
530 *len = icon->protocol_icon->len; | |
531 | |
532 return icon->protocol_icon->image_data; | |
533 } | 438 } |
534 | 439 |
535 return NULL; | 440 return NULL; |
536 } | 441 } |
537 | 442 |
538 const char * | 443 const char * |
539 purple_buddy_icon_get_type(const PurpleBuddyIcon *icon) | 444 purple_buddy_icon_get_extension(const PurpleBuddyIcon *icon) |
540 { | 445 { |
541 if (icon->custom_icon != NULL) | 446 if (icon->img != NULL) |
542 return purple_buddy_icon_data_get_type(icon->custom_icon); | 447 return purple_imgstore_get_extension(icon->img); |
543 | |
544 if (icon->protocol_icon != NULL) | |
545 return purple_buddy_icon_data_get_type(icon->protocol_icon); | |
546 | 448 |
547 return NULL; | 449 return NULL; |
548 } | 450 } |
549 | 451 |
550 void | 452 void |
559 PurpleBuddyIcon *icon; | 461 PurpleBuddyIcon *icon; |
560 | 462 |
561 icon = purple_buddy_icons_find(account, username); | 463 icon = purple_buddy_icons_find(account, username); |
562 | 464 |
563 if (icon != NULL) | 465 if (icon != NULL) |
564 purple_buddy_icon_set_protocol_data(icon, icon_data, icon_len); | 466 purple_buddy_icon_set_data(icon, icon_data, icon_len); |
565 } | 467 } |
566 else | 468 else |
567 { | 469 { |
568 PurpleBuddyIcon *icon = purple_buddy_icon_new(account, username, icon_data, icon_len, NULL, 0); | 470 PurpleBuddyIcon *icon = purple_buddy_icon_new(account, username, icon_data, icon_len); |
569 purple_buddy_icon_unref(icon); | 471 purple_buddy_icon_unref(icon); |
570 } | 472 } |
571 } | 473 } |
572 | 474 |
573 static gboolean | 475 static gboolean |
615 | 517 |
616 if ((icon_cache == NULL) || ((icon = g_hash_table_lookup(icon_cache, username)) == NULL)) | 518 if ((icon_cache == NULL) || ((icon = g_hash_table_lookup(icon_cache, username)) == NULL)) |
617 { | 519 { |
618 PurpleBuddy *b = purple_find_buddy(account, username); | 520 PurpleBuddy *b = purple_find_buddy(account, username); |
619 const char *protocol_icon_file; | 521 const char *protocol_icon_file; |
620 const char *custom_icon_file; | |
621 const char *dirname; | 522 const char *dirname; |
622 gboolean caching; | 523 gboolean caching; |
623 guchar *data; | 524 guchar *data; |
624 size_t len; | 525 size_t len; |
625 | 526 |
626 if (!b) | 527 if (!b) |
627 return NULL; | 528 return NULL; |
628 | 529 |
629 protocol_icon_file = purple_blist_node_get_string((PurpleBlistNode*)b, "buddy_icon"); | 530 protocol_icon_file = purple_blist_node_get_string((PurpleBlistNode*)b, "buddy_icon"); |
630 custom_icon_file = purple_blist_node_get_string((PurpleBlistNode*)b, "custom_buddy_icon"); | 531 |
631 | 532 if (protocol_icon_file == NULL) |
632 if (protocol_icon_file == NULL && custom_icon_file == NULL) | |
633 return NULL; | 533 return NULL; |
634 | 534 |
635 dirname = purple_buddy_icons_get_cache_dir(); | 535 dirname = purple_buddy_icons_get_cache_dir(); |
636 | 536 |
637 caching = purple_buddy_icons_is_caching(); | 537 caching = purple_buddy_icons_is_caching(); |
638 /* By disabling caching temporarily, we avoid a loop | 538 /* By disabling caching temporarily, we avoid a loop |
639 * and don't have to add special code through several | 539 * and don't have to add special code through several |
640 * functions. */ | 540 * functions. */ |
641 purple_buddy_icons_set_caching(FALSE); | 541 purple_buddy_icons_set_caching(FALSE); |
642 | 542 |
643 if (custom_icon_file != NULL) | |
644 { | |
645 char *path = g_build_filename(dirname, custom_icon_file, NULL); | |
646 if (read_icon_file(path, &data, &len)) | |
647 { | |
648 icon = purple_buddy_icon_create(account, username); | |
649 purple_buddy_icon_set_custom_data(icon, data, len); | |
650 } | |
651 g_free(path); | |
652 } | |
653 | |
654 if (protocol_icon_file != NULL) | 543 if (protocol_icon_file != NULL) |
655 { | 544 { |
656 char *path = g_build_filename(dirname, protocol_icon_file, NULL); | 545 char *path = g_build_filename(dirname, protocol_icon_file, NULL); |
657 if (read_icon_file(path, &data, &len)) | 546 if (read_icon_file(path, &data, &len)) |
658 { | 547 { |
659 if (icon == NULL) | 548 if (icon == NULL) |
660 icon = purple_buddy_icon_create(account, username); | 549 icon = purple_buddy_icon_create(account, username); |
661 purple_buddy_icon_set_protocol_data(icon, data, len); | 550 purple_buddy_icon_set_data(icon, data, len); |
662 } | 551 } |
663 g_free(path); | 552 g_free(path); |
664 } | 553 } |
665 | 554 |
666 purple_buddy_icons_set_caching(caching); | 555 purple_buddy_icons_set_caching(caching); |
667 } | 556 } |
668 | 557 |
669 return icon; | 558 return icon; |
559 } | |
560 | |
561 gboolean | |
562 purple_buddy_icons_has_custom_icon(PurpleContact *contact) | |
563 { | |
564 g_return_val_if_fail(contact != NULL, FALSE); | |
565 | |
566 return (purple_blist_node_get_string((PurpleBlistNode*)contact, "custom_buddy_icon") != NULL); | |
567 } | |
568 | |
569 PurpleStoredImage * | |
570 purple_buddy_icons_find_custom_icon(PurpleContact *contact) | |
571 { | |
572 PurpleStoredImage *img; | |
573 const char *custom_icon_file; | |
574 const char *dirname; | |
575 char *path; | |
576 guchar *data; | |
577 size_t len; | |
578 | |
579 g_return_val_if_fail(contact != NULL, NULL); | |
580 | |
581 if ((img = g_hash_table_lookup(custom_icon_cache, contact))) | |
582 { | |
583 return purple_imgstore_ref(img); | |
584 } | |
585 | |
586 custom_icon_file = purple_blist_node_get_string((PurpleBlistNode*)contact, "custom_buddy_icon"); | |
587 | |
588 if (custom_icon_file == NULL) | |
589 return NULL; | |
590 | |
591 dirname = purple_buddy_icons_get_cache_dir(); | |
592 path = g_build_filename(dirname, custom_icon_file, NULL); | |
593 | |
594 if (read_icon_file(path, &data, &len)) | |
595 { | |
596 g_free(path); | |
597 img = purple_buddy_icon_data_new(data, len, custom_icon_file); | |
598 g_hash_table_insert(custom_icon_cache, contact, img); | |
599 return img; | |
600 } | |
601 g_free(path); | |
602 | |
603 return NULL; | |
604 } | |
605 | |
606 void | |
607 purple_buddy_icons_set_custom_icon(PurpleContact *contact, | |
608 guchar *icon_data, size_t icon_len) | |
609 { | |
610 PurpleStoredImage *old_img; | |
611 PurpleStoredImage *img = NULL; | |
612 char *old_icon; | |
613 | |
614 old_img = g_hash_table_lookup(custom_icon_cache, contact); | |
615 | |
616 if (icon_data != NULL && icon_len > 0) | |
617 img = purple_buddy_icon_data_new(icon_data, icon_len, NULL); | |
618 | |
619 old_icon = g_strdup(purple_blist_node_get_string((PurpleBlistNode *)contact, | |
620 "custom_buddy_icon")); | |
621 if (img) | |
622 { | |
623 const char *filename = purple_imgstore_get_filename(img); | |
624 purple_blist_node_set_string((PurpleBlistNode *)contact, | |
625 "custom_buddy_icon", | |
626 filename); | |
627 ref_filename(filename); | |
628 } | |
629 else | |
630 { | |
631 purple_blist_node_remove_setting((PurpleBlistNode *)contact, | |
632 "custom_buddy_icon"); | |
633 } | |
634 unref_filename(old_icon); | |
635 g_free(old_icon); | |
636 | |
637 | |
638 g_hash_table_insert(custom_icon_cache, contact, img); | |
639 purple_imgstore_unref(old_img); | |
670 } | 640 } |
671 | 641 |
672 void | 642 void |
673 purple_buddy_icon_set_old_icons_dir(const char *dirname) | 643 purple_buddy_icon_set_old_icons_dir(const char *dirname) |
674 { | 644 { |
759 void | 729 void |
760 purple_buddy_icons_blist_loaded_cb() | 730 purple_buddy_icons_blist_loaded_cb() |
761 { | 731 { |
762 PurpleBlistNode *node = purple_blist_get_root(); | 732 PurpleBlistNode *node = purple_blist_get_root(); |
763 const char *dirname = purple_buddy_icons_get_cache_dir(); | 733 const char *dirname = purple_buddy_icons_get_cache_dir(); |
734 | |
735 // TODO: TEMP | |
736 old_icons_dir = g_strdup("/home/rlaager/.gaim/icons"); | |
764 | 737 |
765 /* Doing this once here saves having to check it inside a loop. */ | 738 /* Doing this once here saves having to check it inside a loop. */ |
766 if (old_icons_dir != NULL) | 739 if (old_icons_dir != NULL) |
767 { | 740 { |
768 if (!g_file_test(dirname, G_FILE_TEST_IS_DIR)) | 741 if (!g_file_test(dirname, G_FILE_TEST_IS_DIR)) |
793 "buddy_icon", | 766 "buddy_icon", |
794 dirname, filename); | 767 dirname, filename); |
795 } | 768 } |
796 else | 769 else |
797 { | 770 { |
798 // TODO: If filename doesn't exist, drop the setting. | 771 if (!g_file_test(filename, G_FILE_TEST_EXISTS)) |
772 { | |
773 purple_blist_node_remove_setting(node, | |
774 "buddy_icon"); | |
775 } | |
799 ref_filename(filename); | 776 ref_filename(filename); |
800 } | 777 } |
801 } | 778 } |
779 } | |
780 else if (PURPLE_BLIST_NODE_IS_CONTACT(node)) | |
781 { | |
782 const char *filename; | |
802 | 783 |
803 filename = purple_blist_node_get_string(node, "custom_buddy_icon"); | 784 filename = purple_blist_node_get_string(node, "custom_buddy_icon"); |
804 if (filename != NULL) | 785 if (filename != NULL) |
805 { | 786 { |
806 if (old_icons_dir != NULL) | 787 if (old_icons_dir != NULL) |
809 "custom_buddy_icon", | 790 "custom_buddy_icon", |
810 dirname, filename); | 791 dirname, filename); |
811 } | 792 } |
812 else | 793 else |
813 { | 794 { |
814 // TODO: If filename doesn't exist, drop the setting. | 795 if (!g_file_test(filename, G_FILE_TEST_EXISTS)) |
796 { | |
797 purple_blist_node_remove_setting(node, | |
798 "custom_buddy_icon"); | |
799 } | |
815 ref_filename(filename); | 800 ref_filename(filename); |
816 } | 801 } |
817 } | 802 } |
818 } | 803 } |
819 node = purple_blist_node_next(node, TRUE); | 804 node = purple_blist_node_next(node, TRUE); |
874 NULL, (GFreeFunc)g_hash_table_destroy); | 859 NULL, (GFreeFunc)g_hash_table_destroy); |
875 | 860 |
876 icon_data_cache = g_hash_table_new(g_str_hash, g_str_equal); | 861 icon_data_cache = g_hash_table_new(g_str_hash, g_str_equal); |
877 icon_file_cache = g_hash_table_new_full(g_str_hash, g_str_equal, | 862 icon_file_cache = g_hash_table_new_full(g_str_hash, g_str_equal, |
878 g_free, NULL); | 863 g_free, NULL); |
864 custom_icon_cache = g_hash_table_new(g_direct_hash, g_direct_equal); | |
879 | 865 |
880 cache_dir = g_build_filename(purple_user_dir(), "icons", NULL); | 866 cache_dir = g_build_filename(purple_user_dir(), "icons", NULL); |
867 | |
868 purple_signal_connect(purple_imgstore_get_handle(), "image-deleting", | |
869 purple_buddy_icons_get_handle(), | |
870 G_CALLBACK(image_deleting_cb), NULL); | |
881 } | 871 } |
882 | 872 |
883 void | 873 void |
884 purple_buddy_icons_uninit() | 874 purple_buddy_icons_uninit() |
885 { | 875 { |
876 purple_signals_disconnect_by_handle(purple_buddy_icons_get_handle()); | |
877 | |
886 g_hash_table_destroy(account_cache); | 878 g_hash_table_destroy(account_cache); |
887 g_hash_table_destroy(icon_data_cache); | 879 g_hash_table_destroy(icon_data_cache); |
888 g_hash_table_destroy(icon_file_cache); | 880 g_hash_table_destroy(icon_file_cache); |
881 g_hash_table_destroy(custom_icon_cache); | |
889 g_free(old_icons_dir); | 882 g_free(old_icons_dir); |
890 } | 883 } |
891 | 884 |
892 void purple_buddy_icon_get_scale_size(PurpleBuddyIconSpec *spec, int *width, int *height) | 885 void purple_buddy_icon_get_scale_size(PurpleBuddyIconSpec *spec, int *width, int *height) |
893 { | 886 { |