# HG changeset patch # User Richard Laager # Date 1177387027 0 # Node ID 391a79778f8905935abc9cb298c8323dc44fcf67 # Parent 2a19bbc743edb403815f4f562c640f4b0cb7194a Rework the buddy icon subsystem to use the imgstore subsystem, and modify the imgstore subsystem to not require IDs for everything. diff -r 2a19bbc743ed -r 391a79778f89 libpurple/buddyicon.c --- a/libpurple/buddyicon.c Tue Apr 24 03:56:16 2007 +0000 +++ b/libpurple/buddyicon.c Tue Apr 24 03:57:07 2007 +0000 @@ -28,30 +28,26 @@ #include "conversation.h" #include "dbus-maybe.h" #include "debug.h" +#include "imgstore.h" #include "util.h" typedef struct _PurpleBuddyIconData PurpleBuddyIconData; +/* NOTE: Instances of this struct are allocated without zeroing the memory, so + * NOTE: be sure to update purple_buddy_icon_new() if you add members. */ struct _PurpleBuddyIcon { - PurpleAccount *account; /**< The account the user is on. */ - char *username; /**< The username the icon belongs to. */ - PurpleBuddyIconData *protocol_icon; /**< The icon data. */ - PurpleBuddyIconData *custom_icon; /**< The data for a user-set custom icon. */ - int ref_count; /**< The buddy icon reference count. */ -}; - -struct _PurpleBuddyIconData -{ - guchar *image_data; /**< The buddy icon data. */ - size_t len; /**< The length of the buddy icon data. */ - char *filename; /**< The filename of the cache file. */ - int ref_count; /**< The buddy icon reference count. */ + PurpleAccount *account; /**< The account the user is on. */ + char *username; /**< The username the icon belongs to. */ + PurpleStoredImage *img; /**< The id of the stored image with the + the icon data. */ + int ref_count; /**< The buddy icon reference count. */ }; static GHashTable *account_cache = NULL; static GHashTable *icon_data_cache = NULL; static GHashTable *icon_file_cache = NULL; +static GHashTable *custom_icon_cache = NULL; static char *cache_dir = NULL; static gboolean icon_caching = TRUE; @@ -92,33 +88,6 @@ } } -static const char * -get_icon_type(guchar *icon_data, size_t icon_len) -{ - g_return_val_if_fail(icon_data != NULL, NULL); - g_return_val_if_fail(icon_len > 0, NULL); - - if (icon_len >= 4) - { - if (!strncmp((char *)icon_data, "BM", 2)) - return "bmp"; - else if (!strncmp((char *)icon_data, "GIF8", 4)) - return "gif"; - else if (!strncmp((char *)icon_data, "\xff\xd8\xff\xe0", 4)) - return "jpg"; - else if (!strncmp((char *)icon_data, "\x89PNG", 4)) - return "png"; - } - - return "icon"; -} - -static const char * -purple_buddy_icon_data_get_type(PurpleBuddyIconData *data) -{ - return get_icon_type(data->image_data, data->len); -} - static char * purple_buddy_icon_data_calculate_filename(guchar *icon_data, size_t icon_len) { @@ -143,21 +112,23 @@ /* Return the filename */ return g_strdup_printf("%s.%s", digest, - get_icon_type(icon_data, icon_len)); + purple_util_get_image_extension(icon_data, icon_len)); } static void -purple_buddy_icon_data_cache(PurpleBuddyIconData *data) +purple_buddy_icon_data_cache(PurpleStoredImage *img) { const char *dirname; char *path; FILE *file = NULL; + g_return_if_fail(img != NULL); + if (!purple_buddy_icons_is_caching()) return; dirname = purple_buddy_icons_get_cache_dir(); - path = g_build_filename(dirname, data->filename, NULL); + path = g_build_filename(dirname, purple_imgstore_get_filename(img), NULL); if (!g_file_test(dirname, G_FILE_TEST_IS_DIR)) { @@ -173,7 +144,7 @@ if ((file = g_fopen(path, "wb")) != NULL) { - if (!fwrite(data->image_data, data->len, 1, file)) + if (!fwrite(purple_imgstore_get_data(img), purple_imgstore_get_size(img), 1, file)) { purple_debug_error("buddyicon", "Error writing %s: %s\n", path, strerror(errno)); @@ -194,20 +165,20 @@ } static void -purple_buddy_icon_data_uncache(PurpleBuddyIconData *data) +purple_buddy_icon_data_uncache_file(const char *filename) { const char *dirname; char *path; - g_return_if_fail(data != NULL); + g_return_if_fail(filename != NULL); /* It's possible that there are other references to this icon * cache file that are not currently loaded into memory. */ - if (g_hash_table_lookup(icon_file_cache, data->filename)) + if (g_hash_table_lookup(icon_file_cache, filename)) return; dirname = purple_buddy_icons_get_cache_dir(); - path = g_build_filename(dirname, data->filename, NULL); + path = g_build_filename(dirname, filename, NULL); if (g_file_test(path, G_FILE_TEST_EXISTS)) { @@ -223,69 +194,50 @@ g_free(path); } -static PurpleBuddyIconData * -purple_buddy_icon_data_ref(PurpleBuddyIconData *data) +static void +image_deleting_cb(PurpleStoredImage *img, gpointer data) { - g_return_val_if_fail(data != NULL, NULL); + const char *filename = purple_imgstore_get_filename(img); - data->ref_count++; - - return data; + if (img == g_hash_table_lookup(icon_data_cache, filename)) + { + purple_buddy_icon_data_uncache_file(filename); + g_hash_table_remove(icon_data_cache, filename); + } } -static PurpleBuddyIconData * -purple_buddy_icon_data_unref(PurpleBuddyIconData *data) +static PurpleStoredImage * +purple_buddy_icon_data_new(guchar *icon_data, size_t icon_len, const char *filename) { - if (data == NULL) - return NULL; - - g_return_val_if_fail(data->ref_count > 0, NULL); - - data->ref_count--; - - if (data->ref_count == 0) - { - g_hash_table_remove(icon_data_cache, data->filename); - - purple_buddy_icon_data_uncache(data); - - g_free(data->image_data); - g_free(data->filename); - g_free(data); - - return NULL; - } - - return data; -} - -static PurpleBuddyIconData * -purple_buddy_icon_data_new(guchar *icon_data, size_t icon_len) -{ - PurpleBuddyIconData *data; - char *filename; + char *file; + PurpleStoredImage *img; g_return_val_if_fail(icon_data != NULL, NULL); g_return_val_if_fail(icon_len > 0, NULL); - filename = purple_buddy_icon_data_calculate_filename(icon_data, icon_len); if (filename == NULL) - return NULL; + { + file = purple_buddy_icon_data_calculate_filename(icon_data, icon_len); + if (file == NULL) + return NULL; + } + else + file = g_strdup(filename); - if ((data = g_hash_table_lookup(icon_data_cache, filename))) + if ((img = g_hash_table_lookup(icon_data_cache, file))) { - g_free(filename); - return purple_buddy_icon_data_ref(data); + g_free(file); + return purple_imgstore_ref(img); } - data = g_new0(PurpleBuddyIconData, 1); - data->image_data = g_memdup(icon_data, icon_len); - data->len = icon_len; - data->filename = filename; + img = purple_imgstore_add(icon_data, icon_len, file); - purple_buddy_icon_data_cache(data); + /* This will take ownership of file and g_free it either now or later. */ + g_hash_table_insert(icon_data_cache, file, img); - return data; + purple_buddy_icon_data_cache(img); + + return img; } static PurpleBuddyIcon * @@ -294,7 +246,9 @@ PurpleBuddyIcon *icon; GHashTable *icon_cache; - icon = g_new0(PurpleBuddyIcon, 1); + /* This does not zero. See purple_buddy_icon_new() for + * information on which function allocates which member. */ + icon = g_slice_new(PurpleBuddyIcon); PURPLE_DBUS_REGISTER_POINTER(icon, PurpleBuddyIcon); icon->account = account; @@ -316,29 +270,26 @@ PurpleBuddyIcon * purple_buddy_icon_new(PurpleAccount *account, const char *username, - void *protocol_icon_data, size_t protocol_icon_len, - void *custom_icon_data, size_t custom_icon_len) + void *icon_data, size_t icon_len) { PurpleBuddyIcon *icon; g_return_val_if_fail(account != NULL, NULL); g_return_val_if_fail(username != NULL, NULL); - g_return_val_if_fail((protocol_icon_data != NULL && protocol_icon_len > 0) || - (custom_icon_data != NULL && custom_icon_len > 0), NULL); + g_return_val_if_fail(icon_data != NULL, NULL); + g_return_val_if_fail(icon_len > 0, NULL); icon = purple_buddy_icons_find(account, username); + /* purple_buddy_icon_create() sets account & username */ if (icon == NULL) icon = purple_buddy_icon_create(account, username); /* Take a reference for the caller of this function. */ - purple_buddy_icon_ref(icon); + icon->ref_count = 1; - if (protocol_icon_data != NULL && protocol_icon_len > 0) - purple_buddy_icon_set_protocol_data(icon, protocol_icon_data, protocol_icon_len); - - if (custom_icon_data != NULL && custom_icon_len > 0) - purple_buddy_icon_set_custom_data(icon, custom_icon_data, custom_icon_len); + /* purple_buddy_icon_set_data() sets img */ + purple_buddy_icon_set_data(icon, icon_data, icon_len); return icon; } @@ -371,11 +322,10 @@ g_hash_table_remove(icon_cache, purple_buddy_icon_get_username(icon)); g_free(icon->username); - purple_buddy_icon_data_unref(icon->protocol_icon); - purple_buddy_icon_data_unref(icon->custom_icon); + purple_imgstore_unref(icon->img); PURPLE_DBUS_UNREGISTER_POINTER(icon); - g_free(icon); + g_slice_free(PurpleBuddyIcon, icon); return NULL; } @@ -397,58 +347,39 @@ account = purple_buddy_icon_get_account(icon); username = purple_buddy_icon_get_username(icon); - /* If neither type of data exists, then call the functions below with - * NULL to unset the icon. They will then unref the icon and it - * should be destroyed. The only way it wouldn't be destroyed is if - * someone else is holding a reference to it, in which case they can - * kill the icon when they realize it has no data any more. */ - icon_to_set = (icon->protocol_icon || icon->custom_icon) ? icon : NULL; + /* If no data exists, then call the functions below with NULL to + * unset the icon. They will then unref the icon and it should be + * destroyed. The only way it wouldn't be destroyed is if someone + * else is holding a reference to it, in which case they can kill + * the icon when they realize it has no data. */ + icon_to_set = icon->img ? icon : NULL; for (list = sl = purple_find_buddies(account, username); sl != NULL; sl = sl->next) { PurpleBuddy *buddy = (PurpleBuddy *)sl->data; - const char *old_icon; + char *old_icon; purple_buddy_set_icon(buddy, icon_to_set); - old_icon = purple_blist_node_get_string((PurpleBlistNode *)buddy, - "buddy_icon"); - if (icon->protocol_icon) + old_icon = g_strdup(purple_blist_node_get_string((PurpleBlistNode *)buddy, + "buddy_icon")); + if (icon->img) { - old_icon = purple_blist_node_get_string((PurpleBlistNode *)buddy, - "buddy_icon"); + const char *filename = purple_imgstore_get_filename(icon->img); purple_blist_node_set_string((PurpleBlistNode *)buddy, "buddy_icon", - icon->protocol_icon->filename); - ref_filename(icon->protocol_icon->filename); + filename); + ref_filename(filename); } else { purple_blist_node_remove_setting((PurpleBlistNode *)buddy, "buddy_icon"); } unref_filename(old_icon); - - - old_icon = purple_blist_node_get_string((PurpleBlistNode *)buddy, - "custom_buddy_icon"); - if (icon->custom_icon) - { - old_icon = purple_blist_node_get_string((PurpleBlistNode *)buddy, - "custom_buddy_icon"); - purple_blist_node_set_string((PurpleBlistNode *)buddy, - "custom_buddy_icon", - icon->custom_icon->filename); - ref_filename(icon->custom_icon->filename); - } - else - { - purple_blist_node_remove_setting((PurpleBlistNode *)buddy, - "custom_buddy_icon"); - } - unref_filename(old_icon); + g_free(old_icon); } g_slist_free(list); @@ -460,39 +391,21 @@ } void -purple_buddy_icon_set_custom_data(PurpleBuddyIcon *icon, guchar *data, size_t len) +purple_buddy_icon_set_data(PurpleBuddyIcon *icon, guchar *data, size_t len) { - PurpleBuddyIconData *old_data; + PurpleStoredImage *old_img; g_return_if_fail(icon != NULL); - old_data = icon->custom_icon; - icon->custom_icon = NULL; + old_img = icon->img; + icon->img = NULL; if (data != NULL && len > 0) - icon->custom_icon = purple_buddy_icon_data_new(data, len); + icon->img = purple_buddy_icon_data_new(data, len, NULL); purple_buddy_icon_update(icon); - purple_buddy_icon_data_unref(icon->custom_icon); -} - -void -purple_buddy_icon_set_protocol_data(PurpleBuddyIcon *icon, guchar *data, size_t len) -{ - PurpleBuddyIconData *old_data; - - g_return_if_fail(icon != NULL); - - old_data = icon->protocol_icon; - icon->protocol_icon = NULL; - - if (data != NULL && len > 0) - icon->protocol_icon = purple_buddy_icon_data_new(data, len); - - purple_buddy_icon_update(icon); - - purple_buddy_icon_data_unref(old_data); + purple_imgstore_unref(old_img); } PurpleAccount * @@ -511,38 +424,27 @@ return icon->username; } -const guchar * +gconstpointer purple_buddy_icon_get_data(const PurpleBuddyIcon *icon, size_t *len) { g_return_val_if_fail(icon != NULL, NULL); - if (icon->custom_icon) + if (icon->img) { if (len != NULL) - *len = icon->custom_icon->len; - - return icon->custom_icon->image_data; - } + *len = purple_imgstore_get_size(icon->img); - if (icon->protocol_icon) - { - if (len != NULL) - *len = icon->protocol_icon->len; - - return icon->protocol_icon->image_data; + return purple_imgstore_get_data(icon->img); } return NULL; } const char * -purple_buddy_icon_get_type(const PurpleBuddyIcon *icon) +purple_buddy_icon_get_extension(const PurpleBuddyIcon *icon) { - if (icon->custom_icon != NULL) - return purple_buddy_icon_data_get_type(icon->custom_icon); - - if (icon->protocol_icon != NULL) - return purple_buddy_icon_data_get_type(icon->protocol_icon); + if (icon->img != NULL) + return purple_imgstore_get_extension(icon->img); return NULL; } @@ -561,11 +463,11 @@ icon = purple_buddy_icons_find(account, username); if (icon != NULL) - purple_buddy_icon_set_protocol_data(icon, icon_data, icon_len); + purple_buddy_icon_set_data(icon, icon_data, icon_len); } else { - PurpleBuddyIcon *icon = purple_buddy_icon_new(account, username, icon_data, icon_len, NULL, 0); + PurpleBuddyIcon *icon = purple_buddy_icon_new(account, username, icon_data, icon_len); purple_buddy_icon_unref(icon); } } @@ -617,7 +519,6 @@ { PurpleBuddy *b = purple_find_buddy(account, username); const char *protocol_icon_file; - const char *custom_icon_file; const char *dirname; gboolean caching; guchar *data; @@ -627,9 +528,8 @@ return NULL; protocol_icon_file = purple_blist_node_get_string((PurpleBlistNode*)b, "buddy_icon"); - custom_icon_file = purple_blist_node_get_string((PurpleBlistNode*)b, "custom_buddy_icon"); - if (protocol_icon_file == NULL && custom_icon_file == NULL) + if (protocol_icon_file == NULL) return NULL; dirname = purple_buddy_icons_get_cache_dir(); @@ -640,17 +540,6 @@ * functions. */ purple_buddy_icons_set_caching(FALSE); - if (custom_icon_file != NULL) - { - char *path = g_build_filename(dirname, custom_icon_file, NULL); - if (read_icon_file(path, &data, &len)) - { - icon = purple_buddy_icon_create(account, username); - purple_buddy_icon_set_custom_data(icon, data, len); - } - g_free(path); - } - if (protocol_icon_file != NULL) { char *path = g_build_filename(dirname, protocol_icon_file, NULL); @@ -658,7 +547,7 @@ { if (icon == NULL) icon = purple_buddy_icon_create(account, username); - purple_buddy_icon_set_protocol_data(icon, data, len); + purple_buddy_icon_set_data(icon, data, len); } g_free(path); } @@ -669,6 +558,87 @@ return icon; } +gboolean +purple_buddy_icons_has_custom_icon(PurpleContact *contact) +{ + g_return_val_if_fail(contact != NULL, FALSE); + + return (purple_blist_node_get_string((PurpleBlistNode*)contact, "custom_buddy_icon") != NULL); +} + +PurpleStoredImage * +purple_buddy_icons_find_custom_icon(PurpleContact *contact) +{ + PurpleStoredImage *img; + const char *custom_icon_file; + const char *dirname; + char *path; + guchar *data; + size_t len; + + g_return_val_if_fail(contact != NULL, NULL); + + if ((img = g_hash_table_lookup(custom_icon_cache, contact))) + { + return purple_imgstore_ref(img); + } + + custom_icon_file = purple_blist_node_get_string((PurpleBlistNode*)contact, "custom_buddy_icon"); + + if (custom_icon_file == NULL) + return NULL; + + dirname = purple_buddy_icons_get_cache_dir(); + path = g_build_filename(dirname, custom_icon_file, NULL); + + if (read_icon_file(path, &data, &len)) + { + g_free(path); + img = purple_buddy_icon_data_new(data, len, custom_icon_file); + g_hash_table_insert(custom_icon_cache, contact, img); + return img; + } + g_free(path); + + return NULL; +} + +void +purple_buddy_icons_set_custom_icon(PurpleContact *contact, + guchar *icon_data, size_t icon_len) +{ + PurpleStoredImage *old_img; + PurpleStoredImage *img = NULL; + char *old_icon; + + old_img = g_hash_table_lookup(custom_icon_cache, contact); + + if (icon_data != NULL && icon_len > 0) + img = purple_buddy_icon_data_new(icon_data, icon_len, NULL); + + old_icon = g_strdup(purple_blist_node_get_string((PurpleBlistNode *)contact, + "custom_buddy_icon")); + if (img) + { + const char *filename = purple_imgstore_get_filename(img); + purple_blist_node_set_string((PurpleBlistNode *)contact, + "custom_buddy_icon", + filename); + ref_filename(filename); + } + else + { + purple_blist_node_remove_setting((PurpleBlistNode *)contact, + "custom_buddy_icon"); + } + unref_filename(old_icon); + g_free(old_icon); + + + g_hash_table_insert(custom_icon_cache, contact, img); + purple_imgstore_unref(old_img); +} + void purple_buddy_icon_set_old_icons_dir(const char *dirname) { @@ -762,6 +732,9 @@ PurpleBlistNode *node = purple_blist_get_root(); const char *dirname = purple_buddy_icons_get_cache_dir(); + // TODO: TEMP + old_icons_dir = g_strdup("/home/rlaager/.gaim/icons"); + /* Doing this once here saves having to check it inside a loop. */ if (old_icons_dir != NULL) { @@ -795,10 +768,18 @@ } else { - // TODO: If filename doesn't exist, drop the setting. + if (!g_file_test(filename, G_FILE_TEST_EXISTS)) + { + purple_blist_node_remove_setting(node, + "buddy_icon"); + } ref_filename(filename); } } + } + else if (PURPLE_BLIST_NODE_IS_CONTACT(node)) + { + const char *filename; filename = purple_blist_node_get_string(node, "custom_buddy_icon"); if (filename != NULL) @@ -811,7 +792,11 @@ } else { - // TODO: If filename doesn't exist, drop the setting. + if (!g_file_test(filename, G_FILE_TEST_EXISTS)) + { + purple_blist_node_remove_setting(node, + "custom_buddy_icon"); + } ref_filename(filename); } } @@ -876,16 +861,24 @@ icon_data_cache = g_hash_table_new(g_str_hash, g_str_equal); icon_file_cache = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); + custom_icon_cache = g_hash_table_new(g_direct_hash, g_direct_equal); cache_dir = g_build_filename(purple_user_dir(), "icons", NULL); + + purple_signal_connect(purple_imgstore_get_handle(), "image-deleting", + purple_buddy_icons_get_handle(), + G_CALLBACK(image_deleting_cb), NULL); } void purple_buddy_icons_uninit() { + purple_signals_disconnect_by_handle(purple_buddy_icons_get_handle()); + g_hash_table_destroy(account_cache); g_hash_table_destroy(icon_data_cache); g_hash_table_destroy(icon_file_cache); + g_hash_table_destroy(custom_icon_cache); g_free(old_icons_dir); } diff -r 2a19bbc743ed -r 391a79778f89 libpurple/buddyicon.h --- a/libpurple/buddyicon.h Tue Apr 24 03:56:16 2007 +0000 +++ b/libpurple/buddyicon.h Tue Apr 24 03:57:07 2007 +0000 @@ -29,6 +29,7 @@ #include "account.h" #include "blist.h" +#include "imgstore.h" #include "prpl.h" #ifdef __cplusplus @@ -44,25 +45,20 @@ /*@{*/ /** - * Create a buddy icon structure and populate it. + * Creates a new buddy icon structure and populate it. * * If the buddy icon already exists, you'll get a reference to that structure, * which will have been updated with the data supplied. * * @param account The account the user is on. * @param username The username the icon belongs to. - * @param protocol_icon_data The buddy icon data received over the wire. - * @param protocol_icon_len The length of the data in @a protocol_icon_data. - * @param custom_icon_data The data for a custom buddy icon set by the user. - * @param custom_icon_len The length of the data in @a custom_icon-data. - * @return The buddy icon structure, referenced for you. If you don't - * want the reference, then call purple_buddy_icon_unref(). However, - * you may want to use purple_buddy_icon_set_for_user() instead. + * @param icon_data The buddy icon data. + * @param icon_len The buddy icon length. + * + * @return The buddy icon structure. */ -PurpleBuddyIcon * -purple_buddy_icon_new(PurpleAccount *account, const char *username, - void *protocol_icon_data, size_t protocol_icon_len, - void *custom_icon_data, size_t custom_icon_len); +PurpleBuddyIcon *purple_buddy_icon_new(PurpleAccount *account, const char *username, + void *icon_data, size_t icon_len); /** * Increments the reference count on a buddy icon. @@ -92,22 +88,13 @@ void purple_buddy_icon_update(PurpleBuddyIcon *icon); /** - * Sets the buddy icon's data for a custom icon set by the user. - * - * @param icon The buddy icon. - * @param data The buddy icon data for the custom icon set by the user. - * @param len The length of the data in @a data. - */ -void purple_buddy_icon_set_custom_data(PurpleBuddyIcon *icon, guchar *data, size_t len); - -/** * Sets the buddy icon's data that was received over the wire. * * @param icon The buddy icon. * @param data The buddy icon data received over the wire. * @param len The length of the data in @a data. */ -void purple_buddy_icon_set_protocol_data(PurpleBuddyIcon *icon, guchar *data, size_t len); +void purple_buddy_icon_set_data(PurpleBuddyIcon *icon, guchar *data, size_t len); /** * Returns the buddy icon's account. @@ -130,34 +117,23 @@ /** * Returns the buddy icon's data. * - * This will return the data for a custom icon, if one has been set by the - * user. Otherwise, it will return the protocol data, if available. If - * no data is available (which can happen if you're holding on to a - * reference to an icon and the protocol and/or custom icon(s) are deleted - * under you), it will return @c NULL. - * * @param icon The buddy icon. * @param len If not @c NULL, the length of the icon data returned will be * set in the location pointed to by this. * - * @return The icon data. + * @return A pointer to the icon data. */ -const guchar *purple_buddy_icon_get_data(const PurpleBuddyIcon *icon, size_t *len); +gconstpointer purple_buddy_icon_get_data(const PurpleBuddyIcon *icon, size_t *len); /** * Returns an extension corresponding to the buddy icon's file type. * - * This will return the type of a custom icon, if one has been set by the - * user. Otherwise, it will return the type of the protocol icon, if - * available. If no data is available (which can happen if you're holding on - * to a reference to an icon and the protocol and/or custom icon(s) are deleted - * under you), it will return @c NULL. - * * @param icon The buddy icon. * - * @return The icon's extension, or "icon" if unknown. + * @return The icon's extension, "icon" if unknown, or @c NULL if + * the image data has disappeared. */ -const char *purple_buddy_icon_get_type(const PurpleBuddyIcon *icon); +const char *purple_buddy_icon_get_extension(const PurpleBuddyIcon *icon); /*@}*/ @@ -192,6 +168,44 @@ purple_buddy_icons_find(PurpleAccount *account, const char *username); /** + * Returns a boolean indicating if a given contact has a custom buddy icon. + * + * @param contact The contact + * + * @return A boolean indicating if @a contact has a custom buddy icon. + */ +gboolean +purple_buddy_icons_has_custom_icon(PurpleContact *contact); + +/** + * Returns the custom buddy icon image for a contact. + * + * This function deals with loading the icon from the cache, if + * needed, so it should be called in any case where you want the + * appropriate icon. + * + * @param contact The contact + * + * @return The custom buddy icon image. + */ +PurpleStoredImage * +purple_buddy_icons_find_custom_icon(PurpleContact *contact); + +/** + * Sets a custom buddy icon for a user. + * + * This function will deal with saving a record of the icon, + * caching the data, etc. + * + * @param contact The contact for which to set a custom icon. + * @param icon_data The image data of the icon. + * @param icon_len The length of the data in @a icon_data. + */ +void +purple_buddy_icons_set_custom_icon(PurpleContact *contact, + guchar *icon_data, size_t icon_len); + +/** * Sets whether or not buddy icon caching is enabled. * * @param caching TRUE of buddy icon caching should be enabled, or diff -r 2a19bbc743ed -r 391a79778f89 libpurple/core.c --- a/libpurple/core.c Tue Apr 24 03:56:16 2007 +0000 +++ b/libpurple/core.c Tue Apr 24 03:57:07 2007 +0000 @@ -31,6 +31,7 @@ #include "dnsquery.h" #include "ft.h" #include "idle.h" +#include "imgstore.h" #include "network.h" #include "notify.h" #include "plugin.h" @@ -124,6 +125,9 @@ purple_plugins_init(); purple_plugins_probe(G_MODULE_SUFFIX); + /* The buddy icon code uses the imgstore, so init it early. */ + purple_imgstore_init(); + /* Accounts use status and buddy icons, so initialize these before accounts */ purple_status_init(); purple_buddy_icons_init(); @@ -190,6 +194,7 @@ purple_xfers_uninit(); purple_proxy_uninit(); purple_dnsquery_uninit(); + purple_imgstore_uninit(); purple_debug_info("main", "Unloading all plugins\n"); purple_plugins_destroy_all(); diff -r 2a19bbc743ed -r 391a79778f89 libpurple/gaim-compat.h --- a/libpurple/gaim-compat.h Tue Apr 24 03:56:16 2007 +0000 +++ b/libpurple/gaim-compat.h Tue Apr 24 03:57:07 2007 +0000 @@ -351,7 +351,7 @@ #define gaim_buddy_icon_get_account purple_buddy_icon_get_account #define gaim_buddy_icon_get_username purple_buddy_icon_get_username #define gaim_buddy_icon_get_data purple_buddy_icon_get_data -#define gaim_buddy_icon_get_type purple_buddy_icon_get_type +#define gaim_buddy_icon_get_type purple_buddy_icon_get_extension #define gaim_buddy_icons_set_for_user purple_buddy_icons_set_for_user #define gaim_buddy_icons_find purple_buddy_icons_find @@ -962,13 +962,13 @@ #define GaimStoredImage PurpleStoredImage -#define gaim_imgstore_add purple_imgstore_add -#define gaim_imgstore_get purple_imgstore_get +#define gaim_imgstore_add purple_imgstore_add_with_id +#define gaim_imgstore_get purple_imgstore_find_by_id #define gaim_imgstore_get_data purple_imgstore_get_data #define gaim_imgstore_get_size purple_imgstore_get_size #define gaim_imgstore_get_filename purple_imgstore_get_filename -#define gaim_imgstore_ref purple_imgstore_ref -#define gaim_imgstore_unref purple_imgstore_unref +#define gaim_imgstore_ref purple_imgstore_ref_by_id +#define gaim_imgstore_unref purple_imgstore_unref_by_id /* from log.h */ @@ -2232,7 +2232,7 @@ #define gaim_value_new_outgoing purple_value_new_outgoing #define gaim_value_destroy purple_value_destroy #define gaim_value_dup purple_value_dup -#define gaim_value_get_type purple_value_get_type +#define gaim_value_purple_buddy_icon_get_extensionget_type purple_value_get_type #define gaim_value_get_subtype purple_value_get_subtype #define gaim_value_get_specific_type purple_value_get_specific_type #define gaim_value_is_outgoing purple_value_is_outgoing diff -r 2a19bbc743ed -r 391a79778f89 libpurple/imgstore.c --- a/libpurple/imgstore.c Tue Apr 24 03:56:16 2007 +0000 +++ b/libpurple/imgstore.c Tue Apr 24 03:57:07 2007 +0000 @@ -27,140 +27,160 @@ #include #include "debug.h" #include "imgstore.h" +#include "util.h" -static GSList *imgstore = NULL; +static GHashTable *imgstore; static int nextid = 0; /** * Stored image * - * Represents a single IM image awaiting display and/or transmission. - * Now that this type is basicly private too, these two structs could - * probably be combined. + * NOTE: purple_imgstore_add() creates these without zeroing the memory, so + * NOTE: make sure to update that function when adding members. */ struct _PurpleStoredImage { - char *data; /**< The image data. */ + int id; + guint8 refcount; size_t size; /**< The image data's size. */ char *filename; /**< The filename (for the UI) */ + gpointer data; /**< The image data. */ }; -typedef struct +PurpleStoredImage * +purple_imgstore_add(gconstpointer data, size_t size, const char *filename) { - int id; - int refcount; - PurpleStoredImage *img; -} PurpleStoredImagePriv; - -/* private functions */ - -static PurpleStoredImagePriv *purple_imgstore_get_priv(int id) { - GSList *tmp = imgstore; - PurpleStoredImagePriv *priv = NULL; - - g_return_val_if_fail(id > 0, NULL); - - while (tmp && !priv) { - PurpleStoredImagePriv *tmp_priv = tmp->data; - - if (tmp_priv->id == id) - priv = tmp_priv; - - tmp = tmp->next; - } - - if (!priv) - purple_debug(PURPLE_DEBUG_ERROR, "imgstore", "failed to find image id %d\n", id); - - return priv; -} - -static void purple_imgstore_free_priv(PurpleStoredImagePriv *priv) { - PurpleStoredImage *img = NULL; - - g_return_if_fail(priv != NULL); - - img = priv->img; - if (img) { - g_free(img->data); - g_free(img->filename); - g_free(img); - } - - purple_debug(PURPLE_DEBUG_INFO, "imgstore", "freed image id %d\n", priv->id); - - g_free(priv); - - imgstore = g_slist_remove(imgstore, priv); -} - -/* public functions */ - -int purple_imgstore_add(const void *data, size_t size, const char *filename) { - PurpleStoredImagePriv *priv; PurpleStoredImage *img; g_return_val_if_fail(data != NULL, 0); g_return_val_if_fail(size > 0, 0); - img = g_new0(PurpleStoredImage, 1); + img = g_slice_new(PurpleStoredImage); img->data = g_memdup(data, size); img->size = size; img->filename = g_strdup(filename); + img->refcount = 1; + img->id = 0; - priv = g_new0(PurpleStoredImagePriv, 1); - priv->id = ++nextid; - priv->refcount = 1; - priv->img = img; + return img; +} + +int +purple_imgstore_add_with_id(gconstpointer data, size_t size, const char *filename) +{ + PurpleStoredImage *img = purple_imgstore_add(data, size, filename); + img->id = ++nextid; + + g_hash_table_insert(imgstore, GINT_TO_POINTER(img->id), img); - imgstore = g_slist_append(imgstore, priv); - purple_debug(PURPLE_DEBUG_INFO, "imgstore", "added image id %d\n", priv->id); + return img->id; +} + +PurpleStoredImage *purple_imgstore_find_by_id(int id) { + PurpleStoredImage *img = g_hash_table_lookup(imgstore, GINT_TO_POINTER(id)); - return priv->id; + if (img != NULL) + purple_debug_misc("imgstore", "retrieved image id %d\n", img->id); + + return img; +} + +gconstpointer purple_imgstore_get_data(PurpleStoredImage *img) { + return img->data; } -PurpleStoredImage *purple_imgstore_get(int id) { - PurpleStoredImagePriv *priv = purple_imgstore_get_priv(id); +size_t purple_imgstore_get_size(PurpleStoredImage *img) +{ + return img->size; +} - g_return_val_if_fail(priv != NULL, NULL); +const char *purple_imgstore_get_filename(PurpleStoredImage *img) +{ + return img->filename; +} - purple_debug(PURPLE_DEBUG_INFO, "imgstore", "retrieved image id %d\n", priv->id); - - return priv->img; +const char *purple_imgstore_get_extension(PurpleStoredImage *img) +{ + return purple_util_get_image_extension(img->data, img->size); } -gpointer purple_imgstore_get_data(PurpleStoredImage *i) { - return i->data; +void purple_imgstore_ref_by_id(int id) +{ + PurpleStoredImage *img = purple_imgstore_find_by_id(id); + + g_return_if_fail(img != NULL); + + purple_imgstore_ref(img); +} + +void purple_imgstore_unref_by_id(int id) +{ + PurpleStoredImage *img = purple_imgstore_find_by_id(id); + + g_return_if_fail(img != NULL); + + purple_imgstore_unref(img); } -size_t purple_imgstore_get_size(PurpleStoredImage *i) { - return i->size; -} +PurpleStoredImage * +purple_imgstore_ref(PurpleStoredImage *img) +{ + g_return_val_if_fail(img != NULL, NULL); -const char *purple_imgstore_get_filename(PurpleStoredImage *i) { - return i->filename; + img->refcount++; + + return img; } -void purple_imgstore_ref(int id) { - PurpleStoredImagePriv *priv = purple_imgstore_get_priv(id); +PurpleStoredImage * +purple_imgstore_unref(PurpleStoredImage *img) +{ + if (img == NULL) + return NULL; + + g_return_val_if_fail(img->refcount > 0, NULL); + + img->refcount--; - g_return_if_fail(priv != NULL); + if (img->refcount == 0) + { + purple_signal_emit(purple_blist_get_handle(), + "image-deleting", img); - (priv->refcount)++; + if (img->id) + g_hash_table_remove(imgstore, GINT_TO_POINTER(img->id)); + g_slice_free(PurpleStoredImage, img); + } - purple_debug(PURPLE_DEBUG_INFO, "imgstore", "referenced image id %d (count now %d)\n", priv->id, priv->refcount); + return img; } -void purple_imgstore_unref(int id) { - PurpleStoredImagePriv *priv = purple_imgstore_get_priv(id); +void * +purple_imgstore_get_handle() +{ + static int handle; - g_return_if_fail(priv != NULL); - g_return_if_fail(priv->refcount > 0); + return &handle; +} + +void +purple_imgstore_init() +{ + void *handle = purple_imgstore_get_handle(); - (priv->refcount)--; - - purple_debug(PURPLE_DEBUG_INFO, "imgstore", "unreferenced image id %d (count now %d)\n", priv->id, priv->refcount); + purple_signal_register(handle, "image-deleting", + purple_marshal_VOID__POINTER, NULL, + 1, + purple_value_new(PURPLE_TYPE_SUBTYPE, + PURPLE_SUBTYPE_STORED_IMAGE)); - if (priv->refcount == 0) - purple_imgstore_free_priv(priv); + imgstore = g_hash_table_new(g_int_hash, g_int_equal); } + +void +purple_imgstore_uninit() +{ + g_hash_table_destroy(imgstore); + + purple_signals_unregister_by_instance(purple_blist_get_handle()); +} diff -r 2a19bbc743ed -r 391a79778f89 libpurple/imgstore.h --- a/libpurple/imgstore.h Tue Apr 24 03:56:16 2007 +0000 +++ b/libpurple/imgstore.h Tue Apr 24 03:57:07 2007 +0000 @@ -34,9 +34,29 @@ #endif /** - * Add an image to the store. The caller owns a reference - * to the image in the store, and must dereference the image - * with purple_imgstore_unref for it to be freed. + * Add an image to the store. + * + * The caller owns a reference to the image in the store, and must dereference + * the image with purple_imgstore_unref() for it to be freed. + * + * No ID is allocated when using this function. If you need to reference the + * image by an ID, use purple_imgstore_add_with_id() instead. + * + * @param data Pointer to the image data. + * @param size Image data's size. + * @param filename Filename associated with image. + * + * @return The stored image. + */ +PurpleStoredImage * +purple_imgstore_add(gconstpointer data, size_t size, const char *filename); + +/** + * Add an image to the store, allocating an ID. + * + * The caller owns a reference to the image in the store, and must dereference + * the image with purple_imgstore_unref_by_id() or purple_imgstore_unref() + * for it to be freed. * * @param data Pointer to the image data. * @param size Image data's size. @@ -44,7 +64,7 @@ * @return ID for the image. */ -int purple_imgstore_add(const void *data, size_t size, const char *filename); +int purple_imgstore_add_with_id(gconstpointer data, size_t size, const char *filename); /** * Retrieve an image from the store. The caller does not own a @@ -54,22 +74,22 @@ * * @return A pointer to the requested image, or NULL if it was not found. */ -PurpleStoredImage *purple_imgstore_get(int id); +PurpleStoredImage *purple_imgstore_find_by_id(int id); /** * Retrieves a pointer to the image's data. * - * @param i The Image + * @param img The Image * * @return A pointer to the data, which must not * be freed or modified. */ -gpointer purple_imgstore_get_data(PurpleStoredImage *i); +gconstpointer purple_imgstore_get_data(PurpleStoredImage *img); /** * Retrieves the length of the image's data. * - * @param i The Image + * @param img The Image * * @return The size of the data that the pointer returned by * purple_imgstore_get_data points to. @@ -79,30 +99,82 @@ /** * Retrieves a pointer to the image's filename. * - * @param i The Image + * @param img The image * * @return A pointer to the filename, which must not * be freed or modified. */ -const char *purple_imgstore_get_filename(PurpleStoredImage *i); +const char *purple_imgstore_get_filename(PurpleStoredImage *img); + +/** + * Returns an extension corresponding to the image's file type. + * + * @param img The image. + * + * @return The icon's extension or "icon" if unknown. + */ +const char *purple_imgstore_get_extension(PurpleStoredImage *img); /** - * Increment the reference count for an image in the store. The - * image will be removed from the store when the reference count - * is zero. + * Increment the reference count. + * + * @param img The image. + * + * @return @a img + */ +PurpleStoredImage * +purple_imgstore_ref(PurpleStoredImage *img); + +/** + * Decrement the reference count. + * + * If the reference count reaches zero, the image will be freed. + * + * @param img The image. + * + * @return @a img or @c NULL if the reference count reached zero. + */ +PurpleStoredImage * +purple_imgstore_unref(PurpleStoredImage *img); + +/** + * Increment the reference count using an ID. + * + * This is a convience wrapper for purple_imgstore_find_by_id() and + * purple_imgstore_ref(), so if you have a PurpleStoredImage, it'll + * be more efficient to call purple_imgstore_ref() directly. * * @param id The ID for the image. */ -void purple_imgstore_ref(int id); +void purple_imgstore_ref_by_id(int id); /** - * Decrement the reference count for an image in the store. The - * image will be removed from the store when the reference count - * is zero. + * Decrement the reference count using an ID. + * + * This is a convience wrapper for purple_imgstore_find_by_id() and + * purple_imgstore_unref(), so if you have a PurpleStoredImage, it'll + * be more efficient to call purple_imgstore_unref() directly. * * @param id The ID for the image. */ -void purple_imgstore_unref(int id); +void purple_imgstore_unref_by_id(int id); + +/** + * Returns the image store subsystem handle. + * + * @return The subsystem handle. + */ +void *purple_imgstore_get_handle(void); + +/** + * Initializes the image store subsystem. + */ +void purple_imgstore_init(void); + +/** + * Uninitializes the image store subsystem. + */ +void purple_imgstore_uninit(void); #ifdef __cplusplus } diff -r 2a19bbc743ed -r 391a79778f89 libpurple/protocols/jabber/buddy.c --- a/libpurple/protocols/jabber/buddy.c Tue Apr 24 03:56:16 2007 +0000 +++ b/libpurple/protocols/jabber/buddy.c Tue Apr 24 03:57:07 2007 +0000 @@ -714,7 +714,7 @@ purple_notify_user_info_destroy(user_info); while(jbi->vcard_imgids) { - purple_imgstore_unref(GPOINTER_TO_INT(jbi->vcard_imgids->data)); + purple_imgstore_unref_by_id(GPOINTER_TO_INT(jbi->vcard_imgids->data)); jbi->vcard_imgids = g_slist_delete_link(jbi->vcard_imgids, jbi->vcard_imgids); } @@ -959,7 +959,7 @@ data = purple_base64_decode(bintext, &size); - jbi->vcard_imgids = g_slist_prepend(jbi->vcard_imgids, GINT_TO_POINTER(purple_imgstore_add(data, size, "logo.png"))); + jbi->vcard_imgids = g_slist_prepend(jbi->vcard_imgids, GINT_TO_POINTER(purple_imgstore_add_with_id(data, size, "logo.png"))); g_string_append_printf(info_text, "%s:
", photo ? _("Photo") : _("Logo"), diff -r 2a19bbc743ed -r 391a79778f89 libpurple/protocols/msn/msn.c --- a/libpurple/protocols/msn/msn.c Tue Apr 24 03:56:16 2007 +0000 +++ b/libpurple/protocols/msn/msn.c Tue Apr 24 03:57:07 2007 +0000 @@ -1869,7 +1869,7 @@ { char buf[1024]; purple_debug_info("msn", "%s is %d bytes\n", photo_url_text, len); - id = purple_imgstore_add(url_text, len, NULL); + id = purple_imgstore_add_with_id(url_text, len, NULL); g_snprintf(buf, sizeof(buf), "
", id); purple_notify_user_info_prepend_pair(user_info, NULL, buf); } @@ -1888,7 +1888,7 @@ g_free(photo_url_text); g_free(info2_data); if (id != -1) - purple_imgstore_unref(id); + purple_imgstore_unref_by_id(id); #endif } diff -r 2a19bbc743ed -r 391a79778f89 libpurple/protocols/oscar/odc.c --- a/libpurple/protocols/oscar/odc.c Tue Apr 24 03:56:16 2007 +0000 +++ b/libpurple/protocols/oscar/odc.c Tue Apr 24 03:57:07 2007 +0000 @@ -353,7 +353,7 @@ if ((embedded_data != NULL) && (embedded_data->size == size)) { - imgid = purple_imgstore_add(embedded_data->data, size, src); + imgid = purple_imgstore_add_with_id(embedded_data->data, size, src); /* Record the image number */ images = g_slist_append(images, GINT_TO_POINTER(imgid)); @@ -406,7 +406,7 @@ { GSList *l; for (l = images; l != NULL; l = l->next) - purple_imgstore_unref(GPOINTER_TO_INT(l->data)); + purple_imgstore_unref_by_id(GPOINTER_TO_INT(l->data)); g_slist_free(images); } diff -r 2a19bbc743ed -r 391a79778f89 libpurple/protocols/oscar/oscar.c --- a/libpurple/protocols/oscar/oscar.c Tue Apr 24 03:56:16 2007 +0000 +++ b/libpurple/protocols/oscar/oscar.c Tue Apr 24 03:57:07 2007 +0000 @@ -4140,11 +4140,11 @@ id = g_datalist_get_data(&attribs, "id"); /* ... if it refers to a valid purple image ... */ - if (id && (image = purple_imgstore_get(atoi(id)))) { + if (id && (image = purple_imgstore_find_by_id(atoi(id)))) { /* ... append the message from start to the tag ... */ unsigned long size = purple_imgstore_get_size(image); const char *filename = purple_imgstore_get_filename(image); - gpointer imgdata = purple_imgstore_get_data(image); + gconstpointer imgdata = purple_imgstore_get_data(image); oscar_id++; diff -r 2a19bbc743ed -r 391a79778f89 libpurple/protocols/sametime/sametime.c --- a/libpurple/protocols/sametime/sametime.c Tue Apr 24 03:56:16 2007 +0000 +++ b/libpurple/protocols/sametime/sametime.c Tue Apr 24 03:57:07 2007 +0000 @@ -2698,7 +2698,7 @@ cid = make_cid(cid); /* add image to the purple image store */ - img = purple_imgstore_add(d_dat, d_len, cid); + img = purple_imgstore_add_with_id(d_dat, d_len, cid); g_free(d_dat); /* map the cid to the image store identifier */ @@ -2772,7 +2772,7 @@ /* dereference all the imgages */ while(images) { - purple_imgstore_unref(GPOINTER_TO_INT(images->data)); + purple_imgstore_unref_by_id(GPOINTER_TO_INT(images->data)); images = g_list_delete_link(images, images); } } @@ -3856,7 +3856,7 @@ /* find the imgstore data by the id tag */ id = g_datalist_get_data(&attr, "id"); if(id && *id) - img = purple_imgstore_get(atoi(id)); + img = purple_imgstore_find_by_id(atoi(id)); if(img) { char *cid; @@ -3882,9 +3882,8 @@ /* obtain and base64 encode the image data, and put it in the mime part */ - data = purple_imgstore_get_data(img); size = purple_imgstore_get_size(img); - data = purple_base64_encode(data, (gsize) size); + data = purple_base64_encode(purple_imgstore_get_data(img), (gsize) size); purple_mime_part_set_data(part, data); g_free(data); diff -r 2a19bbc743ed -r 391a79778f89 libpurple/protocols/silc/buddy.c --- a/libpurple/protocols/silc/buddy.c Tue Apr 24 03:56:16 2007 +0000 +++ b/libpurple/protocols/silc/buddy.c Tue Apr 24 03:57:07 2007 +0000 @@ -1716,7 +1716,7 @@ } t = purple_buddy_icon_get_type((const PurpleBuddyIcon *)&ic); - if (!t) { + if (!t || !strcmp(t, "icon")) { g_free(ic.data); silc_mime_free(mime); return; diff -r 2a19bbc743ed -r 391a79778f89 libpurple/protocols/silc/ops.c --- a/libpurple/protocols/silc/ops.c Tue Apr 24 03:56:16 2007 +0000 +++ b/libpurple/protocols/silc/ops.c Tue Apr 24 03:57:07 2007 +0000 @@ -161,7 +161,7 @@ if (channel && !convo) goto out; - imgid = purple_imgstore_add(data, data_len, ""); + imgid = purple_imgstore_add_with_id(data, data_len, ""); if (imgid) { cflags |= PURPLE_MESSAGE_IMAGES | PURPLE_MESSAGE_RECV; g_snprintf(tmp, sizeof(tmp), "", imgid); @@ -177,7 +177,7 @@ sender->nickname : "", tmp, cflags, time(NULL)); - purple_imgstore_unref(imgid); + purple_imgstore_unref_by_id(imgid); cflags = 0; } goto out; diff -r 2a19bbc743ed -r 391a79778f89 libpurple/protocols/yahoo/yahoo_profile.c --- a/libpurple/protocols/yahoo/yahoo_profile.c Tue Apr 24 03:56:16 2007 +0000 +++ b/libpurple/protocols/yahoo/yahoo_profile.c Tue Apr 24 03:57:07 2007 +0000 @@ -1022,7 +1022,7 @@ photo_url_text, url_text); } else { purple_debug_info("yahoo", "%s is %d bytes\n", photo_url_text, len); - id = purple_imgstore_add(url_text, len, NULL); + id = purple_imgstore_add_with_id(url_text, len, NULL); tmp = g_strdup_printf("
", id); purple_notify_user_info_add_pair(user_info, NULL, tmp); @@ -1234,7 +1234,7 @@ g_free(photo_url_text); g_free(info2_data); if (id != -1) - purple_imgstore_unref(id); + purple_imgstore_unref_by_id(id); #endif } diff -r 2a19bbc743ed -r 391a79778f89 libpurple/util.c --- a/libpurple/util.c Tue Apr 24 03:56:16 2007 +0000 +++ b/libpurple/util.c Tue Apr 24 03:57:07 2007 +0000 @@ -2569,6 +2569,27 @@ return fp; } +const char * +purple_util_get_image_extension(gpointer data, size_t len) +{ + g_return_val_if_fail(data != NULL, NULL); + g_return_val_if_fail(len > 0, NULL); + + if (len >= 4) + { + if (!strncmp((char *)data, "BM", 2)) + return "bmp"; + else if (!strncmp((char *)data, "GIF8", 4)) + return "gif"; + else if (!strncmp((char *)data, "\xff\xd8\xff\xe0", 4)) + return "jpg"; + else if (!strncmp((char *)data, "\x89PNG", 4)) + return "png"; + } + + return "icon"; +} + gboolean purple_program_is_valid(const char *program) { diff -r 2a19bbc743ed -r 391a79778f89 libpurple/util.h --- a/libpurple/util.h Tue Apr 24 03:56:16 2007 +0000 +++ b/libpurple/util.h Tue Apr 24 03:57:07 2007 +0000 @@ -598,6 +598,25 @@ FILE *purple_mkstemp(char **path, gboolean binary); /** + * Returns an extension corresponding to the image data's file type. + * + * @param data A pointer to the image data + * @param len The length of the image data + * + * @return The appropriate extension, or "icon" if unknown. + */ +const char * +purple_util_get_image_extension(gpointer data, size_t len); + +/*@}*/ + + +/**************************************************************************/ +/** @name Environment Detection Functions */ +/**************************************************************************/ +/*@{*/ + +/** * Checks if the given program name is valid and executable. * * @param program The file name of the application. @@ -1118,6 +1137,7 @@ * inherit the handlers of the parent. */ void purple_restore_default_signal_handlers(void); + #ifdef __cplusplus } #endif diff -r 2a19bbc743ed -r 391a79778f89 libpurple/value.h --- a/libpurple/value.h Tue Apr 24 03:56:16 2007 +0000 +++ b/libpurple/value.h Tue Apr 24 03:57:07 2007 +0000 @@ -76,7 +76,8 @@ PURPLE_SUBTYPE_XFER, PURPLE_SUBTYPE_SAVEDSTATUS, PURPLE_SUBTYPE_XMLNODE, - PURPLE_SUBTYPE_USERINFO + PURPLE_SUBTYPE_USERINFO, + PURPLE_SUBTYPE_STORED_IMAGE } PurpleSubType; /** diff -r 2a19bbc743ed -r 391a79778f89 pidgin/gtkblist.c --- a/pidgin/gtkblist.c Tue Apr 24 03:56:16 2007 +0000 +++ b/pidgin/gtkblist.c Tue Apr 24 03:57:07 2007 +0000 @@ -2155,7 +2155,7 @@ static GdkPixbuf *pidgin_blist_get_buddy_icon(PurpleBlistNode *node, - gboolean scaled, gboolean greyed, gboolean custom) + gboolean scaled, gboolean greyed) { GdkPixbuf *buf, *ret = NULL; GdkPixbufLoader *loader; @@ -2166,6 +2166,7 @@ PurpleChat *chat = NULL; PurpleAccount *account = NULL; PurplePluginProtocolInfo *prpl_info = NULL; + PurpleStoredImage *custom_img; if(PURPLE_BLIST_NODE_IS_CONTACT(node)) { buddy = purple_contact_get_priority_buddy((PurpleContact*)node); @@ -2190,19 +2191,11 @@ return NULL; #endif - if (custom) { - const char *file = purple_blist_node_get_string((PurpleBlistNode*)purple_buddy_get_contact(buddy), - "custom_buddy_icon"); - if (file && *file) { - char *contents; - GError *err = NULL; - if (!g_file_get_contents(file, &contents, &len, &err)) { - purple_debug_info("custom -icon", "Could not open custom-icon %s for %s\n", - file, purple_buddy_get_name(buddy), err->message); - g_error_free(err); - } else - data = (const guchar*)contents; - } + custom_img = purple_buddy_icons_find_custom_icon(purple_buddy_get_contact(buddy)); + if (custom_img) + { + data = purple_imgstore_get_data(custom_img); + len = purple_imgstore_get_size(custom_img); } if (data == NULL) { @@ -2212,7 +2205,6 @@ return NULL; data = purple_buddy_icon_get_data(icon, &len); } - custom = FALSE; /* We are not using the custom icon */ } if(data == NULL) @@ -2221,13 +2213,14 @@ loader = gdk_pixbuf_loader_new(); gdk_pixbuf_loader_write(loader, data, len, NULL); gdk_pixbuf_loader_close(loader, NULL); + + purple_imgstore_unref(custom_img); + buf = gdk_pixbuf_loader_get_pixbuf(loader); if (buf) g_object_ref(G_OBJECT(buf)); g_object_unref(G_OBJECT(loader)); - if (custom) - g_free((void*)data); if (buf) { int orig_width, orig_height; int scale_width, scale_height; @@ -2335,7 +2328,7 @@ } td->status_icon = pidgin_blist_get_status_icon(node, PIDGIN_STATUS_ICON_LARGE); - td->avatar = pidgin_blist_get_buddy_icon(node, !full, FALSE, TRUE); + td->avatar = pidgin_blist_get_buddy_icon(node, !full, FALSE); td->prpl_icon = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_SMALL); tooltip_text = pidgin_get_tooltip_text(node, full); td->layout = gtk_widget_create_pango_layout(gtkblist->tipwindow, NULL); @@ -4893,7 +4886,7 @@ status = pidgin_blist_get_status_icon((PurpleBlistNode*)buddy, PIDGIN_STATUS_ICON_SMALL); - avatar = pidgin_blist_get_buddy_icon((PurpleBlistNode *)buddy, TRUE, TRUE, TRUE); + avatar = pidgin_blist_get_buddy_icon((PurpleBlistNode *)buddy, TRUE, TRUE); if (!avatar) { g_object_ref(G_OBJECT(gtkblist->empty_avatar)); avatar = gtkblist->empty_avatar; @@ -5078,7 +5071,7 @@ status = pidgin_blist_get_status_icon(node, PIDGIN_STATUS_ICON_SMALL); emblem = pidgin_blist_get_emblem(node); - avatar = pidgin_blist_get_buddy_icon(node, TRUE, FALSE, TRUE); + avatar = pidgin_blist_get_buddy_icon(node, TRUE, FALSE); mark = g_markup_escape_text(purple_chat_get_name(chat), -1); diff -r 2a19bbc743ed -r 391a79778f89 pidgin/gtkconv.c --- a/pidgin/gtkconv.c Tue Apr 24 03:56:16 2007 +0000 +++ b/pidgin/gtkconv.c Tue Apr 24 03:57:07 2007 +0000 @@ -2538,7 +2538,7 @@ g_return_if_fail(conv != NULL); - ext = purple_buddy_icon_get_type(purple_conv_im_get_icon(PURPLE_CONV_IM(conv))); + ext = purple_buddy_icon_get_extension(purple_conv_im_get_icon(PURPLE_CONV_IM(conv))); buf = g_strdup_printf("%s.%s", purple_normalize(conv->account, conv->name), ext); diff -r 2a19bbc743ed -r 391a79778f89 pidgin/gtkimhtmltoolbar.c --- a/pidgin/gtkimhtmltoolbar.c Tue Apr 24 03:56:16 2007 +0000 +++ b/pidgin/gtkimhtmltoolbar.c Tue Apr 24 03:57:07 2007 +0000 @@ -480,7 +480,7 @@ name = strrchr(filename, G_DIR_SEPARATOR) + 1; - id = purple_imgstore_add(filedata, size, name); + id = purple_imgstore_add_with_id(filedata, size, name); g_free(filedata); if (id == 0) { @@ -499,7 +499,7 @@ gtk_text_buffer_get_iter_at_mark(gtk_text_view_get_buffer(GTK_TEXT_VIEW(toolbar->imhtml)), &iter, ins); gtk_imhtml_insert_image_at_iter(GTK_IMHTML(toolbar->imhtml), id, &iter); - purple_imgstore_unref(id); + purple_imgstore_unref_by_id(id); } diff -r 2a19bbc743ed -r 391a79778f89 pidgin/gtkmain.c --- a/pidgin/gtkmain.c Tue Apr 24 03:56:16 2007 +0000 +++ b/pidgin/gtkmain.c Tue Apr 24 03:57:07 2007 +0000 @@ -145,7 +145,7 @@ static void sighandler(int sig); /** - * Reap all our dead children. Sometimes Purple forks off a separate + * Reap all our dead children. Sometimes libpurple forks off a separate * process to do some stuff. When that process exits we are * informed about it so that we can call waitpid() and let it * stop being a zombie. @@ -160,7 +160,7 @@ * it continues with the initialization process. This means that * we have a race condition where GStreamer is waitpid()ing for its * child to die and we're catching the SIGCHLD signal. If GStreamer - * is awarded the zombied process then everything is ok. But if Purple + * is awarded the zombied process then everything is ok. But if libpurple * reaps the zombie process then the GStreamer initialization sequence * fails. * @@ -677,7 +677,7 @@ { char *old = g_strconcat(purple_home_dir(), G_DIR_SEPARATOR_S ".gaim", NULL); - char *text = _( + const char *text = _( "Pidgin encountered errors migrating your settings " "from %s to %s. Please investigate and complete the " "migration by hand."); diff -r 2a19bbc743ed -r 391a79778f89 pidgin/gtkutils.c --- a/pidgin/gtkutils.c Tue Apr 24 03:56:16 2007 +0000 +++ b/pidgin/gtkutils.c Tue Apr 24 03:57:07 2007 +0000 @@ -78,12 +78,12 @@ } static GtkIMHtmlFuncs gtkimhtml_cbs = { - (GtkIMHtmlGetImageFunc)purple_imgstore_get, + (GtkIMHtmlGetImageFunc)purple_imgstore_find_by_id, (GtkIMHtmlGetImageDataFunc)purple_imgstore_get_data, (GtkIMHtmlGetImageSizeFunc)purple_imgstore_get_size, (GtkIMHtmlGetImageFilenameFunc)purple_imgstore_get_filename, - purple_imgstore_ref, - purple_imgstore_unref, + purple_imgstore_ref_by_id, + purple_imgstore_unref_by_id, }; void @@ -1350,13 +1350,13 @@ return; } - id = purple_imgstore_add(filedata, size, data->filename); + id = purple_imgstore_add_with_id(filedata, size, data->filename); g_free(filedata); gtk_text_buffer_get_iter_at_mark(GTK_IMHTML(gtkconv->entry)->text_buffer, &iter, gtk_text_buffer_get_insert(GTK_IMHTML(gtkconv->entry)->text_buffer)); gtk_imhtml_insert_image_at_iter(GTK_IMHTML(gtkconv->entry), id, &iter); - purple_imgstore_unref(id); + purple_imgstore_unref_by_id(id); break; }