# HG changeset patch # User Sean Egan # Date 1016091883 0 # Node ID e68e2ba82310d9764423016e18bece24e563182a # Parent 5a459387755ae8d696e06570f79142929f266eb5 [gaim-migrate @ 3057] DirectIM Image sending. Not all the kinks are worked out, and it's really hackish at parts, but it works and I think it's stable. It's late and I have to be up early tommorow, and I want this to be somewhat tested before 0.54 is released so we don't have a repeat of 0.53 ;) Also, Luke Schierer wins the #gaim MVP award with an inclusion in CREDITS :) Thanks, Luke. committer: Tailor Script diff -r 5a459387755a -r e68e2ba82310 doc/CREDITS --- a/doc/CREDITS Thu Mar 14 03:29:03 2002 +0000 +++ b/doc/CREDITS Thu Mar 14 07:44:43 2002 +0000 @@ -67,6 +67,9 @@ Ryan C. Gordon - I still think you look like Silent Bob. Elliot Tobin +Many, many thanks to Luke Schierer who logs many hours in #gaim (as LSchiere) +providing technical support to users and testing patches for developers. + A big thanks to the X-Chat developers, who were kind enough to license X-Chat under the GPL so that I could learn to be as cool as them. -EW diff -r 5a459387755a -r e68e2ba82310 src/conversation.c --- a/src/conversation.c Thu Mar 14 03:29:03 2002 +0000 +++ b/src/conversation.c Thu Mar 14 07:44:43 2002 +0000 @@ -53,6 +53,7 @@ #include "pixmaps/wood.xpm" #include "pixmaps/save_small.xpm" #include "pixmaps/speaker.xpm" +#include "pixmaps/image_icon.xpm" #include "pixmaps/luke03.xpm" #include "pixmaps/oneeye.xpm" @@ -406,6 +407,68 @@ gtk_widget_show(window); } +static void do_insert_image(GtkObject *obj, GtkWidget *wid) +{ + struct conversation *c = gtk_object_get_user_data(obj); + char *name = gtk_file_selection_get_filename(GTK_FILE_SELECTION(wid)); + char *filename; + int pos; + char buf[512]; + struct stat st; + int id = g_slist_length(c->images) + 1; + + if (file_is_dir(name, wid)) + return; + if ((!c->is_chat && g_list_find(conversations, c))) + name = g_strdup(name); + else + name = NULL; + gtk_widget_destroy(wid); + if (!name) + return; + + if (stat(name, &st) != 0) { + debug_printf("Could not stat %s\n", name); + return; + } + + filename = name; + while (strchr(filename, '/')) + filename = strchr(filename, '/') + 1; + + g_snprintf(buf, sizeof(buf), + "", + filename, id, (int)st.st_size); + + c->images = g_slist_append(c->images, g_strdup(name)); + + if (GTK_OLD_EDITABLE(c->entry)->has_selection) { + int finish = GTK_OLD_EDITABLE(c->entry)->selection_end_pos; + gtk_editable_insert_text(GTK_EDITABLE(c->entry), + buf, strlen(buf), &finish); + } else { + pos = GTK_OLD_EDITABLE(c->entry)->current_pos; + gtk_editable_insert_text(GTK_EDITABLE(c->entry), + buf, strlen(buf), &pos); + } + g_free(name); +} + +void insert_image(GtkWidget *save, struct conversation *c) +{ + char buf[BUF_LONG]; + GtkWidget *window = gtk_file_selection_new(_("Gaim - Insert Image")); + g_snprintf(buf, sizeof(buf), "%s/", g_get_home_dir()); + gtk_file_selection_set_filename(GTK_FILE_SELECTION(window), buf); + gtk_object_set_user_data(GTK_OBJECT(GTK_FILE_SELECTION(window)->ok_button), c); + gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(window)->ok_button), + "clicked", GTK_SIGNAL_FUNC(do_insert_image), window); + gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(window)->cancel_button), + "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), (gpointer)window); + gtk_widget_show(window); +} + + void insert_smiley(GtkWidget *smiley, struct conversation *c) { if (state_lock) @@ -931,7 +994,8 @@ void send_callback(GtkWidget *widget, struct conversation *c) { char *buf, *buf2; - int limit, length=0; + int limit; + gulong length=0; int err = 0; if (!c->gc) @@ -1045,52 +1109,79 @@ id = 1; length = strlen(buffy) + strlen(""); bigbuf = g_malloc(length); - g_snprintf(bigbuf, strlen(buffy)+strlen(" "), "%s", buffy); + g_snprintf(bigbuf, strlen(buffy)+strlen(" ") + 1, "%s", buffy); offset = strlen(buffy) + strlen(""); while (tmplist) { - FILE *imgfile; - struct stat st; + FILE *imgfile; + char *filename; + struct stat st; char imgtag[1024]; if (stat(tmplist->data, &st) != 0) { debug_printf("Could not stat %s\n", tmplist->data); break; } + + /* Here we check to make sure the user still wants to send the + * image. He may have deleted the tag in which case we + * don't want to send the binary data. */ + filename = tmplist->data; + while (strchr(filename, '/')) + filename = strchr(filename, '/') + 1; + g_snprintf(imgtag, sizeof(imgtag), + "", + filename, id, (int)st.st_size); + if (!strstr(buffy, imgtag)) { + tmplist = tmplist->next; + continue; + } g_snprintf(imgtag, sizeof(imgtag), "", - id, st.st_size); - length = length + strlen(imgtag) + st.st_size; - bigbuf = realloc(bigbuf, length); - if (!(imgfile = fopen(c->images->data, "r"))) { + id, (int)st.st_size); + + length = length + strlen(imgtag) + st.st_size + strlen("");; + bigbuf = g_realloc(bigbuf, length); + if (!(imgfile = fopen(tmplist->data, "r"))) { debug_printf("Could not open %s\n", tmplist->data); - break; + continue; } g_snprintf(bigbuf + offset, strlen(imgtag) + 1, "%s", imgtag); offset = offset + strlen(imgtag); - fread(bigbuf + offset, 1, st.st_size, imgfile); - offset = offset + st.st_size; - g_snprintf(bigbuf + offset, strlen(""), ""); + offset = offset + fread(bigbuf + offset, 1, st.st_size, imgfile); + fclose(imgfile); + g_snprintf(bigbuf + offset, strlen("") + 1, ""); offset= offset + strlen(""); id++; tmplist = tmplist->next; } - g_snprintf(bigbuf + offset, strlen(""), ""); - if (serv_send_im(c->gc, c->name, bigbuf, length, imflags) > 0) { + g_snprintf(bigbuf + offset, strlen("") + 1, ""); + err =serv_send_im(c->gc, c->name, bigbuf, length, imflags); + if (err > 0) { + GSList *tempy = c->images; + while (tempy) { + g_free(tempy->data); + tempy = tempy->next; + } + g_slist_free(tempy); + c->images = NULL; write_to_conv(c, bigbuf, WFLAG_SEND, NULL, time(NULL), length); if (c->makesound && (sound_options & OPT_SOUND_SEND)) play_sound(SEND); if (im_options & OPT_IM_POPDOWN) gtk_widget_hide(c->window); + } g_free(bigbuf); } else { - if (serv_send_im(c->gc, c->name, buffy, -1, imflags) > 0) + err =serv_send_im(c->gc, c->name, buffy, -1, imflags); + if (err > 0) { write_to_conv(c, buf, WFLAG_SEND, NULL, time(NULL), -1); - if (c->makesound && (sound_options & OPT_SOUND_SEND)) - play_sound(SEND); - if (im_options & OPT_IM_POPDOWN) - gtk_widget_hide(c->window); + if (c->makesound && (sound_options & OPT_SOUND_SEND)) + play_sound(SEND); + if (im_options & OPT_IM_POPDOWN) + gtk_widget_hide(c->window); + } } g_free(buffy); } @@ -1107,6 +1198,8 @@ if (err < 0) { if (err == -E2BIG) do_error_dialog(_("Unable to send message: too large"), _("Message Error")); + else if (err == -ENOTCONN) + debug_printf("Not yet connected\n"); else do_error_dialog(_("Unable to send message: Unknown reason"), _("Message Error")); } else { @@ -1813,9 +1906,7 @@ } void update_progress(struct conversation *c, float percent) { - while (gtk_events_pending()) - gtk_main_iteration(); - + if (percent >= 1 && !(c->progress)) return; @@ -1840,11 +1931,11 @@ GtkWidget *build_conv_toolbar(struct conversation *c) { GdkPixmap *strike_i, *small_i, *normal_i, *big_i, *bold_i, *italic_i, *underline_i, *speaker_i, - *wood_i, *fgcolor_i, *bgcolor_i, *link_i, *font_i, *smiley_i, *save_i; + *wood_i, *fgcolor_i, *bgcolor_i, *link_i, *font_i, *smiley_i, *save_i, *image_i; GtkWidget *strike_p, *small_p, *normal_p, *big_p, *bold_p, *italic_p, *underline_p, *speaker_p, - *wood_p, *fgcolor_p, *bgcolor_p, *link_p, *font_p, *smiley_p, *save_p; + *wood_p, *fgcolor_p, *bgcolor_p, *link_p, *font_p, *smiley_p, *save_p, *image_p; GtkWidget *strike, *small, *normal, *big, *bold, *italic, *underline, *speaker, *wood, - *fgcolorbtn, *bgcolorbtn, *link, *font, *smiley, *save; + *fgcolorbtn, *bgcolorbtn, *link, *font, *smiley, *save, *image; GdkBitmap *mask; GtkWidget *toolbar; GtkWidget *win; @@ -1915,6 +2006,11 @@ gtk_widget_show(smiley_p); gdk_bitmap_unref(mask); + image_i = gdk_pixmap_create_from_xpm_d(win->window, &mask, &win->style->white, image_icon_xpm); + image_p = gtk_pixmap_new(image_i, mask); + gtk_widget_show(image_p); + gdk_bitmap_unref(mask); + wood_i = gdk_pixmap_create_from_xpm_d(win->window, &mask, &win->style->white, wood_xpm); wood_p = gtk_pixmap_new(wood_i, mask); gtk_widget_show(wood_p); @@ -1987,7 +2083,10 @@ GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, NULL, _("Insert smiley face"), _("Smiley"), smiley_p, GTK_SIGNAL_FUNC(insert_smiley), c); - + image = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), + NULL, _("Insert IM Image"), _("Image"), + image_p, GTK_SIGNAL_FUNC(insert_image), c); + gtk_toolbar_append_space(GTK_TOOLBAR(toolbar)); wood = gtk_toolbar_append_element(GTK_TOOLBAR(toolbar), @@ -2027,6 +2126,7 @@ gtk_button_set_relief(GTK_BUTTON(bgcolorbtn), GTK_RELIEF_NONE); gtk_button_set_relief(GTK_BUTTON(link), GTK_RELIEF_NONE); gtk_button_set_relief(GTK_BUTTON(smiley), GTK_RELIEF_NONE); + gtk_button_set_relief(GTK_BUTTON(image), GTK_RELIEF_NONE); gtk_button_set_relief(GTK_BUTTON(wood), GTK_RELIEF_NONE); gtk_button_set_relief(GTK_BUTTON(save), GTK_RELIEF_NONE); gtk_button_set_relief(GTK_BUTTON(speaker), GTK_RELIEF_NONE); @@ -2049,6 +2149,7 @@ gdk_pixmap_unref(wood_i); gdk_pixmap_unref(save_i); gdk_pixmap_unref(speaker_i); + gdk_pixmap_unref(image_i); c->bold = bold; c->strike = strike; @@ -2061,9 +2162,9 @@ c->wood = wood; c->font = font; c->smiley = smiley; + c->imagebtn = image; gtk_widget_set_sensitive(c->log_button, ((logging_options & OPT_LOG_ALL)) ? FALSE : TRUE); - gtk_widget_set_sensitive(c->bold, ((font_options & OPT_FONT_BOLD)) ? FALSE : TRUE); gtk_widget_set_sensitive(c->italic, ((font_options & OPT_FONT_ITALIC)) ? FALSE : TRUE); gtk_widget_set_sensitive(c->underline, ((font_options & OPT_FONT_UNDERLINE)) ? FALSE : TRUE); @@ -2240,7 +2341,6 @@ c->gc = gc; set_convo_title(c); - update_buttons_by_protocol(c); update_icon(c); @@ -2264,7 +2364,6 @@ gtk_widget_set_sensitive(c->whisper, FALSE); if (c->invite) gtk_widget_set_sensitive(c->invite, FALSE); - return; } @@ -2278,11 +2377,16 @@ gtk_widget_set_sensitive(c->send, FALSE); else gtk_widget_set_sensitive(c->send, TRUE); + gtk_widget_set_sensitive(c->imagebtn, FALSE); } else { if (c->gc->prpl->send_im == NULL && c->send) gtk_widget_set_sensitive(c->send, FALSE); else gtk_widget_set_sensitive(c->send, TRUE); + if (c->gc->prpl->options & OPT_PROTO_IM_IMAGE) + gtk_widget_set_sensitive(c->imagebtn, TRUE); + else + gtk_widget_set_sensitive(c->imagebtn, FALSE); } if (c->gc->prpl->warn == NULL && c->warn) diff -r 5a459387755a -r e68e2ba82310 src/protocols/oscar/oscar.c --- a/src/protocols/oscar/oscar.c Thu Mar 14 03:29:03 2002 +0000 +++ b/src/protocols/oscar/oscar.c Thu Mar 14 07:44:43 2002 +0000 @@ -2436,7 +2436,11 @@ else return ret; } debug_printf("Direct IM pending, but not connected; sending through server\n"); - } + } else if (len != -1) { + /* Trying to send an IM image outside of a direct connection. */ + oscar_ask_direct_im(gc, name); + return -ENOTCONN; + } if (imflags & IM_FLAG_AWAY) { ret = aim_send_im(odata->sess, name, AIM_IMFLAGS_AWAY, message); } else { @@ -3168,6 +3172,9 @@ if (!(dim = find_direct_im(od, sn))) return 1; gaim_input_remove(dim->watcher); /* Otherwise, the callback will callback */ + while (gtk_events_pending()) + gtk_main_iteration(); + if ((c = find_conversation(sn))) update_progress(c, percent); dim->watcher = gaim_input_add(dim->conn->fd, GAIM_INPUT_READ, @@ -3554,7 +3561,7 @@ void oscar_init(struct prpl *ret) { ret->protocol = PROTO_OSCAR; - ret->options = OPT_PROTO_BUDDY_ICON; + ret->options = OPT_PROTO_BUDDY_ICON | OPT_PROTO_IM_IMAGE; ret->name = oscar_name; ret->list_icon = oscar_list_icon; ret->away_states = oscar_away_states; diff -r 5a459387755a -r e68e2ba82310 src/protocols/oscar/txqueue.c --- a/src/protocols/oscar/txqueue.c Thu Mar 14 03:29:03 2002 +0000 +++ b/src/protocols/oscar/txqueue.c Thu Mar 14 07:44:43 2002 +0000 @@ -230,15 +230,34 @@ static int aim_bstream_send(aim_bstream_t *bs, aim_conn_t *conn, size_t count) { int wrote = 0; - if (!bs || !conn || (count < 0)) return -EINVAL; if (count > aim_bstream_empty(bs)) count = aim_bstream_empty(bs); /* truncate to remaining space */ - if (count) - wrote = aim_send(conn->fd, bs->data + bs->offset, count); + if (count) { + if ((conn->type == AIM_CONN_TYPE_RENDEZVOUS) && + (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM)) { + /* I strongly suspect that this is a horrible thing to do + * and I feel really guilty doing it. */ + char *sn = aim_directim_getsn(conn); + aim_rxcallback_t userfunc; + while (count - wrote > 1024) { + wrote = wrote + aim_send(conn->fd, bs->data + bs->offset + wrote, 1024); + if ((userfunc=aim_callhandler(conn->sessv, conn, + AIM_CB_FAM_SPECIAL, + AIM_CB_SPECIAL_IMAGETRANSFER))) + userfunc(conn->sessv, NULL, sn, + count-wrote>1024 ? ((double)wrote / count) : 1); + } + } + if (count - wrote) { + wrote = wrote + aim_send(conn->fd, bs->data + bs->offset + wrote, count - wrote); + } + + } + if (((aim_session_t *)conn->sessv)->debug >= 2) { int i; @@ -284,7 +303,6 @@ obslen = aim_bstream_curpos(&obs); aim_bstream_rewind(&obs); - if (aim_bstream_send(&obs, fr->conn, obslen) != obslen) err = -errno; @@ -302,9 +320,8 @@ fu8_t *hbs_raw; int hbslen; int err = 0; - + hbslen = 8 + fr->hdr.oft.hdr2len; - if (!(hbs_raw = malloc(hbslen))) return -1; @@ -317,6 +334,7 @@ aim_bstream_rewind(&hbs); + if (aim_bstream_send(&hbs, fr->conn, hbslen) != hbslen) { err = -errno; @@ -338,6 +356,8 @@ return err; + + } faim_internal int aim_tx_sendframe(aim_session_t *sess, aim_frame_t *fr) diff -r 5a459387755a -r e68e2ba82310 src/prpl.h --- a/src/prpl.h Thu Mar 14 03:29:03 2002 +0000 +++ b/src/prpl.h Thu Mar 14 07:44:43 2002 +0000 @@ -41,7 +41,7 @@ #define PROTO_NAPSTER 9 #define PROTO_ZEPHYR 10 #define PROTO_GADUGADU 11 -/* DON'T TAKE AN UNASSIGNED NUMBER! Talk to Eric or Rob if you'd like +/* DON'T TAKE AN UNASSIGNED NUMBER! Talk to Rob or Sean if you'd like * to create a new PRPL. */ #define PRPL_DESC(x) "Allows gaim to use the " x " protocol.\n\n" \ @@ -70,6 +70,8 @@ #define OPT_PROTO_MAIL_CHECK 0x00000020 /* Oscar and Jabber have buddy icons */ #define OPT_PROTO_BUDDY_ICON 0x00000040 +/* Oscar lets you send images in direct IMs */ +#define OPT_PROTO_IM_IMAGE 0x00000080 #define GAIM_AWAY_CUSTOM "Custom" diff -r 5a459387755a -r e68e2ba82310 src/ui.h --- a/src/ui.h Thu Mar 14 03:29:03 2002 +0000 +++ b/src/ui.h Thu Mar 14 07:44:43 2002 +0000 @@ -122,6 +122,7 @@ GtkWidget *strike; GtkWidget *font; GtkWidget *smiley; + GtkWidget *imagebtn; GtkWidget *fg_color_dialog; GtkWidget *bg_color_dialog; GtkWidget *font_dialog;