| 76 { |
76 { |
| 77 g_idle_add(url_clicked_idle_cb, g_strdup(uri)); |
77 g_idle_add(url_clicked_idle_cb, g_strdup(uri)); |
| 78 } |
78 } |
| 79 |
79 |
| 80 static GtkIMHtmlFuncs gtkimhtml_cbs = { |
80 static GtkIMHtmlFuncs gtkimhtml_cbs = { |
| 81 (GtkIMHtmlGetImageFunc)purple_imgstore_get, |
81 (GtkIMHtmlGetImageFunc)purple_imgstore_find_by_id, |
| 82 (GtkIMHtmlGetImageDataFunc)purple_imgstore_get_data, |
82 (GtkIMHtmlGetImageDataFunc)purple_imgstore_get_data, |
| 83 (GtkIMHtmlGetImageSizeFunc)purple_imgstore_get_size, |
83 (GtkIMHtmlGetImageSizeFunc)purple_imgstore_get_size, |
| 84 (GtkIMHtmlGetImageFilenameFunc)purple_imgstore_get_filename, |
84 (GtkIMHtmlGetImageFilenameFunc)purple_imgstore_get_filename, |
| 85 purple_imgstore_ref, |
85 purple_imgstore_ref_by_id, |
| 86 purple_imgstore_unref, |
86 purple_imgstore_unref_by_id, |
| 87 }; |
87 }; |
| 88 |
88 |
| 89 void |
89 void |
| 90 pidgin_setup_imhtml(GtkWidget *imhtml) |
90 pidgin_setup_imhtml(GtkWidget *imhtml) |
| 91 { |
91 { |
| 1348 g_error_free(err); |
1348 g_error_free(err); |
| 1349 g_free(str); |
1349 g_free(str); |
| 1350 |
1350 |
| 1351 return; |
1351 return; |
| 1352 } |
1352 } |
| 1353 id = purple_imgstore_add(filedata, size, data->filename); |
1353 id = purple_imgstore_add_with_id(filedata, size, data->filename); |
| 1354 g_free(filedata); |
|
| 1355 |
1354 |
| 1356 gtk_text_buffer_get_iter_at_mark(GTK_IMHTML(gtkconv->entry)->text_buffer, &iter, |
1355 gtk_text_buffer_get_iter_at_mark(GTK_IMHTML(gtkconv->entry)->text_buffer, &iter, |
| 1357 gtk_text_buffer_get_insert(GTK_IMHTML(gtkconv->entry)->text_buffer)); |
1356 gtk_text_buffer_get_insert(GTK_IMHTML(gtkconv->entry)->text_buffer)); |
| 1358 gtk_imhtml_insert_image_at_iter(GTK_IMHTML(gtkconv->entry), id, &iter); |
1357 gtk_imhtml_insert_image_at_iter(GTK_IMHTML(gtkconv->entry), id, &iter); |
| 1359 purple_imgstore_unref(id); |
1358 purple_imgstore_unref_by_id(id); |
| 1360 |
1359 |
| 1361 break; |
1360 break; |
| 1362 } |
1361 } |
| 1363 free(data->filename); |
1362 free(data->filename); |
| 1364 free(data->who); |
1363 free(data->who); |
| 2416 return TRUE; |
2415 return TRUE; |
| 2417 return FALSE; |
2416 return FALSE; |
| 2418 } |
2417 } |
| 2419 #endif |
2418 #endif |
| 2420 |
2419 |
| 2421 char * |
2420 gpointer |
| 2422 pidgin_convert_buddy_icon(PurplePlugin *plugin, const char *path) |
2421 pidgin_convert_buddy_icon(PurplePlugin *plugin, const char *path, size_t *len) |
| 2423 { |
2422 { |
| 2424 PurplePluginProtocolInfo *prpl_info; |
2423 PurplePluginProtocolInfo *prpl_info; |
| 2425 #if GTK_CHECK_VERSION(2,2,0) |
2424 #if GTK_CHECK_VERSION(2,2,0) |
| 2426 char **prpl_formats; |
2425 char **prpl_formats; |
| 2427 int width, height; |
2426 int width, height; |
| 2428 char **pixbuf_formats = NULL; |
2427 char **pixbuf_formats = NULL; |
| 2429 struct stat st; |
|
| 2430 GdkPixbufFormat *format; |
2428 GdkPixbufFormat *format; |
| 2431 GdkPixbuf *pixbuf; |
2429 GdkPixbuf *pixbuf; |
| 2432 #if !GTK_CHECK_VERSION(2,4,0) |
2430 #if !GTK_CHECK_VERSION(2,4,0) |
| 2433 GdkPixbufLoader *loader; |
2431 GdkPixbufLoader *loader; |
| 2434 #endif |
2432 #endif |
| 2435 #endif |
2433 #endif |
| 2436 gchar *contents; |
2434 gchar *contents; |
| 2437 gsize length; |
2435 gsize length; |
| 2438 const char *dirname; |
|
| 2439 char *random; |
|
| 2440 char *filename; |
|
| 2441 |
2436 |
| 2442 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(plugin); |
2437 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(plugin); |
| 2443 |
2438 |
| 2444 g_return_val_if_fail(prpl_info->icon_spec.format != NULL, NULL); |
2439 g_return_val_if_fail(prpl_info->icon_spec.format != NULL, NULL); |
| 2445 |
2440 |
| 2446 dirname = purple_buddy_icons_get_cache_dir(); |
|
| 2447 if (!g_file_test(dirname, G_FILE_TEST_IS_DIR)) { |
|
| 2448 purple_debug_info("buddyicon", "Creating icon cache directory.\n"); |
|
| 2449 |
|
| 2450 if (g_mkdir(dirname, S_IRUSR | S_IWUSR | S_IXUSR) < 0) { |
|
| 2451 purple_debug_error("buddyicon", |
|
| 2452 "Unable to create directory %s: %s\n", |
|
| 2453 dirname, strerror(errno)); |
|
| 2454 return NULL; |
|
| 2455 } |
|
| 2456 } |
|
| 2457 |
|
| 2458 random = g_strdup_printf("%x", g_random_int()); |
|
| 2459 filename = g_build_filename(dirname, random, NULL); |
|
| 2460 |
2441 |
| 2461 #if GTK_CHECK_VERSION(2,2,0) |
2442 #if GTK_CHECK_VERSION(2,2,0) |
| 2462 #if GTK_CHECK_VERSION(2,4,0) |
2443 #if GTK_CHECK_VERSION(2,4,0) |
| 2463 format = gdk_pixbuf_get_file_info(path, &width, &height); |
2444 format = gdk_pixbuf_get_file_info(path, &width, &height); |
| 2464 #else |
2445 #else |
| 2485 prpl_info->icon_spec.max_width >= width && |
2466 prpl_info->icon_spec.max_width >= width && |
| 2486 prpl_info->icon_spec.min_height <= height && |
2467 prpl_info->icon_spec.min_height <= height && |
| 2487 prpl_info->icon_spec.max_height >= height))) /* The icon is the correct size */ |
2468 prpl_info->icon_spec.max_height >= height))) /* The icon is the correct size */ |
| 2488 #endif |
2469 #endif |
| 2489 { |
2470 { |
| 2490 FILE *image; |
|
| 2491 |
|
| 2492 #if GTK_CHECK_VERSION(2,2,0) |
2471 #if GTK_CHECK_VERSION(2,2,0) |
| 2493 g_strfreev(prpl_formats); |
2472 g_strfreev(prpl_formats); |
| 2494 g_strfreev(pixbuf_formats); |
2473 g_strfreev(pixbuf_formats); |
| 2495 #endif |
2474 #endif |
| 2496 |
2475 /* We don't need to scale the image. */ |
| 2497 /* We don't need to scale the image, so copy it to the cache folder verbatim */ |
|
| 2498 |
2476 |
| 2499 contents = NULL; |
2477 contents = NULL; |
| 2500 if (!g_file_get_contents(path, &contents, &length, NULL) || |
2478 if (!g_file_get_contents(path, &contents, &length, NULL)) |
| 2501 (image = g_fopen(filename, "wb")) == NULL) |
|
| 2502 { |
2479 { |
| 2503 g_free(random); |
|
| 2504 g_free(filename); |
|
| 2505 g_free(contents); |
2480 g_free(contents); |
| 2506 #if GTK_CHECK_VERSION(2,2,0) && !GTK_CHECK_VERSION(2,4,0) |
|
| 2507 g_object_unref(G_OBJECT(pixbuf)); |
|
| 2508 #endif |
|
| 2509 return NULL; |
|
| 2510 } |
|
| 2511 |
|
| 2512 if (fwrite(contents, 1, length, image) != length) |
|
| 2513 { |
|
| 2514 fclose(image); |
|
| 2515 g_unlink(filename); |
|
| 2516 |
|
| 2517 g_free(random); |
|
| 2518 g_free(filename); |
|
| 2519 g_free(contents); |
|
| 2520 #if GTK_CHECK_VERSION(2,2,0) && !GTK_CHECK_VERSION(2,4,0) |
|
| 2521 g_object_unref(G_OBJECT(pixbuf)); |
|
| 2522 #endif |
|
| 2523 return NULL; |
|
| 2524 } |
|
| 2525 fclose(image); |
|
| 2526 g_free(contents); |
|
| 2527 |
|
| 2528 #if GTK_CHECK_VERSION(2,2,0) && !GTK_CHECK_VERSION(2,4,0) |
2481 #if GTK_CHECK_VERSION(2,2,0) && !GTK_CHECK_VERSION(2,4,0) |
| 2529 g_object_unref(G_OBJECT(pixbuf)); |
2482 g_object_unref(G_OBJECT(pixbuf)); |
| 2530 #endif |
2483 #endif |
| |
2484 return NULL; |
| |
2485 } |
| 2531 } |
2486 } |
| 2532 #if GTK_CHECK_VERSION(2,2,0) |
2487 #if GTK_CHECK_VERSION(2,2,0) |
| 2533 else |
2488 else |
| 2534 { |
2489 { |
| 2535 int i; |
2490 int i; |
| 2536 GError *error = NULL; |
2491 GError *error = NULL; |
| 2537 GdkPixbuf *scale; |
2492 GdkPixbuf *scale; |
| 2538 gboolean success = FALSE; |
2493 gboolean success = FALSE; |
| |
2494 char *filename = NULL; |
| 2539 |
2495 |
| 2540 g_strfreev(pixbuf_formats); |
2496 g_strfreev(pixbuf_formats); |
| 2541 |
2497 |
| 2542 pixbuf = gdk_pixbuf_new_from_file(path, &error); |
2498 pixbuf = gdk_pixbuf_new_from_file(path, &error); |
| 2543 if (error) { |
2499 if (error) { |
| 2544 purple_debug_error("buddyicon", "Could not open icon for conversion: %s\n", error->message); |
2500 purple_debug_error("buddyicon", "Could not open icon for conversion: %s\n", error->message); |
| 2545 g_error_free(error); |
2501 g_error_free(error); |
| 2546 g_free(random); |
|
| 2547 g_free(filename); |
|
| 2548 g_strfreev(prpl_formats); |
2502 g_strfreev(prpl_formats); |
| 2549 return NULL; |
2503 return NULL; |
| 2550 } |
2504 } |
| 2551 |
2505 |
| 2552 if ((prpl_info->icon_spec.scale_rules & PURPLE_ICON_SCALE_SEND) && |
2506 if ((prpl_info->icon_spec.scale_rules & PURPLE_ICON_SCALE_SEND) && |
| 2565 g_object_unref(G_OBJECT(pixbuf)); |
2519 g_object_unref(G_OBJECT(pixbuf)); |
| 2566 pixbuf = scale; |
2520 pixbuf = scale; |
| 2567 } |
2521 } |
| 2568 |
2522 |
| 2569 for (i = 0; prpl_formats[i]; i++) { |
2523 for (i = 0; prpl_formats[i]; i++) { |
| |
2524 FILE *fp; |
| |
2525 |
| |
2526 g_free(filename); |
| |
2527 fp = purple_mkstemp(&filename, TRUE); |
| |
2528 if (!fp) |
| |
2529 { |
| |
2530 g_free(filename); |
| |
2531 return NULL; |
| |
2532 } |
| |
2533 fclose(fp); |
| |
2534 |
| 2570 purple_debug_info("buddyicon", "Converting buddy icon to %s as %s\n", prpl_formats[i], filename); |
2535 purple_debug_info("buddyicon", "Converting buddy icon to %s as %s\n", prpl_formats[i], filename); |
| 2571 /* The "compression" param wasn't supported until gdk-pixbuf 2.8. |
2536 /* The "compression" param wasn't supported until gdk-pixbuf 2.8. |
| 2572 * Using it in previous versions causes the save to fail (and an assert message). */ |
2537 * Using it in previous versions causes the save to fail (and an assert message). */ |
| 2573 if ((gdk_pixbuf_major_version > 2 || (gdk_pixbuf_major_version == 2 |
2538 if ((gdk_pixbuf_major_version > 2 || (gdk_pixbuf_major_version == 2 |
| 2574 && gdk_pixbuf_minor_version >= 8)) |
2539 && gdk_pixbuf_minor_version >= 8)) |
| 2593 } |
2558 } |
| 2594 g_strfreev(prpl_formats); |
2559 g_strfreev(prpl_formats); |
| 2595 g_object_unref(G_OBJECT(pixbuf)); |
2560 g_object_unref(G_OBJECT(pixbuf)); |
| 2596 if (!success) { |
2561 if (!success) { |
| 2597 purple_debug_error("buddyicon", "Could not convert icon to usable format.\n"); |
2562 purple_debug_error("buddyicon", "Could not convert icon to usable format.\n"); |
| 2598 g_free(random); |
2563 return NULL; |
| |
2564 } |
| |
2565 |
| |
2566 contents = NULL; |
| |
2567 if (!g_file_get_contents(filename, &contents, &length, NULL)) |
| |
2568 { |
| |
2569 purple_debug_error("buddyicon", |
| |
2570 "Could not read '%s', which we just wrote to disk.\n", |
| |
2571 filename); |
| |
2572 |
| |
2573 g_free(contents); |
| 2599 g_free(filename); |
2574 g_free(filename); |
| 2600 return NULL; |
2575 return NULL; |
| 2601 } |
2576 } |
| 2602 } |
2577 |
| 2603 |
2578 g_unlink(filename); |
| 2604 if (g_stat(filename, &st) != 0) { |
|
| 2605 purple_debug_error("buddyicon", |
|
| 2606 "Could not stat '%s', which we just wrote to disk: %s\n", |
|
| 2607 filename, strerror(errno)); |
|
| 2608 g_free(random); |
|
| 2609 g_free(filename); |
2579 g_free(filename); |
| 2610 return NULL; |
2580 } |
| 2611 } |
2581 |
| 2612 |
2582 /* Check the image size */ |
| 2613 /* Check the file size */ |
|
| 2614 /* |
2583 /* |
| 2615 * TODO: If the file is too big, it would be cool if we checked if |
2584 * TODO: If the file is too big, it would be cool if we checked if |
| 2616 * the prpl supported jpeg, and then we could convert to that |
2585 * the prpl supported jpeg, and then we could convert to that |
| 2617 * and use a lower quality setting. |
2586 * and use a lower quality setting. |
| 2618 */ |
2587 */ |
| 2619 if ((prpl_info->icon_spec.max_filesize != 0) && |
2588 if ((prpl_info->icon_spec.max_filesize != 0) && |
| 2620 (st.st_size > prpl_info->icon_spec.max_filesize)) |
2589 (length > prpl_info->icon_spec.max_filesize)) |
| 2621 { |
2590 { |
| 2622 gchar *tmp; |
2591 gchar *tmp; |
| 2623 tmp = g_strdup_printf(_("The file '%s' is too large for %s. Please try a smaller image.\n"), |
2592 tmp = g_strdup_printf(_("The file '%s' is too large for %s. Please try a smaller image.\n"), |
| 2624 path, plugin->info->name); |
2593 path, plugin->info->name); |
| 2625 purple_notify_error(NULL, _("Icon Error"), |
2594 purple_notify_error(NULL, _("Icon Error"), |
| 2626 _("Could not set icon"), tmp); |
2595 _("Could not set icon"), tmp); |
| 2627 purple_debug_info("buddyicon", |
2596 purple_debug_info("buddyicon", |
| 2628 "'%s' was converted to an image which is %" G_GSIZE_FORMAT |
2597 "'%s' was converted to an image which is %" G_GSIZE_FORMAT |
| 2629 " bytes, but the maximum icon size for %s is %" G_GSIZE_FORMAT |
2598 " bytes, but the maximum icon size for %s is %" G_GSIZE_FORMAT |
| 2630 " bytes\n", path, st.st_size, plugin->info->name, |
2599 " bytes\n", path, length, plugin->info->name, |
| 2631 prpl_info->icon_spec.max_filesize); |
2600 prpl_info->icon_spec.max_filesize); |
| 2632 g_free(tmp); |
2601 g_free(tmp); |
| 2633 g_free(random); |
|
| 2634 g_free(filename); |
|
| 2635 return NULL; |
2602 return NULL; |
| 2636 } |
2603 } |
| 2637 |
2604 |
| 2638 g_free(filename); |
2605 if (len) |
| 2639 return random; |
2606 *len = length; |
| |
2607 return contents; |
| 2640 #else |
2608 #else |
| 2641 /* |
2609 /* |
| 2642 * The chosen icon wasn't the right size, and we're using |
2610 * The chosen icon wasn't the right size, and we're using |
| 2643 * GTK+ 2.0 so we can't scale it. |
2611 * GTK+ 2.0 so we can't scale it. |
| 2644 */ |
2612 */ |
| 2787 } |
2755 } |
| 2788 #endif /* ! Gtk 2.6.0 */ |
2756 #endif /* ! Gtk 2.6.0 */ |
| 2789 |
2757 |
| 2790 void pidgin_set_custom_buddy_icon(PurpleAccount *account, const char *who, const char *filename) |
2758 void pidgin_set_custom_buddy_icon(PurpleAccount *account, const char *who, const char *filename) |
| 2791 { |
2759 { |
| 2792 PurpleConversation *conv; |
|
| 2793 PurpleBuddy *buddy; |
2760 PurpleBuddy *buddy; |
| 2794 PurpleBlistNode *node; |
2761 PurpleContact *contact; |
| 2795 char *path = NULL; |
2762 gpointer data = NULL; |
| |
2763 size_t len = 0; |
| 2796 |
2764 |
| 2797 buddy = purple_find_buddy(account, who); |
2765 buddy = purple_find_buddy(account, who); |
| 2798 if (!buddy) { |
2766 if (!buddy) { |
| 2799 purple_debug_info("custom-icon", "You can only set custom icon for someone in your buddylist.\n"); |
2767 purple_debug_info("custom-icon", "You can only set custom icon for someone in your buddylist.\n"); |
| 2800 return; |
2768 return; |
| 2801 } |
2769 } |
| 2802 |
2770 |
| 2803 node = (PurpleBlistNode*)purple_buddy_get_contact(buddy); |
2771 contact = purple_buddy_get_contact(buddy); |
| 2804 path = (char*)purple_blist_node_get_string(node, "custom_buddy_icon"); |
|
| 2805 if (path) { |
|
| 2806 struct stat st; |
|
| 2807 if (g_stat(path, &st) == 0) |
|
| 2808 g_unlink(path); |
|
| 2809 path = NULL; |
|
| 2810 } |
|
| 2811 |
2772 |
| 2812 if (filename) { |
2773 if (filename) { |
| 2813 char *newfile; |
2774 const char *prpl_id = purple_account_get_protocol_id(account); |
| 2814 |
2775 PurplePlugin *prpl = purple_find_prpl(prpl_id); |
| 2815 newfile = pidgin_convert_buddy_icon(purple_find_prpl(purple_account_get_protocol_id(account)), |
2776 |
| 2816 filename); |
2777 data = pidgin_convert_buddy_icon(prpl, filename, &len); |
| 2817 path = purple_buddy_icons_get_full_path(newfile); |
2778 |
| 2818 g_free(newfile); |
2779 /* We don't want to delete the old icon if the new one didn't load. */ |
| 2819 } |
2780 if (data == NULL) |
| 2820 |
2781 return; |
| 2821 purple_blist_node_set_string(node, "custom_buddy_icon", path); |
2782 } |
| 2822 g_free(path); |
2783 |
| 2823 |
2784 purple_buddy_icons_set_custom_icon(contact, data, len); |
| 2824 /* Update the conversation */ |
|
| 2825 conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, who, account); |
|
| 2826 if (conv) |
|
| 2827 purple_conversation_update(conv, PURPLE_CONV_UPDATE_ICON); |
|
| 2828 |
|
| 2829 /* Update the buddylist */ |
|
| 2830 if (buddy) |
|
| 2831 purple_blist_update_buddy_icon(buddy); |
|
| 2832 } |
2785 } |
| 2833 |
2786 |
| 2834 char *pidgin_make_pretty_arrows(const char *str) |
2787 char *pidgin_make_pretty_arrows(const char *str) |
| 2835 { |
2788 { |
| 2836 char *ret; |
2789 char *ret; |