# HG changeset patch # User maiku@pidgin.im # Date 1250071494 0 # Node ID 359800ae7d17c24e0dad6e30ca3171940fca58c0 # Parent dad4cb8f81df6d07bca53ef23cb3ef082fa59a2a# Parent d865064a3104ae7335cbcd8e60894a54eb78d234 merge of '235259eaef44e8bacfe07e83eb5c66ddd4887ace' and '2417ca53bef6c584fa8f1e7d5d205793a7091496' diff -r d865064a3104 -r 359800ae7d17 ChangeLog.API --- a/ChangeLog.API Wed Aug 12 10:03:47 2009 +0000 +++ b/ChangeLog.API Wed Aug 12 10:04:54 2009 +0000 @@ -18,6 +18,9 @@ * Three Blist UI ops used to overload libpurple's built-in saving of the buddy list to blist.xml. If a UI implements these, it probably wants to add the buddies itself and not call purple_blist_load. + * Three File Transfer UI ops used to overload libpurple's use of fread + and fwrite for saving a file locally. These allow a UI to stream a + file through a socket without buffering the file on the local disk. * Jabber plugin signals (see jabber-signals.dox) * purple_account_remove_setting * purple_buddy_destroy @@ -65,6 +68,8 @@ * purple_strequal * purple_utf8_strip_unprintables * purple_util_fetch_url_request_len_with_account + * purple_xfer_prpl_ready + * purple_xfer_ui_ready * xmlnode_from_file * xmlnode_get_parent * xmlnode_set_attrib_full @@ -95,6 +100,10 @@ * status is set before emitting signals in purple_xfer_set_status. * Creating multiple distinct chats with the same name (i.e. "MSN Chat") is deprecated and will be removed in libpurple 3.0.0. + * purple_xfer_start now accepts -1 as the fd parameter if the protocol + plugin will administer the transfer itself. 0 is still accepted for + backward compatibility since older versions of libpurple will not + accept -1. Deprecated: * buddy-added and buddy-removed blist signals diff -r d865064a3104 -r 359800ae7d17 doc/funniest_home_convos.txt --- a/doc/funniest_home_convos.txt Wed Aug 12 10:03:47 2009 +0000 +++ b/doc/funniest_home_convos.txt Wed Aug 12 10:04:54 2009 +0000 @@ -572,3 +572,42 @@ 15:46 well, there was a Grand Smiley Theme Database 15:47 the GSTD sounds like a bad acronym 15:47 I realized after typing that + +-- + +(01:51:38 AM) user entered the room. +(01:52:46 AM) user: .addKeyActionListener(new KeyActionListener() onKeyPress() {if (event.geyKeyPresss().equals(Key.UP_ARROW) { inputbox.text = history.pop() }}}}}}}); +(01:52:51 AM) user: THERE, FOR **** SAKE +(01:52:53 AM) user: its 2009 +(01:53:06 AM) user: oh wait. ctrl up works +(01:53:07 AM) user: lol +(01:53:11 AM) user: yey me +(01:53:16 AM) user left the room. +(01:55:31 AM) darkrain42: Wow. +(01:58:15 AM) QuLogic: I think he failed to realize we'd have to re-write pidgin in java to do that +(01:59:44 AM) khc: history.pop() is clearly wrong too + +-- + +Some time later: +(02:41:55 AM) user entered the room. +(02:42:24 AM) user: didn't I read some idiot post, about 2 years ago, before pidgin was renamed / forked, over one dev refusing to make minimize on close? +(02:43:12 AM) QuLogic: I see you've learned to at least ask a question before jumping to random conclusions +(02:44:01 AM) user: QuLogic: :-)))))))))))))))))))))) +(02:44:12 AM) user: hey, I submitted a code patch! +(02:44:36 AM) user: now, anyway, what happened? why did I get the buddy list (empty) stealing focus, and why did it exit on close? +(02:44:40 AM) QuLogic: it's not really a patch if it's in the wrong language +(02:44:42 AM) user: I've had this argument before, in 2006 +(02:44:55 AM) user: QuLogic: simple, rewrite the rest ;-) +(02:44:58 AM) khc: pidgin never steals focus +(02:45:10 AM) khc: if it exit on close, it's because you didn't turn on the systray icon +(02:47:17 AM) user: khc - and that isn't default... why? anyway. I recall something on the matter, and I think this was the project (pre-fork?) or is this the unforked, renamed? I forget. +(02:47:42 AM) user: Whoever it was arguing about it (and font sizes I believe) was an idiot... not one of you I suppose, just making idle chit chat. +(02:47:43 AM) user: thanks +(02:47:48 AM) darkrain42: It is on by default. Some distros change that. +(02:48:00 AM) darkrain42: And I don't even know what you're arguing about at this point. +(02:48:11 AM) user: ... /leave - That command doesn't work on this protocol... /leave #pidgin ...That comm..... :-((( +(02:48:18 AM) user: darkrain42: now arguing, just remembering something +(02:48:27 AM) user left the room. +(02:49:04 AM) darkrain42: Wow. (again) + diff -r d865064a3104 -r 359800ae7d17 libpurple/ft.c --- a/libpurple/ft.c Wed Aug 12 10:03:47 2009 +0000 +++ b/libpurple/ft.c Wed Aug 12 10:04:54 2009 +0000 @@ -40,8 +40,35 @@ static PurpleXferUiOps *xfer_ui_ops = NULL; static GList *xfers; +/* + * A hack to store more data since we can't extend the size of PurpleXfer + * easily. + */ +static GHashTable *xfers_data = NULL; + +typedef struct _PurpleXferPrivData { + /* + * Used to moderate the file transfer when either the read/write ui_ops are + * set or fd is not set. In those cases, the UI/prpl call the respective + * function, which is somewhat akin to a fd watch being triggered. + */ + enum { + PURPLE_XFER_READY_NONE = 0x0, + PURPLE_XFER_READY_UI = 0x1, + PURPLE_XFER_READY_PRPL = 0x2, + } ready; +} PurpleXferPrivData; + static int purple_xfer_choose_file(PurpleXfer *xfer); +static void +purple_xfer_priv_data_destroy(gpointer data) +{ + PurpleXferPrivData *priv = data; + + g_free(priv); +} + GList * purple_xfers_get_all() { @@ -53,6 +80,7 @@ { PurpleXfer *xfer; PurpleXferUiOps *ui_ops; + PurpleXferPrivData *priv; g_return_val_if_fail(type != PURPLE_XFER_UNKNOWN, NULL); g_return_val_if_fail(account != NULL, NULL); @@ -70,6 +98,11 @@ xfer->current_buffer_size = FT_INITIAL_BUFFER_SIZE; xfer->fd = -1; + priv = g_new0(PurpleXferPrivData, 1); + priv->ready = PURPLE_XFER_READY_NONE; + + g_hash_table_insert(xfers_data, xfer, priv); + ui_ops = purple_xfer_get_ui_ops(xfer); if (ui_ops != NULL && ui_ops->new_xfer != NULL) @@ -102,9 +135,11 @@ g_free(xfer->remote_ip); g_free(xfer->local_filename); + g_hash_table_remove(xfers_data, xfer); + PURPLE_DBUS_UNREGISTER_POINTER(xfer); + xfers = g_list_remove(xfers, xfer); g_free(xfer); - xfers = g_list_remove(xfers, xfer); } void @@ -482,13 +517,16 @@ if (type == PURPLE_XFER_SEND) { /* Sending a file */ /* Check the filename. */ + PurpleXferUiOps *ui_ops; + ui_ops = purple_xfer_get_ui_ops(xfer); + #ifdef _WIN32 if (g_strrstr(filename, "../") || g_strrstr(filename, "..\\")) #else if (g_strrstr(filename, "../")) #endif { - char *utf8 = g_filename_to_utf8(filename, -1, NULL, NULL, NULL); + utf8 = g_filename_to_utf8(filename, -1, NULL, NULL, NULL); msg = g_strdup_printf(_("%s is not a valid filename.\n"), utf8); purple_xfer_error(type, account, xfer->who, msg); @@ -499,15 +537,20 @@ return; } - if (g_stat(filename, &st) == -1) { - purple_xfer_show_file_error(xfer, filename); - purple_xfer_unref(xfer); - return; + if (ui_ops == NULL || (ui_ops->ui_read == NULL && ui_ops->ui_write == NULL)) { + if (g_stat(filename, &st) == -1) { + purple_xfer_show_file_error(xfer, filename); + purple_xfer_unref(xfer); + return; + } + + purple_xfer_set_local_filename(xfer, filename); + purple_xfer_set_size(xfer, st.st_size); + } else { + utf8 = g_strdup(filename); + purple_xfer_set_local_filename(xfer, filename); } - purple_xfer_set_local_filename(xfer, filename); - purple_xfer_set_size(xfer, st.st_size); - base = g_path_get_basename(filename); utf8 = g_filename_to_utf8(base, -1, NULL, NULL, NULL); g_free(base); @@ -516,7 +559,6 @@ msg = g_strdup_printf(_("Offering to send %s to %s"), utf8, buddy ? purple_buddy_get_alias(buddy) : xfer->who); g_free(utf8); - purple_xfer_conversation_write(xfer, msg, FALSE); g_free(msg); } @@ -939,17 +981,23 @@ } static void -transfer_cb(gpointer data, gint source, PurpleInputCondition condition) +do_transfer(PurpleXfer *xfer) { PurpleXferUiOps *ui_ops; - PurpleXfer *xfer = (PurpleXfer *)data; guchar *buffer = NULL; gssize r = 0; - if (condition & PURPLE_INPUT_READ) { + ui_ops = purple_xfer_get_ui_ops(xfer); + + if (xfer->type == PURPLE_XFER_RECEIVE) { r = purple_xfer_read(xfer, &buffer); if (r > 0) { - const size_t wc = fwrite(buffer, 1, r, xfer->dest_fp); + size_t wc; + if (ui_ops && ui_ops->ui_write) + wc = ui_ops->ui_write(xfer, buffer, r); + else + wc = fwrite(buffer, 1, r, xfer->dest_fp); + if (wc != r) { purple_debug_error("filetransfer", "Unable to write whole buffer.\n"); purple_xfer_cancel_local(xfer); @@ -961,7 +1009,7 @@ g_free(buffer); return; } - } else if (condition & PURPLE_INPUT_WRITE) { + } else if (xfer->type == PURPLE_XFER_SEND) { size_t result; size_t s = MIN(purple_xfer_get_bytes_remaining(xfer), xfer->current_buffer_size); @@ -975,26 +1023,53 @@ return; } - buffer = g_malloc0(s); + if (ui_ops && ui_ops->ui_read) { + gssize tmp = ui_ops->ui_read(xfer, &buffer, s); + if (tmp == 0) { + /* + * UI isn't ready to send data. It will call + * purple_xfer_ui_ready when ready, which sets back up this + * watcher. + */ + if (xfer->watcher != 0) { + purple_timeout_remove(xfer->watcher); + xfer->watcher = 0; + } - result = fread(buffer, 1, s, xfer->dest_fp); - if (result != s) { - purple_debug_error("filetransfer", "Unable to read whole buffer.\n"); - purple_xfer_cancel_remote(xfer); - g_free(buffer); - return; + return; + } else if (tmp < 0) { + purple_debug_error("filetransfer", "Unable to read whole buffer.\n"); + purple_xfer_cancel_local(xfer); + return; + } + + result = tmp; + } else { + buffer = g_malloc0(s); + result = fread(buffer, 1, s, xfer->dest_fp); + if (result != s) { + purple_debug_error("filetransfer", "Unable to read whole buffer.\n"); + purple_xfer_cancel_local(xfer); + g_free(buffer); + return; + } } /* Write as much as we're allowed to. */ - r = purple_xfer_write(xfer, buffer, s); + r = purple_xfer_write(xfer, buffer, result); if (r == -1) { purple_xfer_cancel_remote(xfer); g_free(buffer); return; - } else if (r < s) { - /* We have to seek back in the file now. */ - fseek(xfer->dest_fp, r - s, SEEK_CUR); + } else if (r < result) { + if (ui_ops == NULL || (ui_ops->ui_read == NULL && ui_ops->ui_write == NULL)) { + /* We have to seek back in the file now. */ + fseek(xfer->dest_fp, r - s, SEEK_CUR); + } + else { + ui_ops->data_not_sent(xfer, buffer + r, result - r); + } } else { /* * We managed to write the entire buffer. This means our @@ -1016,8 +1091,6 @@ g_free(buffer); - ui_ops = purple_xfer_get_ui_ops(xfer); - if (ui_ops != NULL && ui_ops->update_progress != NULL) ui_ops->update_progress(xfer, purple_xfer_get_progress(xfer)); @@ -1028,22 +1101,45 @@ } static void +transfer_cb(gpointer data, gint source, PurpleInputCondition condition) +{ + PurpleXfer *xfer = data; + + if (xfer->dest_fp == NULL) { + /* The UI is moderating its side manually */ + PurpleXferPrivData *priv = g_hash_table_lookup(xfers_data, xfer); + if (0 == (priv->ready & PURPLE_XFER_READY_UI)) { + priv->ready |= PURPLE_XFER_READY_PRPL; + + purple_input_remove(xfer->watcher); + xfer->watcher = 0; + return; + } + } + + do_transfer(xfer); +} + +static void begin_transfer(PurpleXfer *xfer, PurpleInputCondition cond) { PurpleXferType type = purple_xfer_get_type(xfer); + PurpleXferUiOps *ui_ops = purple_xfer_get_ui_ops(xfer); - xfer->dest_fp = g_fopen(purple_xfer_get_local_filename(xfer), - type == PURPLE_XFER_RECEIVE ? "wb" : "rb"); + if (ui_ops == NULL || (ui_ops->ui_read == NULL && ui_ops->ui_write == NULL)) { + xfer->dest_fp = g_fopen(purple_xfer_get_local_filename(xfer), + type == PURPLE_XFER_RECEIVE ? "wb" : "rb"); - if (xfer->dest_fp == NULL) { - purple_xfer_show_file_error(xfer, purple_xfer_get_local_filename(xfer)); - purple_xfer_cancel_local(xfer); - return; + if (xfer->dest_fp == NULL) { + purple_xfer_show_file_error(xfer, purple_xfer_get_local_filename(xfer)); + purple_xfer_cancel_local(xfer); + return; + } + + fseek(xfer->dest_fp, xfer->bytes_sent, SEEK_SET); } - fseek(xfer->dest_fp, xfer->bytes_sent, SEEK_SET); - - if (xfer->fd) + if (xfer->fd != -1) xfer->watcher = purple_input_add(xfer->fd, cond, transfer_cb, xfer); xfer->start_time = time(NULL); @@ -1068,6 +1164,54 @@ } void +purple_xfer_ui_ready(PurpleXfer *xfer) +{ + PurpleInputCondition cond; + PurpleXferType type; + PurpleXferPrivData *priv; + + g_return_if_fail(xfer != NULL); + + priv = g_hash_table_lookup(xfers_data, xfer); + priv->ready |= PURPLE_XFER_READY_UI; + + if (0 == (priv->ready & PURPLE_XFER_READY_PRPL)) + return; + + type = purple_xfer_get_type(xfer); + if (type == PURPLE_XFER_SEND) + cond = PURPLE_INPUT_WRITE; + else /* if (type == PURPLE_XFER_RECEIVE) */ + cond = PURPLE_INPUT_READ; + + if (xfer->watcher == 0 && xfer->fd != -1) + xfer->watcher = purple_input_add(xfer->fd, cond, transfer_cb, xfer); + + priv->ready = PURPLE_XFER_READY_NONE; + + do_transfer(xfer); +} + +void +purple_xfer_prpl_ready(PurpleXfer *xfer) +{ + PurpleXferPrivData *priv; + + g_return_if_fail(xfer != NULL); + + priv = g_hash_table_lookup(xfers_data, xfer); + priv->ready |= PURPLE_XFER_READY_PRPL; + + /* I don't think fwrite/fread are ever *not* ready */ + if (xfer->dest_fp == NULL && 0 == (priv->ready & PURPLE_XFER_READY_UI)) + return; + + priv->ready = PURPLE_XFER_READY_NONE; + + do_transfer(xfer); +} + +void purple_xfer_start(PurpleXfer *xfer, int fd, const char *ip, unsigned int port) { @@ -1081,6 +1225,13 @@ purple_xfer_set_status(xfer, PURPLE_XFER_STATUS_STARTED); + /* + * FIXME 3.0.0 -- there's too much broken code depending on fd == 0 + * meaning "don't use a real fd" + */ + if (fd == 0) + fd = -1; + if (type == PURPLE_XFER_RECEIVE) { cond = PURPLE_INPUT_READ; @@ -1127,7 +1278,7 @@ xfer->watcher = 0; } - if (xfer->fd != 0) + if (xfer->fd != -1) close(xfer->fd); if (xfer->dest_fp != NULL) { @@ -1190,7 +1341,7 @@ xfer->watcher = 0; } - if (xfer->fd != 0) + if (xfer->fd != -1) close(xfer->fd); if (xfer->dest_fp != NULL) { @@ -1255,7 +1406,7 @@ xfer->watcher = 0; } - if (xfer->fd != 0) + if (xfer->fd != -1) close(xfer->fd); if (xfer->dest_fp != NULL) { @@ -1325,6 +1476,9 @@ purple_xfers_init(void) { void *handle = purple_xfers_get_handle(); + xfers_data = g_hash_table_new_full(g_direct_hash, g_direct_equal, + NULL, purple_xfer_priv_data_destroy); + /* register signals */ purple_signal_register(handle, "file-recv-accept", purple_marshal_VOID__POINTER, NULL, 1, @@ -1371,6 +1525,9 @@ purple_signals_disconnect_by_handle(handle); purple_signals_unregister_by_instance(handle); + + g_hash_table_destroy(xfers_data); + xfers_data = NULL; } void diff -r d865064a3104 -r 359800ae7d17 libpurple/ft.h --- a/libpurple/ft.h Wed Aug 12 10:03:47 2009 +0000 +++ b/libpurple/ft.h Wed Aug 12 10:04:54 2009 +0000 @@ -77,10 +77,50 @@ void (*cancel_local)(PurpleXfer *xfer); void (*cancel_remote)(PurpleXfer *xfer); + /** + * UI op to write data received from the prpl. The UI must deal with the + * entire buffer and return size, or it is treated as an error. + * + * @param xfer The file transfer structure + * @param buffer The buffer to write + * @param size The size of the buffer + * + * @return size if the write was successful, or a value between 0 and + * size on error. + * @since 2.6.0 + */ + gssize (*ui_write)(PurpleXfer *xfer, const guchar *buffer, gssize size); + + /** + * UI op to read data to send to the prpl for a file transfer. + * + * @param xfer The file transfer structure + * @param buffer A pointer to a buffer. The UI must allocate this buffer. + * libpurple will free the data. + * @param size The maximum amount of data to put in the buffer. + * + * @returns The amount of data in the buffer, 0 if nothing is available, + * and a negative value if an error occurred and the transfer + * should be cancelled (libpurple will cancel). + * @since 2.6.0 + */ + gssize (*ui_read)(PurpleXfer *xfer, guchar **buffer, gssize size); + + /** + * Op to notify the UI that not all the data read in was written. The UI + * should re-enqueue this data and return it the next time read is called. + * + * This MUST be implemented if read and write are implemented. + * + * @param xfer The file transfer structure + * @param buffer A pointer to the beginning of the unwritten data. + * @param size The amount of unwritten data. + * + * @since 2.6.0 + */ + void (*data_not_sent)(PurpleXfer *xfer, const guchar *buffer, gsize size); + void (*_purple_reserved1)(void); - void (*_purple_reserved2)(void); - void (*_purple_reserved3)(void); - void (*_purple_reserved4)(void); } PurpleXferUiOps; /** @@ -132,7 +172,6 @@ gssize (*read)(guchar **buffer, PurpleXfer *xfer); gssize (*write)(const guchar *buffer, size_t size, PurpleXfer *xfer); void (*ack)(PurpleXfer *xfer, const guchar *buffer, size_t size); - } ops; PurpleXferUiOps *ui_ops; /**< UI-specific operations. */ @@ -548,6 +587,12 @@ * file receive transfer. On send, @a fd must be specified, and * @a ip and @a port are ignored. * + * Prior to libpurple 2.6.0, passing '0' to @a fd was special-cased to + * allow the protocol plugin to facilitate the file transfer itself. As of + * 2.6.0, this is supported (for backward compatibility), but will be + * removed in libpurple 3.0.0. If a prpl detects that the running libpurple + * is running 2.6.0 or higher, it should use the invalid fd '-1'. + * * @param xfer The file transfer. * @param fd The file descriptor for the socket. * @param ip The IP address to connect to. @@ -617,6 +662,28 @@ */ void purple_xfer_conversation_write(PurpleXfer *xfer, char *message, gboolean is_error); +/** + * Allows the UI to signal it's ready to send/receive data (depending on + * the direction of the file transfer. Used when the UI is providing + * read/write/data_not_sent UI ops. + * + * @param xfer The file transfer which is ready. + * + * @since 2.6.0 + */ +void purple_xfer_ui_ready(PurpleXfer *xfer); + +/** + * Allows the prpl to signal it's readh to send/receive data (depending on + * the direction of the file transfer. Used when the prpl provides read/write + * ops and cannot/does not provide a raw fd to the core. + * + * @param xfer The file transfer which is ready. + * + * @since 2.6.0 + */ +void purple_xfer_prpl_ready(PurpleXfer *xfer); + /*@}*/ /**************************************************************************/ diff -r d865064a3104 -r 359800ae7d17 libpurple/protocols/jabber/buddy.c --- a/libpurple/protocols/jabber/buddy.c Wed Aug 12 10:03:47 2009 +0000 +++ b/libpurple/protocols/jabber/buddy.c Wed Aug 12 10:04:54 2009 +0000 @@ -513,6 +513,7 @@ xmlnode_insert_data(binval, enc, -1); g_free(enc); + purple_imgstore_unref(img); } else if (vc_node) { xmlnode *photo; /* TODO: Remove all PHOTO children? (see above note) */ diff -r d865064a3104 -r 359800ae7d17 libpurple/protocols/jabber/chat.c --- a/libpurple/protocols/jabber/chat.c Wed Aug 12 10:03:47 2009 +0000 +++ b/libpurple/protocols/jabber/chat.c Wed Aug 12 10:04:54 2009 +0000 @@ -750,6 +750,7 @@ if(!server || !*server) { purple_notify_error(js->gc, _("Invalid Server"), _("Invalid Server"), NULL); + purple_roomlist_set_in_progress(js->roomlist, FALSE); return; } diff -r d865064a3104 -r 359800ae7d17 libpurple/protocols/jabber/iq.c --- a/libpurple/protocols/jabber/iq.c Wed Aug 12 10:03:47 2009 +0000 +++ b/libpurple/protocols/jabber/iq.c Wed Aug 12 10:04:54 2009 +0000 @@ -282,11 +282,6 @@ id = xmlnode_get_attrib(packet, "id"); iq_type = xmlnode_get_attrib(packet, "type"); - signal_return = GPOINTER_TO_INT(purple_signal_emit_return_1(jabber_plugin, - "jabber-receiving-iq", js->gc, iq_type, id, from, packet)); - if (signal_return) - return; - /* * child will be either the first tag child or NULL if there is no child. * Historically, we used just the 'query' subchild, but newer XEPs use @@ -345,6 +340,11 @@ return; } + signal_return = GPOINTER_TO_INT(purple_signal_emit_return_1(jabber_plugin, + "jabber-receiving-iq", js->gc, iq_type, id, from, packet)); + if (signal_return) + return; + /* First, lets see if a special callback got registered */ if(type == JABBER_IQ_RESULT || type == JABBER_IQ_ERROR) { if((jcd = g_hash_table_lookup(js->iq_callbacks, id))) { diff -r d865064a3104 -r 359800ae7d17 libpurple/protocols/jabber/si.c --- a/libpurple/protocols/jabber/si.c Wed Aug 12 10:03:47 2009 +0000 +++ b/libpurple/protocols/jabber/si.c Wed Aug 12 10:04:54 2009 +0000 @@ -67,7 +67,7 @@ JabberIBBSession *ibb_session; guint ibb_timeout_handle; - FILE *fp; + PurpleCircBuffer *ibb_buffer; } JabberSIXfer; /* some forward declarations */ @@ -1012,18 +1012,8 @@ if (size <= purple_xfer_get_bytes_remaining(xfer)) { purple_debug_info("jabber", "about to write %" G_GSIZE_FORMAT " bytes from IBB stream\n", size); - if(!fwrite(data, size, 1, jsx->fp)) { - purple_debug_error("jabber", "error writing to file\n"); - purple_xfer_cancel_remote(xfer); - return; - } - purple_xfer_set_bytes_sent(xfer, purple_xfer_get_bytes_sent(xfer) + size); - purple_xfer_update_progress(xfer); - - if (purple_xfer_get_bytes_remaining(xfer) == 0) { - purple_xfer_set_completed(xfer, TRUE); - purple_xfer_end(xfer); - } + purple_circ_buffer_append(jsx->ibb_buffer, data, size); + purple_xfer_prpl_ready(xfer); } else { /* trying to write past size of file transfers negotiated size, reject transfer to protect against malicious behaviour */ @@ -1034,6 +1024,25 @@ } +static gssize +jabber_si_xfer_ibb_read(guchar **out_buffer, PurpleXfer *xfer) +{ + JabberSIXfer *jsx = xfer->data; + guchar *buffer; + gsize size; + gsize tmp; + + size = jsx->ibb_buffer->bufused; + *out_buffer = buffer = g_malloc(size); + while ((tmp = purple_circ_buffer_get_max_read(jsx->ibb_buffer))) { + memcpy(buffer, jsx->ibb_buffer->outptr, tmp); + buffer += tmp; + purple_circ_buffer_mark_read(jsx->ibb_buffer, tmp); + } + + return size; +} + static gboolean jabber_si_xfer_ibb_open_cb(JabberStream *js, const char *who, const char *id, xmlnode *open) @@ -1044,21 +1053,10 @@ JabberSIXfer *jsx = (JabberSIXfer *) xfer->data; JabberIBBSession *sess = jabber_ibb_session_create_from_xmlnode(js, who, id, open, xfer); - const char *filename; jabber_si_bytestreams_ibb_timeout_remove(jsx); if (sess) { - /* open the file to write to */ - filename = purple_xfer_get_local_filename(xfer); - jsx->fp = g_fopen(filename, "wb"); - if (jsx->fp == NULL) { - purple_debug_error("jabber", "failed to open file %s for writing: %s\n", - filename, g_strerror(errno)); - purple_xfer_cancel_remote(xfer); - return FALSE; - } - /* setup callbacks here...*/ jabber_ibb_session_set_data_received_callback(sess, jabber_si_xfer_ibb_recv_data_cb); @@ -1068,9 +1066,14 @@ jabber_si_xfer_ibb_error_cb); jsx->ibb_session = sess; + jsx->ibb_buffer = + purple_circ_buffer_new(jabber_ibb_session_get_block_size(sess)); + + /* set up read function */ + purple_xfer_set_read_fnc(xfer, jabber_si_xfer_ibb_read); /* start the transfer */ - purple_xfer_start(xfer, 0, NULL, 0); + purple_xfer_start(xfer, -1, NULL, 0); return TRUE; } else { /* failed to create IBB session */ @@ -1086,32 +1089,17 @@ } } -static void -jabber_si_xfer_ibb_send_data(JabberIBBSession *sess) +static gssize +jabber_si_xfer_ibb_write(const guchar *buffer, size_t len, PurpleXfer *xfer) { - PurpleXfer *xfer = (PurpleXfer *) jabber_ibb_session_get_user_data(sess); JabberSIXfer *jsx = (JabberSIXfer *) xfer->data; - gsize remaining = purple_xfer_get_bytes_remaining(xfer); - gsize packet_size = remaining < jabber_ibb_session_get_block_size(sess) ? - remaining : jabber_ibb_session_get_block_size(sess); - gpointer data = g_malloc(packet_size); - int res; + JabberIBBSession *sess = jsx->ibb_session; + gsize packet_size = len < jabber_ibb_session_get_block_size(sess) ? + len : jabber_ibb_session_get_block_size(sess); - purple_debug_info("jabber", "IBB: about to read %" G_GSIZE_FORMAT " bytes from file %p\n", - packet_size, jsx->fp); - res = fread(data, packet_size, 1, jsx->fp); + jabber_ibb_session_send_data(sess, buffer, packet_size); - if (res == 1) { - jabber_ibb_session_send_data(sess, data, packet_size); - purple_xfer_set_bytes_sent(xfer, - purple_xfer_get_bytes_sent(xfer) + packet_size); - purple_xfer_update_progress(xfer); - } else { - purple_debug_error("jabber", - "jabber_si_xfer_ibb_send_data: error reading from file\n"); - purple_xfer_cancel_local(xfer); - } - g_free(data); + return packet_size; } static void @@ -1127,7 +1115,7 @@ purple_xfer_end(xfer); } else { /* send more... */ - jabber_si_xfer_ibb_send_data(sess); + purple_xfer_prpl_ready(xfer); } } @@ -1135,28 +1123,13 @@ jabber_si_xfer_ibb_opened_cb(JabberIBBSession *sess) { PurpleXfer *xfer = (PurpleXfer *) jabber_ibb_session_get_user_data(sess); - JabberSIXfer *jsx = (JabberSIXfer *) xfer->data; JabberStream *js = jabber_ibb_session_get_js(sess); PurpleConnection *gc = js->gc; PurpleAccount *account = purple_connection_get_account(gc); if (jabber_ibb_session_get_state(sess) == JABBER_IBB_SESSION_OPENED) { - const char *filename = purple_xfer_get_local_filename(xfer); - jsx->fp = g_fopen(filename, "rb"); - if (jsx->fp == NULL) { - purple_debug_error("jabber", "Failed to open file %s for reading: %s\n", - filename, g_strerror(errno)); - purple_xfer_error(purple_xfer_get_type(xfer), account, - jabber_ibb_session_get_who(sess), - _("Failed to open the file")); - purple_xfer_cancel_local(xfer); - return; - } - - purple_xfer_start(xfer, 0, NULL, 0); - purple_xfer_set_bytes_sent(xfer, 0); - purple_xfer_update_progress(xfer); - jabber_si_xfer_ibb_send_data(sess); + purple_xfer_start(xfer, -1, NULL, 0); + purple_xfer_prpl_ready(xfer); } else { /* error */ purple_xfer_error(purple_xfer_get_type(xfer), account, @@ -1171,8 +1144,6 @@ { JabberSIXfer *jsx = (JabberSIXfer *) xfer->data; - purple_xfer_ref(xfer); - jsx->ibb_session = jabber_ibb_session_create(js, jsx->stream_id, purple_xfer_get_remote_user(xfer), xfer); @@ -1187,6 +1158,11 @@ jabber_ibb_session_set_error_callback(jsx->ibb_session, jabber_si_xfer_ibb_error_cb); + purple_xfer_set_write_fnc(xfer, jabber_si_xfer_ibb_write); + + jsx->ibb_buffer = + purple_circ_buffer_new(jabber_ibb_session_get_block_size(jsx->ibb_session)); + /* open the IBB session */ jabber_ibb_session_open(jsx->ibb_session); @@ -1342,10 +1318,8 @@ jabber_ibb_session_destroy(jsx->ibb_session); } - if (jsx->fp) { - purple_debug_info("jabber", - "jabber_si_xfer_free: closing file for IBB transfer\n"); - fclose(jsx->fp); + if (jsx->ibb_buffer) { + purple_circ_buffer_destroy(jsx->ibb_buffer); } purple_debug_info("jabber", "jabber_si_xfer_free(): freeing jsx %p\n", jsx); @@ -1356,7 +1330,6 @@ g_free(jsx->rxqueue); g_free(jsx); xfer->data = NULL; - } } @@ -1632,7 +1605,6 @@ jsx->local_streamhost_fd = -1; jsx->ibb_session = NULL; - jsx->fp = NULL; purple_xfer_set_init_fnc(xfer, jabber_si_xfer_init); purple_xfer_set_cancel_send_fnc(xfer, jabber_si_xfer_cancel_send); diff -r d865064a3104 -r 359800ae7d17 libpurple/protocols/msn/msg.c --- a/libpurple/protocols/msn/msg.c Wed Aug 12 10:03:47 2009 +0000 +++ b/libpurple/protocols/msn/msg.c Wed Aug 12 10:04:54 2009 +0000 @@ -1102,6 +1102,7 @@ { GHashTable *body; const gchar *guid; + gboolean accepted = FALSE; g_return_if_fail(cmdproc != NULL); g_return_if_fail(msg != NULL); @@ -1129,6 +1130,9 @@ } else purple_debug_warning("msn", "Invite msg missing " "Application-GUID.\n"); + + accepted = TRUE; + } else if (!strcmp(guid, "{02D3C01F-BF30-4825-A83A-DE7AF41648AA}")) { purple_debug_info("msn", "Computer call\n"); @@ -1154,9 +1158,35 @@ g_free(buf); } } - } else - purple_debug_warning("msn", - "Unhandled invite msg with GUID %s.\n", guid); + } else { + const gchar *application = g_hash_table_lookup(body, "Application-Name"); + purple_debug_warning("msn", "Unhandled invite msg with GUID %s: %s.\n", + guid, application ? application : "(null)"); + } + + if (!accepted) { + const gchar *cookie = g_hash_table_lookup(body, "Invitation-Cookie"); + if (cookie) { + MsnSwitchBoard *swboard = cmdproc->data; + char *text; + MsnMessage *cancel; + + cancel = msn_message_new(MSN_MSG_TEXT); + msn_message_set_content_type(cancel, "text/x-msmsgsinvite"); + msn_message_set_charset(cancel, "UTF-8"); + msn_message_set_flag(cancel, 'U'); + + text = g_strdup_printf("Invitation-Command: CANCEL\r\n" + "Invitation-Cookie: %s\r\n" + "Cancel-Code: REJECT_NOT_INSTALLED\r\n", + cookie); + msn_message_set_bin_data(cancel, text, strlen(text)); + g_free(text); + + msn_switchboard_send_msg(swboard, cancel, TRUE); + msn_message_destroy(cancel); + } + } g_hash_table_destroy(body); } diff -r d865064a3104 -r 359800ae7d17 libpurple/protocols/msn/slp.c --- a/libpurple/protocols/msn/slp.c Wed Aug 12 10:03:47 2009 +0000 +++ b/libpurple/protocols/msn/slp.c Wed Aug 12 10:04:54 2009 +0000 @@ -244,6 +244,8 @@ got_sessionreq(MsnSlpCall *slpcall, const char *branch, const char *euf_guid, const char *context) { + gboolean accepted = FALSE; + if (!strcmp(euf_guid, MSN_OBJ_GUID)) { /* Emoticon or UserDisplay */ @@ -314,7 +316,10 @@ msn_slpmsg_set_image(slpmsg, img); msn_slplink_queue_slpmsg(slplink, slpmsg); purple_imgstore_unref(img); + + accepted = TRUE; } + else if (!strcmp(euf_guid, MSN_FT_GUID)) { /* File Transfer */ @@ -360,6 +365,9 @@ purple_xfer_request(xfer); } + + accepted = TRUE; + } else if (!strcmp(euf_guid, MSN_CAM_REQUEST_GUID)) { purple_debug_info("msn", "Cam request.\n"); if (slpcall && slpcall->slplink && @@ -382,6 +390,7 @@ g_free(buf); } } + } else if (!strcmp(euf_guid, MSN_CAM_GUID)) { purple_debug_info("msn", "Cam invite.\n"); if (slpcall && slpcall->slplink && @@ -404,8 +413,16 @@ g_free(buf); } } + } else purple_debug_warning("msn", "SLP SessionReq with unknown EUF-GUID: %s\n", euf_guid); + + if (!accepted) { + char *content = g_strdup_printf("SessionID: %lu\r\n\r\n", + slpcall->session_id); + send_decline(slpcall, branch, "application/x-msnmsgr-sessionreqbody", content); + g_free(content); + } } void diff -r d865064a3104 -r 359800ae7d17 libpurple/protocols/msn/slplink.c --- a/libpurple/protocols/msn/slplink.c Wed Aug 12 10:03:47 2009 +0000 +++ b/libpurple/protocols/msn/slplink.c Wed Aug 12 10:04:54 2009 +0000 @@ -456,7 +456,7 @@ slpmsg->info = "SLP FILE"; xfer = (PurpleXfer *)slpcall->xfer; - purple_xfer_start(slpcall->xfer, 0, NULL, 0); + purple_xfer_start(slpcall->xfer, -1, NULL, 0); slpmsg->fp = xfer->dest_fp; if (g_stat(purple_xfer_get_local_filename(xfer), &st) == 0) slpmsg->size = st.st_size; @@ -537,7 +537,7 @@ if (xfer != NULL) { purple_xfer_ref(xfer); - purple_xfer_start(xfer, 0, NULL, 0); + purple_xfer_start(xfer, -1, NULL, 0); if (xfer->data == NULL) { purple_xfer_unref(xfer); diff -r d865064a3104 -r 359800ae7d17 libpurple/protocols/msnp9/slplink.c --- a/libpurple/protocols/msnp9/slplink.c Wed Aug 12 10:03:47 2009 +0000 +++ b/libpurple/protocols/msnp9/slplink.c Wed Aug 12 10:04:54 2009 +0000 @@ -496,7 +496,7 @@ slpmsg->info = "SLP FILE"; #endif xfer = (PurpleXfer *)slpcall->xfer; - purple_xfer_start(slpcall->xfer, 0, NULL, 0); + purple_xfer_start(slpcall->xfer, -1, NULL, 0); slpmsg->fp = xfer->dest_fp; if (g_stat(purple_xfer_get_local_filename(xfer), &st) == 0) slpmsg->size = st.st_size; @@ -561,7 +561,7 @@ if (xfer != NULL) { purple_xfer_ref(xfer); - purple_xfer_start(xfer, 0, NULL, 0); + purple_xfer_start(xfer, -1, NULL, 0); if (xfer->data == NULL) { purple_xfer_unref(xfer); diff -r d865064a3104 -r 359800ae7d17 pidgin/gtkimhtml.c --- a/pidgin/gtkimhtml.c Wed Aug 12 10:03:47 2009 +0000 +++ b/pidgin/gtkimhtml.c Wed Aug 12 10:04:54 2009 +0000 @@ -2953,7 +2953,7 @@ font->size = oldfont->size; else font->size = 3; - if ((imhtml->format_functions & (GTK_IMHTML_GROW|GTK_IMHTML_SHRINK))) + if ((imhtml->format_functions & (GTK_IMHTML_GROW|GTK_IMHTML_SHRINK)) && (font->size != 3 || (oldfont && oldfont->size == 3))) gtk_imhtml_font_set_size(imhtml, font->size); g_free(size); fonts = g_slist_prepend (fonts, font); diff -r d865064a3104 -r 359800ae7d17 pidgin/gtkmedia.c --- a/pidgin/gtkmedia.c Wed Aug 12 10:03:47 2009 +0000 +++ b/pidgin/gtkmedia.c Wed Aug 12 10:04:54 2009 +0000 @@ -500,7 +500,7 @@ gtkmedia->priv->request_type = PURPLE_MEDIA_NONE; - purple_request_accept_cancel(gtkmedia, "Incoming Call", + purple_request_accept_cancel(gtkmedia, _("Incoming Call"), message, NULL, PURPLE_DEFAULT_ACTION_NONE, (void*)account, gtkmedia->priv->screenname, NULL, gtkmedia->priv->media, diff -r d865064a3104 -r 359800ae7d17 po/nn.po --- a/po/nn.po Wed Aug 12 10:03:47 2009 +0000 +++ b/po/nn.po Wed Aug 12 10:04:54 2009 +0000 @@ -2,8 +2,8 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-08-02 23:34-0700\n" -"PO-Revision-Date: 2009-08-01 13:29+0100\n" +"POT-Creation-Date: 2009-08-09 19:06-0700\n" +"PO-Revision-Date: 2009-08-09 02:41+0100\n" "Last-Translator: Yngve Spjeld Landro \n" "Language-Team: \n" "MIME-Version: 1.0\n" @@ -12132,6 +12132,9 @@ msgid "%s wishes to start a video session with you." msgstr "%s ønskjer å starta ei biletøkt med deg." +msgid "_Pause" +msgstr "_Pause" + #, c-format msgid "%s has %d new message." msgid_plural "%s has %d new messages." @@ -12673,7 +12676,7 @@ "(%s for filnamn)" msgid "M_ute sounds" -msgstr "&Demp lydar" +msgstr "_Demp lydar" msgid "Sounds when conversation has _focus" msgstr "Lydar medan samtalevindauget har _fokus" @@ -12688,7 +12691,7 @@ msgstr "Spel" msgid "_Browse..." -msgstr "Bla &gjennom…" +msgstr "Bla _gjennom…" msgid "_Reset" msgstr "_Nullstill" @@ -13068,9 +13071,6 @@ msgid "_Open Mail" msgstr "_Opna e-post" -msgid "_Pause" -msgstr "_Pause" - msgid "_Edit" msgstr "_Endra"