# HG changeset patch # User Richard Laager # Date 1177434022 0 # Node ID 72dc611f32577c685da9200585e36425fcd02eb5 # Parent 6c97924af83b9e03f21702cb145e67d3b54e847b Fix the custom icon stuff, and various memory leaks. At this point, custom icons work properly, EXCEPT FOR A SERIOUS LEAK which I haven't fixed yet because I'm seeing weird memory allocation issues. Once I deal with that, it's just the account icon stuff that's left. diff -r 6c97924af83b -r 72dc611f3257 libpurple/buddyicon.c --- a/libpurple/buddyicon.c Tue Apr 24 16:20:01 2007 +0000 +++ b/libpurple/buddyicon.c Tue Apr 24 17:00:22 2007 +0000 @@ -567,6 +567,7 @@ icon->ref_count = 0; icon->img = NULL; purple_buddy_icon_set_data(icon, data, len); + g_free(data); } g_free(path); } @@ -614,6 +615,7 @@ { g_free(path); img = purple_buddy_icon_data_new(data, len, custom_icon_file); + g_free(data); g_hash_table_insert(custom_icon_cache, contact, img); return img; } @@ -629,6 +631,7 @@ PurpleStoredImage *old_img; PurpleStoredImage *img = NULL; char *old_icon; + PurpleBlistNode *child; old_img = g_hash_table_lookup(custom_icon_cache, contact); @@ -653,8 +656,27 @@ unref_filename(old_icon); g_free(old_icon); + g_hash_table_insert(custom_icon_cache, contact, img); - g_hash_table_insert(custom_icon_cache, contact, img); + for (child = contact->node.child ; child ; child = child->next) + { + PurpleBuddy *buddy; + PurpleConversation *conv; + + if (!PURPLE_BLIST_NODE_IS_BUDDY(child)) + continue; + + buddy = (PurpleBuddy *)child; + + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, + purple_buddy_get_name(buddy), + purple_buddy_get_account(buddy)); + if (conv) + purple_conversation_update(conv, PURPLE_CONV_UPDATE_ICON); + + purple_blist_update_buddy_icon(buddy); + } + purple_imgstore_unref(old_img); } @@ -787,11 +809,13 @@ } else { + char *path = g_build_filename(dirname, filename, NULL); if (!g_file_test(filename, G_FILE_TEST_EXISTS)) { purple_blist_node_remove_setting(node, "buddy_icon"); } + g_free(path); ref_filename(filename); } } @@ -811,11 +835,13 @@ } else { - if (!g_file_test(filename, G_FILE_TEST_EXISTS)) + char *path = g_build_filename(dirname, filename, NULL); + if (!g_file_test(path, G_FILE_TEST_EXISTS)) { purple_blist_node_remove_setting(node, "custom_buddy_icon"); } + g_free(path); ref_filename(filename); } } diff -r 6c97924af83b -r 72dc611f3257 libpurple/imgstore.c --- a/libpurple/imgstore.c Tue Apr 24 16:20:01 2007 +0000 +++ b/libpurple/imgstore.c Tue Apr 24 17:00:22 2007 +0000 @@ -55,7 +55,7 @@ g_return_val_if_fail(data != NULL, 0); g_return_val_if_fail(size > 0, 0); - img = g_slice_new(PurpleStoredImage); + img = g_new(PurpleStoredImage, 1); img->data = g_memdup(data, size); img->size = size; img->filename = g_strdup(filename); @@ -146,10 +146,12 @@ { purple_signal_emit(purple_imgstore_get_handle(), "image-deleting", img); - if (img->id) g_hash_table_remove(imgstore, GINT_TO_POINTER(img->id)); - g_slice_free(PurpleStoredImage, img); + + g_free(img->data); + g_free(img->filename); + g_free(img); } return img; diff -r 6c97924af83b -r 72dc611f3257 pidgin/gtkaccount.c --- a/pidgin/gtkaccount.c Tue Apr 24 16:20:01 2007 +0000 +++ b/pidgin/gtkaccount.c Tue Apr 24 17:00:22 2007 +0000 @@ -302,8 +302,10 @@ dialog = data; +#if 0 if (filename != NULL) set_dialog_icon(dialog, pidgin_convert_buddy_icon(dialog->plugin, filename), g_strdup(filename)); +#endif dialog->icon_filesel = NULL; } @@ -342,7 +344,9 @@ } if ((rtmp = strchr(tmp, '\r')) || (rtmp = strchr(tmp, '\n'))) *rtmp = '\0'; +#if 0 set_dialog_icon(dialog, pidgin_convert_buddy_icon(dialog->plugin, tmp), g_strdup(tmp)); +#endif g_free(tmp); } gtk_drag_finish(dc, TRUE, FALSE, t); @@ -1159,10 +1163,12 @@ else if (purple_prefs_get_path(PIDGIN_PREFS_ROOT "/accounts/buddyicon") && icon_change) { const char *filename = purple_prefs_get_path(PIDGIN_PREFS_ROOT "/accounts/buddyicon"); +#if 0 char *icon = pidgin_convert_buddy_icon(dialog->plugin, filename); purple_account_set_buddy_icon_path(account, filename); purple_account_set_buddy_icon(account, icon); g_free(icon); +#endif } } diff -r 6c97924af83b -r 72dc611f3257 pidgin/gtkblist.c --- a/pidgin/gtkblist.c Tue Apr 24 16:20:01 2007 +0000 +++ b/pidgin/gtkblist.c Tue Apr 24 17:00:22 2007 +0000 @@ -2204,6 +2204,8 @@ if (!(icon = purple_buddy_icons_find(buddy->account, buddy->name))) /* Not sure I like this...*/ return NULL; data = purple_buddy_icon_get_data(icon, &len); + if (data == NULL) + return NULL; } } @@ -2213,14 +2215,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)); + // TODO: FIX THIS!!! + //purple_imgstore_unref(custom_img); + if (buf) { int orig_width, orig_height; int scale_width, scale_height; diff -r 6c97924af83b -r 72dc611f3257 pidgin/gtkconv.c --- a/pidgin/gtkconv.c Tue Apr 24 16:20:01 2007 +0000 +++ b/pidgin/gtkconv.c Tue Apr 24 17:00:22 2007 +0000 @@ -2482,23 +2482,6 @@ fclose(fp); } -static const char * -custom_icon_pref_name(PidginConversation *gtkconv) -{ - PurpleConversation *conv; - PurpleAccount *account; - PurpleBuddy *buddy; - - conv = gtkconv->active_conv; - account = purple_conversation_get_account(conv); - buddy = purple_find_buddy(account, purple_conversation_get_name(conv)); - if (buddy) { - PurpleContact *contact = purple_buddy_get_contact(buddy); - return purple_blist_node_get_string((PurpleBlistNode*)contact, "custom_buddy_icon"); - } - return NULL; -} - static void custom_icon_sel_cb(const char *filename, gpointer data) { @@ -2574,7 +2557,8 @@ icon_menu(GtkObject *obj, GdkEventButton *e, PidginConversation *gtkconv) { static GtkWidget *menu = NULL; - const char *pref; + PurpleConversation *conv; + PurpleBuddy *buddy; if (e->button != 3 || e->type != GDK_BUTTON_PRESS) return FALSE; @@ -2608,11 +2592,18 @@ 0, 0, NULL); /* Is there a custom icon for this person? */ - pref = custom_icon_pref_name(gtkconv); - if (pref && *pref) { - pidgin_new_item_from_stock(menu, _("Remove Custom Icon"), NULL, - G_CALLBACK(remove_custom_icon_cb), gtkconv, - 0, 0, NULL); + conv = gtkconv->active_conv; + buddy = purple_find_buddy(purple_conversation_get_account(conv), + purple_conversation_get_name(conv)); + if (buddy) + { + PurpleContact *contact = purple_buddy_get_contact(buddy); + if (contact && purple_buddy_icons_has_custom_icon(contact)) + { + pidgin_new_item_from_stock(menu, _("Remove Custom Icon"), NULL, + G_CALLBACK(remove_custom_icon_cb), gtkconv, + 0, 0, NULL); + } } gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, e->button, e->time); @@ -6175,12 +6166,14 @@ PidginConversation *gtkconv; PidginWindow *win; + PurpleBuddy *buddy; + GdkPixbufLoader *loader; GdkPixbufAnimation *anim; GError *err = NULL; - const char *custom = NULL; - const void *data = NULL; + PurpleStoredImage *custom_img = NULL; + gconstpointer data = NULL; size_t len; GdkPixbuf *buf; @@ -6237,17 +6230,18 @@ if (purple_conversation_get_gc(conv) == NULL) return; - custom = custom_icon_pref_name(gtkconv); - if (custom) { - /* There is a custom icon for this user */ - char *contents = NULL; - if (!g_file_get_contents(custom, &contents, &len, &err)) { - purple_debug_warning("custom icon", "could not load custom icon %s for %s\n", - custom, purple_conversation_get_name(conv)); - g_error_free(err); - err = NULL; - } else - data = contents; + buddy = purple_find_buddy(account, purple_conversation_get_name(conv)); + if (buddy) + { + PurpleContact *contact = purple_buddy_get_contact(buddy); + if (contact) { + custom_img = purple_buddy_icons_find_custom_icon(contact); + if (custom_img) { + /* There is a custom icon for this user */ + data = purple_imgstore_get_data(custom_img); + len = purple_imgstore_get_size(custom_img); + } + } } if (data == NULL) { @@ -6257,7 +6251,9 @@ return; data = purple_buddy_icon_get_data(icon, &len); - custom = NULL; + + if (data == NULL) + return; } loader = gdk_pixbuf_loader_new(); @@ -6268,8 +6264,8 @@ g_object_ref(G_OBJECT(anim)); g_object_unref(loader); - if (custom) - g_free((void*)data); + // TODO: FIX THIS!!! + //purple_imgstore_unref(custom_img); if (!anim) return; @@ -6281,9 +6277,6 @@ g_error_free(err); } - if (!gtkconv->u.im->anim) - return; - if (gdk_pixbuf_animation_is_static_image(gtkconv->u.im->anim)) { gtkconv->u.im->iter = NULL; buf = gdk_pixbuf_animation_get_static_image(gtkconv->u.im->anim); diff -r 6c97924af83b -r 72dc611f3257 pidgin/gtkmain.c --- a/pidgin/gtkmain.c Tue Apr 24 16:20:01 2007 +0000 +++ b/pidgin/gtkmain.c Tue Apr 24 17:00:22 2007 +0000 @@ -678,7 +678,7 @@ char *old = g_strconcat(purple_home_dir(), G_DIR_SEPARATOR_S ".gaim", NULL); const char *text = _( - "Pidgin encountered errors migrating your settings " + "%s encountered errors migrating your settings " "from %s to %s. Please investigate and complete the " "migration by hand."); GtkWidget *dialog; @@ -687,7 +687,8 @@ 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, - text, old, purple_user_dir()); + text, PIDGIN_NAME, + old, purple_user_dir()); g_free(old); g_signal_connect_swapped(dialog, "response", diff -r 6c97924af83b -r 72dc611f3257 pidgin/gtkstatusbox.c --- a/pidgin/gtkstatusbox.c Tue Apr 24 16:20:01 2007 +0000 +++ b/pidgin/gtkstatusbox.c Tue Apr 24 17:00:22 2007 +0000 @@ -1439,8 +1439,10 @@ PurplePluginProtocolInfo *prplinfo = PURPLE_PLUGIN_PROTOCOL_INFO(plug); if (prplinfo && prplinfo->icon_spec.format) { char *icon = NULL; +#if 0 if (filename) icon = pidgin_convert_buddy_icon(plug, filename); +#endif purple_account_set_bool(box->account, "use-global-buddyicon", (filename != NULL)); purple_account_set_ui_string(box->account, PIDGIN_UI, "non-global-buddyicon-cached-path", icon); purple_account_set_buddy_icon_path(box->account, filename); @@ -1459,8 +1461,10 @@ purple_account_get_bool(account, "use-global-buddyicon", TRUE) && prplinfo->icon_spec.format) { char *icon = NULL; +#if 0 if (filename) icon = pidgin_convert_buddy_icon(plug, filename); +#endif purple_account_set_buddy_icon_path(account, filename); purple_account_set_buddy_icon(account, icon); g_free(icon); diff -r 6c97924af83b -r 72dc611f3257 pidgin/gtkutils.c --- a/pidgin/gtkutils.c Tue Apr 24 16:20:01 2007 +0000 +++ b/pidgin/gtkutils.c Tue Apr 24 17:00:22 2007 +0000 @@ -2409,15 +2409,14 @@ } #endif -char * -pidgin_convert_buddy_icon(PurplePlugin *plugin, const char *path) +gpointer +pidgin_convert_buddy_icon(PurplePlugin *plugin, const char *path, size_t *len) { PurplePluginProtocolInfo *prpl_info; #if GTK_CHECK_VERSION(2,2,0) char **prpl_formats; int width, height; char **pixbuf_formats = NULL; - struct stat st; GdkPixbufFormat *format; GdkPixbuf *pixbuf; #if !GTK_CHECK_VERSION(2,4,0) @@ -2426,28 +2425,11 @@ #endif gchar *contents; gsize length; - const char *dirname; - char *random; - char *filename; prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(plugin); g_return_val_if_fail(prpl_info->icon_spec.format != NULL, NULL); - dirname = purple_buddy_icons_get_cache_dir(); - if (!g_file_test(dirname, G_FILE_TEST_IS_DIR)) { - purple_debug_info("buddyicon", "Creating icon cache directory.\n"); - - if (g_mkdir(dirname, S_IRUSR | S_IWUSR | S_IXUSR) < 0) { - purple_debug_error("buddyicon", - "Unable to create directory %s: %s\n", - dirname, strerror(errno)); - return NULL; - } - } - - random = g_strdup_printf("%x", g_random_int()); - filename = g_build_filename(dirname, random, NULL); #if GTK_CHECK_VERSION(2,2,0) #if GTK_CHECK_VERSION(2,4,0) @@ -2478,47 +2460,21 @@ prpl_info->icon_spec.max_height >= height))) /* The icon is the correct size */ #endif { - FILE *image; - #if GTK_CHECK_VERSION(2,2,0) g_strfreev(prpl_formats); g_strfreev(pixbuf_formats); #endif - - /* We don't need to scale the image, so copy it to the cache folder verbatim */ + /* We don't need to scale the image. */ contents = NULL; - if (!g_file_get_contents(path, &contents, &length, NULL) || - (image = g_fopen(filename, "wb")) == NULL) + if (!g_file_get_contents(path, &contents, &length, NULL)) { - g_free(random); - g_free(filename); g_free(contents); #if GTK_CHECK_VERSION(2,2,0) && !GTK_CHECK_VERSION(2,4,0) - g_object_unref(G_OBJECT(pixbuf)); + g_object_unref(G_OBJECT(pixbuf)); #endif return NULL; } - - if (fwrite(contents, 1, length, image) != length) - { - fclose(image); - g_unlink(filename); - - g_free(random); - g_free(filename); - g_free(contents); -#if GTK_CHECK_VERSION(2,2,0) && !GTK_CHECK_VERSION(2,4,0) - g_object_unref(G_OBJECT(pixbuf)); -#endif - return NULL; - } - fclose(image); - g_free(contents); - -#if GTK_CHECK_VERSION(2,2,0) && !GTK_CHECK_VERSION(2,4,0) - g_object_unref(G_OBJECT(pixbuf)); -#endif } #if GTK_CHECK_VERSION(2,2,0) else @@ -2527,6 +2483,7 @@ GError *error = NULL; GdkPixbuf *scale; gboolean success = FALSE; + char *filename = NULL; g_strfreev(pixbuf_formats); @@ -2534,8 +2491,6 @@ if (error) { purple_debug_error("buddyicon", "Could not open icon for conversion: %s\n", error->message); g_error_free(error); - g_free(random); - g_free(filename); g_strfreev(prpl_formats); return NULL; } @@ -2558,6 +2513,17 @@ } for (i = 0; prpl_formats[i]; i++) { + FILE *fp; + + g_free(filename); + fp = purple_mkstemp(&filename, TRUE); + if (!fp) + { + g_free(filename); + return NULL; + } + fclose(fp); + purple_debug_info("buddyicon", "Converting buddy icon to %s as %s\n", prpl_formats[i], filename); /* The "compression" param wasn't supported until gdk-pixbuf 2.8. * Using it in previous versions causes the save to fail (and an assert message). */ @@ -2586,29 +2552,33 @@ g_object_unref(G_OBJECT(pixbuf)); if (!success) { purple_debug_error("buddyicon", "Could not convert icon to usable format.\n"); - g_free(random); + return NULL; + } + + contents = NULL; + if (!g_file_get_contents(filename, &contents, &length, NULL)) + { + purple_debug_error("buddyicon", + "Could not read '%s', which we just wrote to disk.\n", + filename); + + g_free(contents); g_free(filename); return NULL; } + + g_unlink(filename); + g_free(filename); } - if (g_stat(filename, &st) != 0) { - purple_debug_error("buddyicon", - "Could not stat '%s', which we just wrote to disk: %s\n", - filename, strerror(errno)); - g_free(random); - g_free(filename); - return NULL; - } - - /* Check the file size */ + /* Check the image size */ /* * TODO: If the file is too big, it would be cool if we checked if * the prpl supported jpeg, and then we could convert to that * and use a lower quality setting. */ if ((prpl_info->icon_spec.max_filesize != 0) && - (st.st_size > prpl_info->icon_spec.max_filesize)) + (length > prpl_info->icon_spec.max_filesize)) { gchar *tmp; tmp = g_strdup_printf(_("The file '%s' is too large for %s. Please try a smaller image.\n"), @@ -2618,16 +2588,15 @@ purple_debug_info("buddyicon", "'%s' was converted to an image which is %" G_GSIZE_FORMAT " bytes, but the maximum icon size for %s is %" G_GSIZE_FORMAT - " bytes\n", path, st.st_size, plugin->info->name, + " bytes\n", path, length, plugin->info->name, prpl_info->icon_spec.max_filesize); g_free(tmp); - g_free(random); - g_free(filename); return NULL; } - g_free(filename); - return random; + if (len) + *len = length; + return contents; #else /* * The chosen icon wasn't the right size, and we're using @@ -2780,10 +2749,10 @@ void pidgin_set_custom_buddy_icon(PurpleAccount *account, const char *who, const char *filename) { - PurpleConversation *conv; PurpleBuddy *buddy; - PurpleBlistNode *node; - char *path = NULL; + PurpleContact *contact; + gpointer data = NULL; + size_t len = 0; buddy = purple_find_buddy(account, who); if (!buddy) { @@ -2791,35 +2760,20 @@ return; } - node = (PurpleBlistNode*)purple_buddy_get_contact(buddy); - path = (char*)purple_blist_node_get_string(node, "custom_buddy_icon"); - if (path) { - struct stat st; - if (g_stat(path, &st) == 0) - g_unlink(path); - path = NULL; - } + contact = purple_buddy_get_contact(buddy); if (filename) { - char *newfile; - - newfile = pidgin_convert_buddy_icon(purple_find_prpl(purple_account_get_protocol_id(account)), - filename); - path = purple_buddy_icons_get_full_path(newfile); - g_free(newfile); + const char *prpl_id = purple_account_get_protocol_id(account); + PurplePlugin *prpl = purple_find_prpl(prpl_id); + + data = pidgin_convert_buddy_icon(prpl, filename, &len); + + /* We don't want to delete the old icon if the new one didn't load. */ + if (data == NULL) + return; } - purple_blist_node_set_string(node, "custom_buddy_icon", path); - g_free(path); - - /* Update the conversation */ - conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, who, account); - if (conv) - purple_conversation_update(conv, PURPLE_CONV_UPDATE_ICON); - - /* Update the buddylist */ - if (buddy) - purple_blist_update_buddy_icon(buddy); + purple_buddy_icons_set_custom_icon(contact, data, len); } char *pidgin_make_pretty_arrows(const char *str) diff -r 6c97924af83b -r 72dc611f3257 pidgin/gtkutils.h --- a/pidgin/gtkutils.h Tue Apr 24 16:20:01 2007 +0000 +++ b/pidgin/gtkutils.h Tue Apr 24 17:00:22 2007 +0000 @@ -445,11 +445,13 @@ /** * Converts a buddy icon to the required size and format * - * @param plugin The prpl to conver the icon - * @param path The path of a buddy icon to convert - * @return The name of a new buddy icon + * @param plugin The prpl to convert the icon + * @param path The path of a file to convert + * @param len If not @c NULL, the length of the returned data will be set here. + * + * @return The converted image data, or @c NULL if an error occurred. */ -char* pidgin_convert_buddy_icon(PurplePlugin *plugin, const char *path); +gpointer pidgin_convert_buddy_icon(PurplePlugin *plugin, const char *path, size_t *len); #if !GTK_CHECK_VERSION(2,6,0) /**