Mercurial > pidgin.yaz
changeset 28222:6fca316de1e2
merged with im.pidgin.pidgin
author | Yoshiki Yazawa <yaz@honeyplanet.jp> |
---|---|
date | Wed, 12 Aug 2009 02:05:32 +0900 |
parents | 766f7905314a (current diff) e502112a03e7 (diff) |
children | 90d108cda54e |
files | libpurple/protocols/jabber/si.c |
diffstat | 8 files changed, 183 insertions(+), 50 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog.API Mon Aug 10 20:36:54 2009 +0900 +++ b/ChangeLog.API Wed Aug 12 02:05:32 2009 +0900 @@ -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,7 @@ * purple_strequal * purple_utf8_strip_unprintables * purple_util_fetch_url_request_len_with_account + * purple_xfer_ui_ready * xmlnode_from_file * xmlnode_get_parent * xmlnode_set_attrib_full @@ -95,6 +99,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
--- a/libpurple/ft.c Mon Aug 10 20:36:54 2009 +0900 +++ b/libpurple/ft.c Wed Aug 12 02:05:32 2009 +0900 @@ -482,13 +482,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 +502,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->read == NULL && ui_ops->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 +524,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); } @@ -946,10 +953,17 @@ guchar *buffer = NULL; gssize r = 0; + ui_ops = purple_xfer_get_ui_ops(xfer); + if (condition & PURPLE_INPUT_READ) { 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->write) + wc = ui_ops->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); @@ -975,26 +989,53 @@ return; } - buffer = g_malloc0(s); + if (ui_ops && ui_ops->read) { + gssize tmp = ui_ops->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->read == NULL && ui_ops->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 +1057,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)); @@ -1031,19 +1070,22 @@ 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->read == NULL && ui_ops->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 +1110,26 @@ } void +purple_xfer_ui_ready(PurpleXfer *xfer) +{ + PurpleInputCondition cond; + PurpleXferType type; + + g_return_if_fail(xfer != NULL); + + 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); + + transfer_cb(xfer, 0, cond); +} + +void purple_xfer_start(PurpleXfer *xfer, int fd, const char *ip, unsigned int port) { @@ -1081,6 +1143,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 +1196,7 @@ xfer->watcher = 0; } - if (xfer->fd != 0) + if (xfer->fd != -1) close(xfer->fd); if (xfer->dest_fp != NULL) { @@ -1190,7 +1259,7 @@ xfer->watcher = 0; } - if (xfer->fd != 0) + if (xfer->fd != -1) close(xfer->fd); if (xfer->dest_fp != NULL) { @@ -1255,7 +1324,7 @@ xfer->watcher = 0; } - if (xfer->fd != 0) + if (xfer->fd != -1) close(xfer->fd); if (xfer->dest_fp != NULL) {
--- a/libpurple/ft.h Mon Aug 10 20:36:54 2009 +0900 +++ b/libpurple/ft.h Wed Aug 12 02:05:32 2009 +0900 @@ -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 (*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 (*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,16 @@ */ 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. + * + * @param xfer The file transfer for which data is ready. + * + * @since 2.6.0 + */ +void purple_xfer_ui_ready(PurpleXfer *xfer); + /*@}*/ /**************************************************************************/
--- a/libpurple/protocols/jabber/buddy.c Mon Aug 10 20:36:54 2009 +0900 +++ b/libpurple/protocols/jabber/buddy.c Wed Aug 12 02:05:32 2009 +0900 @@ -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) */
--- a/libpurple/protocols/jabber/iq.c Mon Aug 10 20:36:54 2009 +0900 +++ b/libpurple/protocols/jabber/iq.c Wed Aug 12 02:05:32 2009 +0900 @@ -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))) {
--- a/libpurple/protocols/jabber/si.c Mon Aug 10 20:36:54 2009 +0900 +++ b/libpurple/protocols/jabber/si.c Wed Aug 12 02:05:32 2009 +0900 @@ -1072,7 +1072,7 @@ jsx->ibb_session = sess; /* 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 */ @@ -1155,7 +1155,7 @@ return; } - purple_xfer_start(xfer, 0, NULL, 0); + purple_xfer_start(xfer, -1, NULL, 0); purple_xfer_set_bytes_sent(xfer, 0); purple_xfer_update_progress(xfer); jabber_si_xfer_ibb_send_data(sess);
--- a/libpurple/protocols/msn/slplink.c Mon Aug 10 20:36:54 2009 +0900 +++ b/libpurple/protocols/msn/slplink.c Wed Aug 12 02:05:32 2009 +0900 @@ -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);
--- a/libpurple/protocols/msnp9/slplink.c Mon Aug 10 20:36:54 2009 +0900 +++ b/libpurple/protocols/msnp9/slplink.c Wed Aug 12 02:05:32 2009 +0900 @@ -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);