Mercurial > pidgin.yaz
changeset 8962:4ff4c34b7500
[gaim-migrate @ 9736]
IM Image, WYSIWYG.
It's still somewhat buggy, although the worse problems are with oscar's
direct connect. We could always yank oscar's im image flag if we think it
will cause too many bug reports.
I made the GaimImgstore struct opque.
I modified oscar's sending function to parse im images better, and
everything seems to work. I made it write some errors to the conversation
if you try to send an image and you aren't direct connected. That's just
a hack until you can set formatting flags on a per conversation bases.
There's a scrolling bug I haven't tracked down. I think it may exist
normally and this just causes it better.
It's worth noting jabber also uses this for pics in profiles, although
I never did find a test case. Hopefully some other stuff can use this
soon too, maybe Yahoo! pics in profiles or something.
committer: Tailor Script <tailor@pidgin.im>
author | Tim Ringenbach <marv@pidgin.im> |
---|---|
date | Mon, 17 May 2004 06:47:20 +0000 |
parents | 92e061a1db10 |
children | 59f1eb8c76d2 |
files | ChangeLog src/gtkconv.c src/gtkimhtml.c src/gtkimhtml.h src/gtkimhtmltoolbar.c src/gtknotify.c src/gtkutils.c src/gtkutils.h src/imgstore.c src/imgstore.h src/protocols/oscar/oscar.c |
diffstat | 11 files changed, 282 insertions(+), 236 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog Mon May 17 04:39:14 2004 +0000 +++ b/ChangeLog Mon May 17 06:47:20 2004 +0000 @@ -37,6 +37,8 @@ * New tabs should scroll correctly again (Tim Ringenbach) * Ampersands in links should work right (Tim Ringenbach) * Win32 transparency plugin fixes (Kevin Stange) + * IM Image support for AIM is back. It still depends on Direct + Connect, and both are still as bugger as ever, if not more so. Preference Changes: * Added a "none" smiley theme to replace the "Show graphical
--- a/src/gtkconv.c Mon May 17 04:39:14 2004 +0000 +++ b/src/gtkconv.c Mon May 17 06:47:20 2004 +0000 @@ -334,7 +334,7 @@ return; buf = gtk_imhtml_get_markup(GTK_IMHTML(gtkconv->entry)); - clean = gaim_markup_strip_html(buf); + clean = gtk_imhtml_get_text(GTK_IMHTML(gtkconv->entry), NULL, NULL); gtk_widget_grab_focus(gtkconv->entry); @@ -4532,7 +4532,6 @@ GaimConvWindow *win; GaimConnection *gc; int gtk_font_options = 0; - GSList *images = NULL; char buf[BUF_LONG]; char buf2[BUF_LONG]; char mdate[64]; @@ -4556,9 +4555,6 @@ gaim_conv_window_show(win); } - if (flags & GAIM_MESSAGE_IMAGES) - gaim_gtk_find_images(message, &images); - if (gtk_text_buffer_get_char_count(gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtkconv->imhtml)))) gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), "<BR>", 0); @@ -4595,8 +4591,7 @@ "<FONT %s><FONT SIZE=\"2\"><!--(%s) --></FONT><B>%s</B></FONT>", sml_attrib, mdate, message); - gtk_imhtml_append_text_with_images(GTK_IMHTML(gtkconv->imhtml), - buf2, 0, images); + gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, 0); /* Add the message to a conversations scrollback buffer */ conv->history = g_string_append(conv->history, buf); @@ -4613,9 +4608,8 @@ "<FONT %s><FONT SIZE=\"2\"><!--(%s) --></FONT><B>%s</B></FONT>", sml_attrib, mdate, message); - gtk_imhtml_append_text_with_images(GTK_IMHTML(gtkconv->imhtml), - buf2, 0, images); - + gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, 0); + /* Add the message to a conversations scrollback buffer */ conv->history = g_string_append(conv->history, buf); conv->history = g_string_append(conv->history, "<BR>\n"); @@ -4624,8 +4618,7 @@ "<B><FONT %s COLOR=\"#777777\">%s</FONT></B>", sml_attrib, message); - gtk_imhtml_append_text_with_images(GTK_IMHTML(gtkconv->imhtml), - buf, 0, images); + gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf, 0); } else { char *new_message = g_memdup(message, length); @@ -4706,8 +4699,8 @@ g_free(str); - gtk_imhtml_append_text_with_images(GTK_IMHTML(gtkconv->imhtml), - buf2, 0, images); + gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), + buf2, 0); if(gc){ char *pre = g_strdup_printf("<font %s>", sml_attrib ? sml_attrib : ""); @@ -4727,8 +4720,8 @@ else with_font_tag = g_memdup(new_message, length); - gtk_imhtml_append_text_with_images(GTK_IMHTML(gtkconv->imhtml), - with_font_tag, gtk_font_options, images); + gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), + with_font_tag, gtk_font_options); conv->history = g_string_append(conv->history, buf); conv->history = g_string_append(conv->history, new_message); @@ -4741,18 +4734,6 @@ if(sml_attrib) g_free(sml_attrib); - - if (images) { - GSList *tmp; - - for (tmp = images; tmp; tmp = tmp->next) { - GdkPixbuf *pixbuf = tmp->data; - if(pixbuf) - g_object_unref(pixbuf); - } - - g_slist_free(images); - } } static void
--- a/src/gtkimhtml.c Mon May 17 04:39:14 2004 +0000 +++ b/src/gtkimhtml.c Mon May 17 06:47:20 2004 +0000 @@ -905,6 +905,7 @@ { GtkIMHtml *imhtml = GTK_IMHTML(object); GList *scalables; + GSList *l; g_hash_table_destroy(imhtml->smiley_data); gtk_smiley_tree_destroy(imhtml->default_smilies); @@ -923,12 +924,20 @@ scale->free(scale); } + for (l = imhtml->im_images; l; l = l->next) { + int id; + id = GPOINTER_TO_INT(l->data); + if (imhtml->funcs->image_unref) + imhtml->funcs->image_unref(id); + } + if (imhtml->clipboard_text_string) { g_free(imhtml->clipboard_text_string); g_free(imhtml->clipboard_html_string); } g_list_free(imhtml->scalables); + g_slist_free(imhtml->im_images); G_OBJECT_CLASS(parent_class)->finalize (object); } @@ -2167,34 +2176,18 @@ case 46: /* IMG (opt) */ case 59: /* IMG */ { -#if 0 -/* disabling this for now, it's easy to add it back... */ - GdkPixbuf *img = NULL; - const gchar *filename = NULL; + const char *id; + + gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); + ws[0] = '\0'; wpos = 0; if (!(imhtml->format_functions & GTK_IMHTML_IMAGE)) break; - if (images && images->data) { - img = images->data; - images = images->next; - filename = g_object_get_data(G_OBJECT(img), "filename"); - g_object_ref(G_OBJECT(img)); - } else { - img = gtk_widget_render_icon(GTK_WIDGET(imhtml), - GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_BUTTON, - "gtkimhtml-missing-image"); - } - - scalable = gtk_imhtml_image_new(img, filename); - /* NEW_BIT(NEW_SCALABLE_BIT); */ - gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); - scalable->add_to(scalable, imhtml, iter); - scalable->scale(scalable, rect.width, rect.height); - imhtml->scalables = g_list_append(imhtml->scalables, scalable); - - g_object_unref(G_OBJECT(img)); -#endif + id = gtk_imhtml_get_html_opt(tag, "ID="); + + gtk_imhtml_insert_image_at_iter(imhtml, atoi(id), iter); + break; } case 47: /* P (opt) */ case 48: /* H3 (opt) */ @@ -2486,7 +2479,7 @@ imhtml->smiley_shortcuts = allow; } -void +void gtk_imhtml_set_protocol_name(GtkIMHtml *imhtml, gchar *protocol_name) { imhtml->protocol_name = protocol_name; } @@ -2538,7 +2531,7 @@ } /* GtkIMHtmlScalable, gtk_imhtml_image, gtk_imhtml_hr */ -GtkIMHtmlScalable *gtk_imhtml_image_new(GdkPixbuf *img, const gchar *filename) +GtkIMHtmlScalable *gtk_imhtml_image_new(GdkPixbuf *img, const gchar *filename, int id) { GtkIMHtmlImage *im_image = g_malloc(sizeof(GtkIMHtmlImage)); GtkImage *image = GTK_IMAGE(gtk_image_new_from_pixbuf(img)); @@ -2553,6 +2546,7 @@ im_image->height = gdk_pixbuf_get_height(img); im_image->mark = NULL; im_image->filename = filename ? g_strdup(filename) : NULL; + im_image->id = id; g_object_ref(img); return GTK_IMHTML_SCALABLE(im_image); @@ -2733,6 +2727,7 @@ { GtkIMHtmlImage *image = (GtkIMHtmlImage *)scale; GtkWidget *box = gtk_event_box_new(); + char *tag; GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter); gtk_container_add(GTK_CONTAINER(box), GTK_WIDGET(image->image)); @@ -2740,6 +2735,10 @@ gtk_widget_show(GTK_WIDGET(image->image)); gtk_widget_show(box); + tag = g_strdup_printf("<IMG ID=\"%d\">", image->id); + g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_htmltext", tag, g_free); + g_object_set_data(G_OBJECT(anchor), "gtkimhtml_plaintext", "[Image]"); + gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), box, anchor); g_signal_connect(G_OBJECT(box), "event", G_CALLBACK(gtk_imhtml_image_clicked), image); } @@ -3513,6 +3512,61 @@ g_free(unescaped); } +void gtk_imhtml_insert_image_at_iter(GtkIMHtml *imhtml, int id, GtkTextIter *iter) +{ + GdkPixbuf *pixbuf = NULL; + const char *filename = NULL; + gpointer image; + GdkRectangle rect; + GtkIMHtmlScalable *scalable = NULL; + int minus; + + if (!imhtml->funcs || !imhtml->funcs->image_get || + !imhtml->funcs->image_get_size || !imhtml->funcs->image_get_data || + !imhtml->funcs->image_get_filename || !imhtml->funcs->image_ref || + !imhtml->funcs->image_unref) + return; + + image = imhtml->funcs->image_get(id); + + if (image) { + gpointer data; + size_t len; + + data = imhtml->funcs->image_get_data(image); + len = imhtml->funcs->image_get_size(image); + + if (data && len) { + GdkPixbufLoader *loader = gdk_pixbuf_loader_new(); + gdk_pixbuf_loader_write(loader, data, len, NULL); + pixbuf = gdk_pixbuf_loader_get_pixbuf(loader); + if (pixbuf) + g_object_ref(G_OBJECT(pixbuf)); + gdk_pixbuf_loader_close(loader, NULL); + } + + } + + if (pixbuf) { + filename = imhtml->funcs->image_get_filename(image); + imhtml->funcs->image_ref(id); + imhtml->im_images = g_slist_prepend(imhtml->im_images, GINT_TO_POINTER(id)); + } else { + pixbuf = gtk_widget_render_icon(GTK_WIDGET(imhtml), GTK_STOCK_MISSING_IMAGE, + GTK_ICON_SIZE_BUTTON, "gtkimhtml-missing-image"); + } + + scalable = gtk_imhtml_image_new(pixbuf, filename, id); + gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); + scalable->add_to(scalable, imhtml, iter); + minus = gtk_text_view_get_left_margin(GTK_TEXT_VIEW(imhtml)) + + gtk_text_view_get_right_margin(GTK_TEXT_VIEW(imhtml)); + scalable->scale(scalable, rect.width - minus, rect.height); + imhtml->scalables = g_list_append(imhtml->scalables, scalable); + + g_object_unref(G_OBJECT(pixbuf)); +} + static const gchar *tag_to_html_start(GtkTextTag *tag) { const gchar *name; @@ -3796,3 +3850,9 @@ return g_string_free(str, FALSE); } + +void gtk_imhtml_set_funcs(GtkIMHtml *imhtml, GtkIMHtmlFuncs *f) +{ + g_return_if_fail(imhtml != NULL); + imhtml->funcs = f; +}
--- a/src/gtkimhtml.h Mon May 17 04:39:14 2004 +0000 +++ b/src/gtkimhtml.h Mon May 17 06:47:20 2004 +0000 @@ -48,6 +48,7 @@ typedef struct _GtkIMHtmlScalable GtkIMHtmlScalable; typedef struct _GtkIMHtmlImage GtkIMHtmlImage; typedef struct _GtkIMHtmlHr GtkIMHtmlHr; +typedef struct _GtkIMHtmlFuncs GtkIMHtmlFuncs; typedef enum { GTK_IMHTML_BOLD = 1 << 0, @@ -111,6 +112,9 @@ char *clipboard_text_string; char *clipboard_html_string; + + GSList *im_images; + GtkIMHtmlFuncs *funcs; }; struct _GtkIMHtmlClass { @@ -159,6 +163,7 @@ gchar *filename; int width; int height; + int id; }; struct _GtkIMHtmlHr { @@ -178,6 +183,23 @@ GTK_IMHTML_USE_POINTSIZE = 1 << 8 } GtkIMHtmlOptions; +typedef gpointer (*GtkIMHtmlGetImageFunc) (int id); +typedef gpointer (*GtkIMHtmlGetImageDataFunc) (gpointer i); +typedef size_t (*GtkIMHtmlGetImageSizeFunc) (gpointer i); +typedef const char *(*GtkIMHtmlGetImageFilenameFunc)(gpointer i); +typedef void (*GtkIMHtmlImageRefFunc) (int id); +typedef void (*GtkIMHtmlImageUnrefFunc) (int id); + +struct _GtkIMHtmlFuncs { + GtkIMHtmlGetImageFunc image_get; + GtkIMHtmlGetImageDataFunc image_get_data; + GtkIMHtmlGetImageSizeFunc image_get_size; + GtkIMHtmlGetImageFilenameFunc image_get_filename; + GtkIMHtmlImageRefFunc image_ref; + GtkIMHtmlImageUnrefFunc image_unref; +}; + + GtkType gtk_imhtml_get_type (void); GtkWidget* gtk_imhtml_new (void *, void *); @@ -190,6 +212,8 @@ void gtk_imhtml_remove_smileys (GtkIMHtml *imhtml); +void gtk_imhtml_set_funcs (GtkIMHtml *imhtml, GtkIMHtmlFuncs *f); + void gtk_imhtml_show_comments (GtkIMHtml *imhtml, gboolean show); void gtk_imhtml_html_shortcuts(GtkIMHtml *imhtml, gboolean allow); @@ -217,7 +241,7 @@ void gtk_imhtml_font_zoom(GtkIMHtml *imhtml, double zoom); GtkIMHtmlScalable *gtk_imhtml_scalable_new(); -GtkIMHtmlScalable *gtk_imhtml_image_new(GdkPixbuf *img, const gchar *filename); +GtkIMHtmlScalable *gtk_imhtml_image_new(GdkPixbuf *img, const gchar *filename, int id); void gtk_imhtml_image_free(GtkIMHtmlScalable *); void gtk_imhtml_image_scale(GtkIMHtmlScalable *, int, int); void gtk_imhtml_image_add_to(GtkIMHtmlScalable *, GtkIMHtml *, GtkTextIter *); @@ -248,6 +272,7 @@ void gtk_imhtml_insert_link(GtkIMHtml *imhtml, GtkTextMark *mark, const char *url, const char *text); void gtk_imhtml_insert_smiley(GtkIMHtml *imhtml, const char *sml, char *smiley); void gtk_imhtml_insert_smiley_at_iter(GtkIMHtml *imhtml, const char *sml, char *smiley, GtkTextIter *iter); +void gtk_imhtml_insert_image_at_iter(GtkIMHtml *imhtml, int id, GtkTextIter *iter); void gtk_imhtml_font_set_size(GtkIMHtml *imhtml, gint size); void gtk_imhtml_font_shrink(GtkIMHtml *imhtml); void gtk_imhtml_font_grow(GtkIMHtml *imhtml);
--- a/src/gtkimhtmltoolbar.c Mon May 17 04:39:14 2004 +0000 +++ b/src/gtkimhtmltoolbar.c Mon May 17 06:47:20 2004 +0000 @@ -413,6 +413,8 @@ size_t size; GError *error = NULL; int id; + GtkTextIter iter; + GtkTextMark *ins; if (resp != GTK_RESPONSE_OK) { //set_toggle(toolbar->image, FALSE); @@ -461,12 +463,12 @@ return; } - //im->images = g_slist_append(im->images, GINT_TO_POINTER(id)); - - /*buf = g_strdup_printf("<IMG ID=\"%d\" SRC=\"file://%s\">", id, filename); - gtk_text_buffer_insert_at_cursor(GTK_TEXT_BUFFER(gtkconv->entry_buffer), buf, -1); - g_free(buf); - */ + ins = gtk_text_buffer_get_insert(gtk_text_view_get_buffer(GTK_TEXT_VIEW(toolbar->imhtml))); + 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); + gaim_imgstore_unref(id); + g_free(name); } @@ -986,9 +988,6 @@ gtk_widget_show(sep); toolbar->sml = NULL; gtk_widget_show_all(hbox); - - /* XXX - IMIMAGE - Fix IM images then remove the following line */ - gtk_widget_hide(toolbar->image); } GtkWidget *gtk_imhtmltoolbar_new()
--- a/src/gtknotify.c Mon May 17 04:39:14 2004 +0000 +++ b/src/gtknotify.c Mon May 17 06:47:20 2004 +0000 @@ -303,7 +303,6 @@ GtkWidget *button; GtkWidget *imhtml; GtkWidget *sw; - GSList *images = NULL; int options = 0; char label_text[2048]; char *linked_text; @@ -376,29 +375,12 @@ options ^= GTK_IMHTML_NO_NEWLINE; options ^= GTK_IMHTML_NO_SCROLL; - gaim_gtk_find_images(text, &images); - /* Make sure URLs are clickable */ linked_text = gaim_markup_linkify(text); - gtk_imhtml_append_text_with_images(GTK_IMHTML(imhtml), linked_text, - options, images); + gtk_imhtml_append_text(GTK_IMHTML(imhtml), linked_text, + options); g_free(linked_text); - if (images) - { - GSList *tmp; - - for (tmp = images; tmp; tmp = tmp->next) - { - GdkPixbuf *pixbuf = tmp->data; - - if (pixbuf != NULL) - g_object_unref(pixbuf); - } - - g_slist_free(images); - } - /* Show the window */ gtk_widget_show(window);
--- a/src/gtkutils.c Mon May 17 04:39:14 2004 +0000 +++ b/src/gtkutils.c Mon May 17 06:47:20 2004 +0000 @@ -70,6 +70,15 @@ g_idle_add(url_clicked_idle_cb, g_strdup(uri)); } +GtkIMHtmlFuncs gtkimhtml_cbs = { + (GtkIMHtmlGetImageFunc)gaim_imgstore_get, + (GtkIMHtmlGetImageDataFunc)gaim_imgstore_get_data, + (GtkIMHtmlGetImageSizeFunc)gaim_imgstore_get_size, + (GtkIMHtmlGetImageFilenameFunc)gaim_imgstore_get_filename, + gaim_imgstore_ref, + gaim_imgstore_unref, +}; + void gaim_setup_imhtml(GtkWidget *imhtml) { @@ -80,6 +89,8 @@ G_CALLBACK(url_clicked_cb), NULL); smiley_themeize(imhtml); + + gtk_imhtml_set_funcs(GTK_IMHTML(imhtml), >kimhtml_cbs); } void @@ -924,62 +935,6 @@ } void -gaim_gtk_find_images(const char *message, GSList **list) -{ - GData *attribs; - const char *tmp, *start, *end; - - g_return_if_fail(message != NULL); - g_return_if_fail( list != NULL); - - tmp = message; - while (gaim_markup_find_tag("img", tmp, &start, &end, &attribs)) { - GaimStoredImage *image = NULL; - GdkPixbufLoader *loader = NULL; - GdkPixbuf *pixbuf = NULL; - GError *error = NULL; - char *id = g_datalist_get_data(&attribs, "id"); - - tmp = end + 1; - - if (id) - image = gaim_imgstore_get(atoi(id)); - - g_datalist_clear(&attribs); - - if (!image) { - *list = g_slist_append(*list, NULL); - continue; - } - - loader = gdk_pixbuf_loader_new(); - - if (gdk_pixbuf_loader_write(loader, image->data, image->size, &error) - && (pixbuf = gdk_pixbuf_loader_get_pixbuf(loader))) { - - if (image->filename) - g_object_set_data_full(G_OBJECT(pixbuf), "filename", - g_strdup(image->filename), g_free); - g_object_ref(G_OBJECT(pixbuf)); - *list = g_slist_append(*list, pixbuf); - } else { - if (error) { - gaim_debug(GAIM_DEBUG_ERROR, "gtkutils", - "Failed to make pixbuf from image store: %s\n", - error->message); - g_error_free(error); - } else { - gaim_debug(GAIM_DEBUG_ERROR, "gtkutils", - "Failed to make pixbuf from image store: unknown reason\n"); - } - *list = g_slist_append(*list, NULL); - } - - gdk_pixbuf_loader_close(loader, NULL); - } -} - -void gaim_gtk_setup_gtkspell(GtkTextView *textview) { #ifdef USE_GTKSPELL
--- a/src/gtkutils.h Mon May 17 04:39:14 2004 +0000 +++ b/src/gtkutils.h Mon May 17 06:47:20 2004 +0000 @@ -269,18 +269,6 @@ gboolean gaim_gtk_check_if_dir(const char *path, GtkFileSelection *filesel); /** - * Parses a message to find \<IMG\> tags with valid ID attributes that - * refer to images in Gaim's image store, and load them into a list - * of GdkPixbufs. Image tags with missing ID paramaters, or those that - * refer to images that are not in the store will have a corresponding - * NULL entry on the list. - * - * @param message The message to parse for image tags. - * @param list A pointer to the GSList of GdkPixbufs that will be created. - */ -void gaim_gtk_find_images(const char *message, GSList **list); - -/** * Sets up GtkSpell for the given GtkTextView, reporting errors * if encountered. *
--- a/src/imgstore.c Mon May 17 04:39:14 2004 +0000 +++ b/src/imgstore.c Mon May 17 06:47:20 2004 +0000 @@ -31,6 +31,20 @@ static GSList *imgstore = NULL; 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. + */ +struct _GaimStoredImage +{ + char *data; /**< The image data. */ + size_t size; /**< The image data's size. */ + char *filename; /**< The filename (for the UI) */ +}; + typedef struct { int id; @@ -117,6 +131,18 @@ return priv->img; } +gpointer gaim_imgstore_get_data(GaimStoredImage *i) { + return i->data; +} + +size_t gaim_imgstore_get_size(GaimStoredImage *i) { + return i->size; +} + +const char *gaim_imgstore_get_filename(GaimStoredImage *i) { + return i->filename; +} + void gaim_imgstore_ref(int id) { GaimStoredImagePriv *priv = gaim_imgstore_get_priv(id);
--- a/src/imgstore.h Mon May 17 04:39:14 2004 +0000 +++ b/src/imgstore.h Mon May 17 06:47:20 2004 +0000 @@ -26,17 +26,8 @@ #ifndef _GAIM_CONV_IMGSTORE_H_ #define _GAIM_CONV_IMGSTORE_H_ -/** - * Stored image - * - * Represents a single IM image awaiting display and/or transmission. - */ -typedef struct -{ - char *data; /**< The image data. */ - size_t size; /**< The image data's size. */ - char *filename; /**< The filename (for the UI) */ -} GaimStoredImage; +struct _GaimStoredImage; +typedef struct _GaimStoredImage GaimStoredImage; #ifdef __cplusplus extern "C" { @@ -66,6 +57,36 @@ GaimStoredImage *gaim_imgstore_get(int id); /** + * Retrieves a pointer to the image's data. + * + * @param i The Image + * + * @return A pointer to the data, which must not + * be freed or modified. + */ +gpointer gaim_imgstore_get_data(GaimStoredImage *i); + +/** + * Retrieves the length of the image's data. + * + * @param i The Image + * + * @return The size of the data that the pointer returned by + * gaim_imgstore_get_data points to. + */ +size_t gaim_imgstore_get_size(GaimStoredImage *i); + +/** + * Retrieves a pointer to the image's filename. + * + * @param i The Image + * + * @return A pointer to the filename, which must not + * be freed or modified. + */ +const char *gaim_imgstore_get_filename(GaimStoredImage *i); + +/** * Increment the reference count for an image in the store. The * image will be removed from the store when the reference count * is zero.
--- a/src/protocols/oscar/oscar.c Mon May 17 04:39:14 2004 +0000 +++ b/src/protocols/oscar/oscar.c Mon May 17 06:47:20 2004 +0000 @@ -4524,15 +4524,18 @@ if (dim && dim->connected) { /* If we're directly connected, send a direct IM */ ret = gaim_odc_send_im(od->sess, dim->conn, message, imflags); - } else if (imflags & GAIM_CONV_IM_IMAGES) { - /* Trying to send an IM image outside of a direct connection. */ - oscar_ask_direct_im(gc, name); - ret = -ENOTCONN; } else { struct buddyinfo *bi; struct aim_sendimext_args args; struct stat st; gsize len; + GaimConversation *conv = gaim_find_conversation_with_account(name, gaim_connection_get_account(gc)); + + if (strstr(message, "<IMG ")) + gaim_conversation_write(conv, "", + _("Your IM Image was not sent. " + "You must be Direct Connected to send IM Images."), + GAIM_MESSAGE_ERROR, time(NULL)); bi = g_hash_table_lookup(od->buddyinfo, gaim_normalize(gc->account, name)); if (!bi) { @@ -5632,6 +5635,12 @@ buf = gaim_strdup_withhtml(message); len = strlen(buf); + if (strstr(buf, "<IMG ")) + gaim_conversation_write(conv, "", + _("Your IM Image was not sent. " + "You cannot send IM Images in AIM chats."), + GAIM_MESSAGE_ERROR, time(NULL)); + encoding = oscar_encoding_check(buf); if (encoding & AIM_IMFLAGS_UNICODE) { gaim_debug_info("oscar", "Sending Unicode chat\n"); @@ -5929,8 +5938,8 @@ } /* - * This is called when each chunk of an image is received. It can be used to - * update a progress bar, or to eat lots of dry cat food. Wet cat food is + * This is called when each chunk of an image is received. It can be used to + * update a progress bar, or to eat lots of dry cat food. Wet cat food is * nasty, you sicko. */ static int gaim_odc_update_ui(aim_session_t *sess, aim_frame_t *fr, ...) { @@ -5947,7 +5956,7 @@ percent = va_arg(ap, double); va_end(ap); - if (!(dim = find_direct_im(od, sn))) + if (!sn || !(dim = find_direct_im(od, sn))) return 1; if (dim->watcher) { gaim_input_remove(dim->watcher); /* Otherwise, the callback will callback */ @@ -6146,75 +6155,73 @@ char *buf; size_t len; int ret; - - if (imflags & GAIM_CONV_IM_IMAGES) { - GString *msg = g_string_new(""); - GString *data = g_string_new("<BINARY>"); - GData *attribs; - const char *tmp, *start, *end, *last = NULL; - int oscar_id = 0; - - tmp = message; - - /* for each valid IMG tag... */ - while (gaim_markup_find_tag("img", tmp, &start, &end, &attribs)) { - GaimStoredImage *image = NULL; - const char *id; - - last = end; - id = g_datalist_get_data(&attribs, "id"); - - /* ... if it refers to a valid gaim image ... */ - if (id && (image = gaim_imgstore_get(atoi(id)))) { - /* ... append the message from start to the tag ... */ - msg = g_string_append_len(msg, tmp, start - tmp); - oscar_id++; - - /* ... insert a new img tag with the oscar id ... */ - if (image->filename) - g_string_append_printf(msg, - "<IMG SRC=\"file://%s\" ID=\"%d\" DATASIZE=\"%d\">", - image->filename, oscar_id, (int)image->size); - else - g_string_append_printf(msg, - "<IMG ID=\"%d\" DATASIZE=\"%d\">", - oscar_id, (int)image->size); - - /* ... and append the data to the binary section ... */ - g_string_append_printf(data, "<DATA ID=\"%d\" SIZE=\"%d\">", - oscar_id, (int)image->size); - data = g_string_append_len(data, image->data, image->size); - data = g_string_append(data, "</DATA>"); - } else { - /* ... otherwise, allow the possibly invalid img tag through. */ - /* should we do something else? */ - msg = g_string_append_len(msg, tmp, (end + 1) - tmp); - } - - g_datalist_clear(&attribs); - - /* continue from the end of the tag */ - tmp = end + 1; + GString *msg = g_string_new(""); + GString *data = g_string_new("<BINARY>"); + GData *attribs; + const char *start, *end, *last; + int oscar_id = 0; + + last = message; + + /* for each valid IMG tag... */ + while (last && *last && gaim_markup_find_tag("img", last, &start, &end, &attribs)) { + GaimStoredImage *image = NULL; + const char *id; + + if (start - last) { + g_string_append_len(msg, last, start - last); } - /* append any remaining message data (without the > :-) */ - if (last++ && *last) - msg = g_string_append(msg, last); - - /* if we inserted any images in the binary section, append it */ - if (oscar_id) { - msg = g_string_append_len(msg, data->str, data->len); - msg = g_string_append(msg, "</BINARY>"); + id = g_datalist_get_data(&attribs, "id"); + + /* ... if it refers to a valid gaim image ... */ + if (id && (image = gaim_imgstore_get(atoi(id)))) { + /* ... append the message from start to the tag ... */ + size_t size = gaim_imgstore_get_size(image); + const char *filename = gaim_imgstore_get_filename(image); + gpointer imgdata = gaim_imgstore_get_data(image); + + oscar_id++; + + /* ... insert a new img tag with the oscar id ... */ + if (filename) + g_string_append_printf(msg, + "<IMG SRC=\"file://%s\" ID=\"%d\" DATASIZE=\"%zu\">", + filename, oscar_id, size); + else + g_string_append_printf(msg, + "<IMG ID=\"%d\" DATASIZE=\"%zu\">", + oscar_id, size); + + /* ... and append the data to the binary section ... */ + g_string_append_printf(data, "<DATA ID=\"%d\" SIZE=\"%zu\">", + oscar_id, size); + data = g_string_append_len(data, imgdata, size); + data = g_string_append(data, "</DATA>"); } - - len = msg->len; - buf = msg->str; - g_string_free(msg, FALSE); - g_string_free(data, TRUE); - } else { - len = strlen(message); - buf = g_memdup(message, len+1); - } + /* If the tag is invalid, skip it, thus no else here */ + + g_datalist_clear(&attribs); + + /* continue from the end of the tag */ + last = end + 1; + } + + /* append any remaining message data (without the > :-) */ + if (last && *last) + msg = g_string_append(msg, last); + + /* if we inserted any images in the binary section, append it */ + if (oscar_id) { + msg = g_string_append_len(msg, data->str, data->len); + msg = g_string_append(msg, "</BINARY>"); + } + + len = msg->len; + buf = msg->str; + g_string_free(msg, FALSE); + g_string_free(data, TRUE); + /* XXX - The last parameter below is the encoding. Let Paco-Paco do something with it. */ if (imflags & GAIM_CONV_IM_AUTO_RESP)