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 {