Mercurial > pidgin.yaz
changeset 25502:ee966d2dc151
propagate from branch 'im.pidgin.pidgin' (head dff846c19b3c14ce3094dda9a5b72c70e6e11121)
to branch 'im.pidgin.pidgin.yaz' (head 96dcf99b9a4d5aec09c2173b5f2f901d96330dbd)
author | Yoshiki Yazawa <yaz@honeyplanet.jp> |
---|---|
date | Sat, 09 Jun 2007 04:12:47 +0000 |
parents | be1c61b5f30d (current diff) cf0e01adfaa9 (diff) |
children | 7577706bde9c |
files | libpurple/protocols/jabber/jabber.c |
diffstat | 13 files changed, 452 insertions(+), 260 deletions(-) [+] |
line wrap: on
line diff
--- a/COPYRIGHT Fri Jun 08 03:19:13 2007 +0000 +++ b/COPYRIGHT Sat Jun 09 04:12:47 2007 +0000 @@ -226,6 +226,7 @@ Lalo Martins John Matthews Simo Mattila +Michal Matyska Ryan McCabe Peter McCurdy Kurt McKee
--- a/libpurple/protocols/bonjour/bonjour.c Fri Jun 08 03:19:13 2007 +0000 +++ b/libpurple/protocols/bonjour/bonjour.c Sat Jun 09 04:12:47 2007 +0000 @@ -267,6 +267,7 @@ bonjour_convo_closed(PurpleConnection *connection, const char *who) { PurpleBuddy *buddy = purple_find_buddy(connection->account, who); + BonjourBuddy *bb; if (buddy == NULL) { @@ -277,7 +278,9 @@ return; } - bonjour_jabber_close_conversation(((BonjourData*)(connection->proto_data))->jabber_data, buddy); + bb = buddy->proto_data; + bonjour_jabber_close_conversation(bb->conversation); + bb->conversation = NULL; } static char * @@ -320,6 +323,8 @@ static gboolean plugin_unload(PurplePlugin *plugin) { + /* These shouldn't happen here because they are allocated in _init() */ + g_free(default_firstname); g_free(default_lastname); g_free(default_hostname);
--- a/libpurple/protocols/bonjour/buddy.c Fri Jun 08 03:19:13 2007 +0000 +++ b/libpurple/protocols/bonjour/buddy.c Sat Jun 09 04:12:47 2007 +0000 @@ -178,11 +178,8 @@ g_free(buddy->node); g_free(buddy->ver); - if (buddy->conversation != NULL) - { - g_free(buddy->conversation->buddy_name); - g_free(buddy->conversation); - } + bonjour_jabber_close_conversation(buddy->conversation); + buddy->conversation = NULL; #ifdef USE_BONJOUR_APPLE if (buddy->txt_query != NULL)
--- a/libpurple/protocols/bonjour/jabber.c Fri Jun 08 03:19:13 2007 +0000 +++ b/libpurple/protocols/bonjour/jabber.c Sat Jun 09 04:12:47 2007 +0000 @@ -28,7 +28,6 @@ #endif #include <sys/types.h> #include <glib.h> -#include <glib/gprintf.h> #include <unistd.h> #include <fcntl.h> @@ -45,39 +44,10 @@ #include "bonjour.h" #include "buddy.h" -static gint -_connect_to_buddy(PurpleBuddy *gb) -{ - gint socket_fd; - struct sockaddr_in buddy_address; - BonjourBuddy *bb = gb->proto_data; - - purple_debug_info("bonjour", "Connecting to buddy %s at %s:%d.\n", - purple_buddy_get_name(gb), bb->ip ? bb->ip : "(null)", bb->port_p2pj); - - /* Create a socket and make it non-blocking */ - socket_fd = socket(PF_INET, SOCK_STREAM, 0); - if (socket_fd < 0) { - purple_debug_warning("bonjour", "Error opening socket: %s\n", strerror(errno)); - return -1; - } - - buddy_address.sin_family = PF_INET; - buddy_address.sin_port = htons(bb->port_p2pj); - inet_aton(bb->ip, &(buddy_address.sin_addr)); - memset(&(buddy_address.sin_zero), '\0', 8); - - /* TODO: make this nonblocking before connecting */ - if (connect(socket_fd, (struct sockaddr*)&buddy_address, sizeof(struct sockaddr)) == 0) - fcntl(socket_fd, F_SETFL, O_NONBLOCK); - else { - purple_debug_warning("bonjour", "Error connecting to buddy %s at %s:%d error: %s\n", purple_buddy_get_name(gb), bb->ip ? bb->ip : "(null)", bb->port_p2pj, strerror(errno)); - close(socket_fd); - socket_fd = -1; - } - - return socket_fd; -} +#define STREAM_END "</stream:stream>" +/* TODO: specify version='1.0' and send stream features */ +#define DOCTYPE "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" \ + "<stream:stream xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\" from=\"%s\" to=\"%s\">" #if 0 /* this isn't used anywhere... */ static const char * @@ -104,6 +74,19 @@ } #endif +static BonjourJabberConversation * +bonjour_jabber_conv_new() { + + BonjourJabberConversation *bconv = g_new0(BonjourJabberConversation, 1); + bconv->socket = -1; + bconv->tx_buf = purple_circ_buffer_new(512); + bconv->tx_handler = -1; + bconv->rx_handler = -1; + + return bconv; +} + + static const char * _font_size_ichat_to_purple(int size) { @@ -125,9 +108,9 @@ } static void -_jabber_parse_and_write_message_to_ui(char *message, PurpleConnection *connection, PurpleBuddy *gb) +_jabber_parse_and_write_message_to_ui(xmlnode *message_node, PurpleConnection *connection, PurpleBuddy *pb) { - xmlnode *message_node, *body_node, *html_node, *events_node; + xmlnode *body_node, *html_node, *events_node; char *body, *html_body = NULL; const char *ichat_balloon_color = NULL; const char *ichat_text_color = NULL; @@ -136,16 +119,9 @@ const char *font_color = NULL; gboolean composing_event = FALSE; - /* Parsing of the message */ - message_node = xmlnode_from_str(message, strlen(message)); - if (message_node == NULL) + body_node = xmlnode_get_child(message_node, "body"); + if (body_node == NULL) return; - - body_node = xmlnode_get_child(message_node, "body"); - if (body_node == NULL) { - xmlnode_free(message_node); - return; - } body = xmlnode_get_data(body_node); html_node = xmlnode_get_child(message_node, "html"); @@ -171,11 +147,8 @@ font_color = xmlnode_get_attrib(html_body_font_node, "color"); html_body = xmlnode_get_data(html_body_font_node); if (html_body == NULL) - { - gint garbage = -1; /* This is the kind of formated messages that Purple creates */ - html_body = xmlnode_to_str(html_body_font_node, &garbage); - } + html_body = xmlnode_to_str(html_body_font_node, NULL); } } } @@ -184,14 +157,11 @@ if (events_node != NULL) { if (xmlnode_get_child(events_node, "composing") != NULL) - { composing_event = TRUE; - } if (xmlnode_get_child(events_node, "id") != NULL) { /* The user is just typing */ /* TODO: Deal with typing notification */ - xmlnode_free(message_node); g_free(body); g_free(html_body); return; @@ -207,31 +177,30 @@ if (font_size == NULL) font_size = "3"; if (ichat_text_color == NULL) ichat_text_color = "#000000"; if (ichat_balloon_color == NULL) ichat_balloon_color = "#FFFFFF"; - body = g_strconcat("<font face='", font_face, "' size='", font_size, "' color='", ichat_text_color, - "' back='", ichat_balloon_color, "'>", html_body, "</font>", NULL); + body = g_strdup_printf("<font face='%s' size='%s' color='%s' back='%s'>%s</font>", + font_face, font_size, ichat_text_color, ichat_balloon_color, + html_body); } /* TODO: Should we do something with "composing_event" here? */ /* Send the message to the UI */ - serv_got_im(connection, gb->name, body, 0, time(NULL)); + serv_got_im(connection, pb->name, body, 0, time(NULL)); - /* Free all the strings and nodes (the attributes are freed with their nodes) */ - xmlnode_free(message_node); g_free(body); g_free(html_body); } struct _check_buddy_by_address_t { const char *address; - PurpleBuddy **gb; + PurpleBuddy **pb; BonjourJabber *bj; }; static void _check_buddy_by_address(gpointer key, gpointer value, gpointer data) { - PurpleBuddy *gb = value; + PurpleBuddy *pb = value; BonjourBuddy *bb; struct _check_buddy_by_address_t *cbba = data; @@ -240,11 +209,11 @@ * is the same as the account requesting the check then continue to determine * whether the buddies IP matches the target IP. */ - if (cbba->bj->account == gb->account) + if (cbba->bj->account == pb->account) { - bb = gb->proto_data; + bb = pb->proto_data; if ((bb != NULL) && (g_ascii_strcasecmp(bb->ip, cbba->address) == 0)) - *(cbba->gb) = gb; + *(cbba->pb) = pb; } } @@ -279,24 +248,96 @@ return total_message_length; } -static gint -_send_data(gint socket, char *message) +static void +_send_data_write_cb(gpointer data, gint source, PurpleInputCondition cond) { - gint message_len = strlen(message); - gint partial_sent = 0; - gchar *partial_message = message; + PurpleBuddy *pb = data; + BonjourBuddy *bb = pb->proto_data; + BonjourJabberConversation *bconv = bb->conversation; + int ret, writelen; + + /* TODO: Make sure that the stream has been established before sending */ + + writelen = purple_circ_buffer_get_max_read(bconv->tx_buf); + + if (writelen == 0) { + purple_input_remove(bconv->tx_handler); + bconv->tx_handler = -1; + return; + } - while ((partial_sent = send(socket, partial_message, message_len, 0)) < message_len) - { - if (partial_sent != -1) { - partial_message += partial_sent; - message_len -= partial_sent; - } else { - return -1; - } + ret = send(bconv->socket, bconv->tx_buf->outptr, writelen, 0); + + if (ret < 0 && errno == EAGAIN) + return; + else if (ret <= 0) { + PurpleConversation *conv; + const char *error = strerror(errno); + + purple_debug_error("bonjour", "Error sending message to buddy %s error: %s\n", + purple_buddy_get_name(pb), error ? error : "(null)"); + + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bb->name, pb->account); + if (conv != NULL) + purple_conversation_write(conv, NULL, + _("Unable to send message."), + PURPLE_MESSAGE_SYSTEM, time(NULL)); + + bonjour_jabber_close_conversation(bb->conversation); + bb->conversation = NULL; + return; } - return strlen(message); + purple_circ_buffer_mark_read(bconv->tx_buf, ret); +} + +static gint +_send_data(PurpleBuddy *pb, char *message) +{ + gint ret; + int len = strlen(message); + BonjourBuddy *bb = pb->proto_data; + BonjourJabberConversation *bconv = bb->conversation; + + /* If we're not ready to actually send, append it to the buffer */ + if (bconv->tx_handler != -1 + || bconv->connect_data != NULL + || !bconv->stream_started + || purple_circ_buffer_get_max_read(bconv->tx_buf) > 0) { + ret = -1; + errno = EAGAIN; + } else { + ret = send(bconv->socket, message, len, 0); + } + + if (ret == -1 && errno == EAGAIN) + ret = 0; + else if (ret <= 0) { + PurpleConversation *conv; + const char *error = strerror(errno); + + purple_debug_error("bonjour", "Error sending message to buddy %s error: %s\n", + purple_buddy_get_name(pb), error ? error : "(null)"); + + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bb->name, pb->account); + if (conv != NULL) + purple_conversation_write(conv, NULL, + _("Unable to send message."), + PURPLE_MESSAGE_SYSTEM, time(NULL)); + + bonjour_jabber_close_conversation(bb->conversation); + bb->conversation = NULL; + return -1; + } + + if (ret < len) { + if (bconv->tx_handler == -1) + bconv->tx_handler = purple_input_add(bconv->socket, PURPLE_INPUT_WRITE, + _send_data_write_cb, pb); + purple_circ_buffer_append(bconv->tx_buf, message + ret, len - ret); + } + + return ret; } static void @@ -304,17 +345,22 @@ { char *message = NULL; gint message_length; - PurpleBuddy *gb = data; - PurpleAccount *account = gb->account; - PurpleConversation *conversation; - BonjourBuddy *bb = gb->proto_data; + PurpleBuddy *pb = data; + PurpleAccount *account = pb->account; + BonjourBuddy *bb = pb->proto_data; gboolean closed_conversation = FALSE; xmlnode *message_node; /* Read the data from the socket */ if ((message_length = _read_data(socket, &message)) == -1) { /* There have been an error reading from the socket */ - /* TODO: Shouldn't we handle the error if it isn't EAGAIN? */ + if (errno != EAGAIN) { + bonjour_jabber_close_conversation(bb->conversation); + bb->conversation = NULL; + + /* I guess we really don't need to notify the user. + * If they try to send another message it'll reconnect */ + } return; } else if (message_length == 0) { /* The other end has closed the socket */ closed_conversation = TRUE; @@ -330,62 +376,106 @@ /* Parse the message into an XMLnode for analysis */ message_node = xmlnode_from_str(message, strlen(message)); - /* Check if the start of the stream has been received, if not check that the current */ - /* data is the start of the stream */ - if (!(bb->conversation->stream_started)) - { - /* Check if this is the start of the stream */ - if ((message_node != NULL) && - g_ascii_strcasecmp(xmlnode_get_attrib(message_node, "xmlns"), "jabber:client") && - (xmlnode_get_attrib(message_node,"xmlns:stream") != NULL)) - { - bb->conversation->stream_started = TRUE; - } - else - { - /* TODO: This needs to be nonblocking! */ - if (send(bb->conversation->socket, DOCTYPE, strlen(DOCTYPE), 0) == -1) - purple_debug_error("bonjour", "Unable to start a conversation with %s\n", bb->name); - else - bb->conversation->stream_started = TRUE; - } - } - /* * Check that this is not the end of the conversation. This is * using a magic string, but xmlnode won't play nice when just * parsing an end tag */ - if (purple_str_has_prefix(message, STREAM_END) || (closed_conversation == TRUE)) { - char *closed_conv_message; + if (closed_conversation || purple_str_has_prefix(message, STREAM_END)) { + PurpleConversation *conv; /* Close the socket, clear the watcher and free memory */ - if (bb->conversation != NULL) { - close(bb->conversation->socket); - purple_input_remove(bb->conversation->watcher_id); - g_free(bb->conversation->buddy_name); - g_free(bb->conversation); - bb->conversation = NULL; - } + bonjour_jabber_close_conversation(bb->conversation); + bb->conversation = NULL; /* Inform the user that the conversation has been closed */ - conversation = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, gb->name, account); - closed_conv_message = g_strdup_printf(_("%s has closed the conversation."), gb->name); - purple_conversation_write(conversation, NULL, closed_conv_message, PURPLE_MESSAGE_SYSTEM, time(NULL)); - g_free(closed_conv_message); + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, pb->name, account); + if (conv != NULL) { + char *tmp = g_strdup_printf(_("%s has closed the conversation."), pb->name); + purple_conversation_write(conv, NULL, tmp, PURPLE_MESSAGE_SYSTEM, time(NULL)); + g_free(tmp); + } + } else if (message_node != NULL) { + /* Parse the message to get the data and send to the ui */ + _jabber_parse_and_write_message_to_ui(message_node, account->gc, pb); } else { - /* Parse the message to get the data and send to the ui */ - _jabber_parse_and_write_message_to_ui(message, account->gc, gb); + /* TODO: Deal with receiving only a partial message */ } + g_free(message); if (message_node != NULL) xmlnode_free(message_node); } +struct _stream_start_data { + char *msg; + PurpleInputFunction tx_handler_cb; +}; + +static void +_start_stream(gpointer data, gint source, PurpleInputCondition condition) +{ + PurpleBuddy *pb = data; + BonjourBuddy *bb = pb->proto_data; + struct _stream_start_data *ss = bb->conversation->stream_data; + int len, ret; + + len = strlen(ss->msg); + + /* Start Stream */ + ret = send(source, ss->msg, len, 0); + + if (ret == -1 && errno == EAGAIN) + return; + else if (ret <= 0) { + const char *err = strerror(errno); + PurpleConversation *conv; + + purple_debug_error("bonjour", "Error starting stream with buddy %s at %s:%d error: %s\n", + purple_buddy_get_name(pb), bb->ip ? bb->ip : "(null)", bb->port_p2pj, err ? err : "(null)"); + + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bb->name, pb->account); + if (conv != NULL) + purple_conversation_write(conv, NULL, + _("Unable to send the message, the conversation couldn't be started."), + PURPLE_MESSAGE_SYSTEM, time(NULL)); + + bonjour_jabber_close_conversation(bb->conversation); + bb->conversation = NULL; + + return; + } + + /* This is EXTREMELY unlikely to happen */ + if (ret < len) { + char *tmp = g_strdup(ss->msg + ret); + g_free(ss->msg); + ss->msg = tmp; + return; + } + + /* Stream started; process the send buffer if there is one*/ + purple_input_remove(bb->conversation->tx_handler); + bb->conversation->tx_handler= -1; + + bb->conversation->stream_started = TRUE; + + g_free(ss->msg); + g_free(ss); + bb->conversation->stream_data = NULL; + + if (ss->tx_handler_cb) { + bb->conversation->tx_handler = purple_input_add(source, PURPLE_INPUT_WRITE, + ss->tx_handler_cb, pb); + /* We can probably write the data now. */ + (ss->tx_handler_cb)(pb, source, PURPLE_INPUT_WRITE); + } +} + static void _server_socket_handler(gpointer data, int server_socket, PurpleInputCondition condition) { - PurpleBuddy *gb = NULL; + PurpleBuddy *pb = NULL; struct sockaddr_in their_addr; /* connector's address information */ socklen_t sin_size = sizeof(struct sockaddr); int client_socket; @@ -407,36 +497,63 @@ address_text = inet_ntoa(their_addr.sin_addr); cbba = g_new0(struct _check_buddy_by_address_t, 1); cbba->address = address_text; - cbba->gb = &gb; + cbba->pb = &pb; cbba->bj = data; g_hash_table_foreach(bl->buddies, _check_buddy_by_address, cbba); g_free(cbba); - if (gb == NULL) + if (pb == NULL) { purple_debug_info("bonjour", "We don't like invisible buddies, this is not a superheros comic\n"); close(client_socket); return; } - bb = gb->proto_data; + bb = pb->proto_data; /* Check if the conversation has been previously started */ if (bb->conversation == NULL) { - bb->conversation = g_new(BonjourJabberConversation, 1); + int ret, len; + char *stream_start = g_strdup_printf(DOCTYPE, purple_account_get_username(pb->account), + purple_buddy_get_name(pb)); + + len = strlen(stream_start); + + /* Start the stream */ + ret = send(client_socket, stream_start, len, 0); + + if (ret == -1 && errno == EAGAIN) + ret = 0; + else if (ret <= 0) { + const char *err = strerror(errno); + + purple_debug_error("bonjour", "Error starting stream with buddy %s at %s:%d error: %s\n", + purple_buddy_get_name(pb), bb->ip ? bb->ip : "(null)", bb->port_p2pj, err ? err : "(null)"); + + close(client_socket); + g_free(stream_start); + + return; + } + + bb->conversation = bonjour_jabber_conv_new(); bb->conversation->socket = client_socket; - bb->conversation->stream_started = FALSE; - bb->conversation->buddy_name = g_strdup(gb->name); - bb->conversation->message_id = 1; + bb->conversation->rx_handler = purple_input_add(client_socket, + PURPLE_INPUT_READ, _client_socket_handler, pb); - if (bb->conversation->stream_started == FALSE) { - /* Start the stream */ - send(bb->conversation->socket, DOCTYPE, strlen(DOCTYPE), 0); + /* This is unlikely to happen */ + if (ret < len) { + struct _stream_start_data *ss = g_new(struct _stream_start_data, 1); + ss->msg = g_strdup(stream_start + ret); + ss->tx_handler_cb = NULL; /* We have nothing to write yet */ + bb->conversation->stream_data = ss; + /* Finish sending the stream start */ + bb->conversation->tx_handler = purple_input_add(client_socket, + PURPLE_INPUT_WRITE, _start_stream, pb); + } else { bb->conversation->stream_started = TRUE; } - /* Open a watcher for the client socket */ - bb->conversation->watcher_id = purple_input_add(client_socket, PURPLE_INPUT_READ, - _client_socket_handler, gb); + g_free(stream_start); } else { close(client_socket); } @@ -514,134 +631,199 @@ return data->port; } +static void +_connected_to_buddy(gpointer data, gint source, const gchar *error) +{ + PurpleBuddy *pb = data; + BonjourBuddy *bb = pb->proto_data; + int len, ret; + char *stream_start = g_strdup_printf(DOCTYPE, purple_account_get_username(pb->account), purple_buddy_get_name(pb)); + + bb->conversation->connect_data = NULL; + + if (source < 0) { + PurpleConversation *conv; + + purple_debug_error("bonjour", "Error connecting to buddy %s at %s:%d error: %s\n", + purple_buddy_get_name(pb), bb->ip ? bb->ip : "(null)", bb->port_p2pj, error ? error : "(null)"); + + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bb->name, pb->account); + if (conv != NULL) + purple_conversation_write(conv, NULL, + _("Unable to send the message, the conversation couldn't be started."), + PURPLE_MESSAGE_SYSTEM, time(NULL)); + + bonjour_jabber_close_conversation(bb->conversation); + bb->conversation = NULL; + return; + } + + len = strlen(stream_start); + + /* Start the stream and send queued messages */ + ret = send(source, stream_start, len, 0); + + if (ret == -1 && errno == EAGAIN) + ret = 0; + else if (ret <= 0) { + const char *err = strerror(errno); + PurpleConversation *conv; + + purple_debug_error("bonjour", "Error starting stream with buddy %s at %s:%d error: %s\n", + purple_buddy_get_name(pb), bb->ip ? bb->ip : "(null)", bb->port_p2pj, err ? err : "(null)"); + + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bb->name, pb->account); + if (conv != NULL) + purple_conversation_write(conv, NULL, + _("Unable to send the message, the conversation couldn't be started."), + PURPLE_MESSAGE_SYSTEM, time(NULL)); + + close(source); + bonjour_jabber_close_conversation(bb->conversation); + bb->conversation = NULL; + + g_free(stream_start); + + return; + } + + bb->conversation->socket = source; + bb->conversation->rx_handler = purple_input_add(source, + PURPLE_INPUT_READ, _client_socket_handler, pb); + + /* This is unlikely to happen */ + if (ret < len) { + struct _stream_start_data *ss = g_new(struct _stream_start_data, 1); + ss->msg = g_strdup(stream_start + ret); + ss->tx_handler_cb = _send_data_write_cb; + bb->conversation->stream_data = ss; + /* Finish sending the stream start */ + bb->conversation->tx_handler = purple_input_add(source, + PURPLE_INPUT_WRITE, _start_stream, pb); + } + /* Process the send buffer */ + else { + bb->conversation->stream_started = TRUE; + /* Watch for when we can write the buffered messages */ + bb->conversation->tx_handler = purple_input_add(source, PURPLE_INPUT_WRITE, + _send_data_write_cb, pb); + /* We can probably write the data now. */ + _send_data_write_cb(pb, source, PURPLE_INPUT_WRITE); + } + + g_free(stream_start); +} + int bonjour_jabber_send_message(BonjourJabber *data, const gchar *to, const gchar *body) { - xmlnode *message_node = NULL; - gchar *message = NULL; - gint message_length = -1; - xmlnode *message_body_node = NULL; - xmlnode *message_html_node = NULL; - xmlnode *message_html_body_node = NULL; - xmlnode *message_html_body_font_node = NULL; - xmlnode *message_x_node = NULL; - PurpleBuddy *gb = NULL; - BonjourBuddy *bb = NULL; - PurpleConversation *conversation = NULL; - char *message_from_ui = NULL; - char *stripped_message = NULL; - gint ret; + xmlnode *message_node, *node, *node2; + gchar *message; + PurpleBuddy *pb; + BonjourBuddy *bb; + int ret; - gb = purple_find_buddy(data->account, to); - if (gb == NULL) { + pb = purple_find_buddy(data->account, to); + if (pb == NULL) { purple_debug_info("bonjour", "Can't send a message to an offline buddy (%s).\n", to); /* You can not send a message to an offline buddy */ return -10000; } - bb = (BonjourBuddy *)gb->proto_data; + bb = pb->proto_data; /* Check if there is a previously open conversation */ if (bb->conversation == NULL) { - int socket = _connect_to_buddy(gb); - if (socket < 0) - return -10001; + PurpleProxyConnectData *connect_data; - bb->conversation = g_new(BonjourJabberConversation, 1); - bb->conversation->socket = socket; - bb->conversation->stream_started = FALSE; - bb->conversation->buddy_name = g_strdup(gb->name); - bb->conversation->watcher_id = purple_input_add(bb->conversation->socket, - PURPLE_INPUT_READ, _client_socket_handler, gb); - } + /* Make sure that the account always has a proxy of "none". + * This is kind of dirty, but proxy_connect_none() isn't exposed. */ + static PurpleProxyInfo *tmp_none_proxy_info = NULL; + if (!tmp_none_proxy_info) { + tmp_none_proxy_info = purple_proxy_info_new(); + purple_proxy_info_set_type(tmp_none_proxy_info, PURPLE_PROXY_NONE); + } + purple_account_set_proxy_info(data->account, tmp_none_proxy_info); - /* Enclose the message from the UI within a "font" node */ - message_body_node = xmlnode_new("body"); - stripped_message = purple_markup_strip_html(body); - xmlnode_insert_data(message_body_node, stripped_message, strlen(stripped_message)); - g_free(stripped_message); - - message_from_ui = g_strconcat("<font>", body, "</font>", NULL); - message_html_body_font_node = xmlnode_from_str(message_from_ui, strlen(message_from_ui)); - g_free(message_from_ui); + connect_data = + purple_proxy_connect(data->account->gc, data->account, bb->ip, + bb->port_p2pj, _connected_to_buddy, pb); - message_html_body_node = xmlnode_new("body"); - xmlnode_insert_child(message_html_body_node, message_html_body_font_node); + if (connect_data == NULL) { + purple_debug_error("bonjour", "Unable to connect to buddy (%s).\n", to); + return -10001; + } - message_html_node = xmlnode_new("html"); - xmlnode_set_attrib(message_html_node, "xmlns", "http://www.w3.org/1999/xhtml"); - xmlnode_insert_child(message_html_node, message_html_body_node); - - message_x_node = xmlnode_new("x"); - xmlnode_set_attrib(message_x_node, "xmlns", "jabber:x:event"); - xmlnode_insert_child(message_x_node, xmlnode_new("composing")); + bb->conversation = bonjour_jabber_conv_new(); + bb->conversation->connect_data = connect_data; + /* We don't want _send_data() to register the tx_handler; + * that neeeds to wait until we're actually connected. */ + bb->conversation->tx_handler = 0; + } message_node = xmlnode_new("message"); - xmlnode_set_attrib(message_node, "to", ((BonjourBuddy*)(gb->proto_data))->name); - xmlnode_set_attrib(message_node, "from", data->account->username); + xmlnode_set_attrib(message_node, "to", bb->name); + xmlnode_set_attrib(message_node, "from", purple_account_get_username(data->account)); xmlnode_set_attrib(message_node, "type", "chat"); - xmlnode_insert_child(message_node, message_body_node); - xmlnode_insert_child(message_node, message_html_node); - xmlnode_insert_child(message_node, message_x_node); + + /* Enclose the message from the UI within a "font" node */ + node = xmlnode_new_child(message_node, "body"); + message = purple_markup_strip_html(body); + xmlnode_insert_data(node, message, strlen(message)); + g_free(message); + + node = xmlnode_new_child(message_node, "html"); + xmlnode_set_namespace(node, "http://www.w3.org/1999/xhtml"); - message = xmlnode_to_str(message_node, &message_length); + node = xmlnode_new_child(node, "body"); + message = g_strdup_printf("<font>%s</font>", body); + node2 = xmlnode_from_str(message, strlen(message)); + g_free(message); + xmlnode_insert_child(node, node2); + + node = xmlnode_new_child(message_node, "x"); + xmlnode_set_namespace(node, "jabber:x:event"); + xmlnode_insert_child(node, xmlnode_new("composing")); + + message = xmlnode_to_str(message_node, NULL); xmlnode_free(message_node); - /* Check if the stream for the conversation has been started */ - if (bb->conversation->stream_started == FALSE) - { - /* Start the stream */ - if (send(bb->conversation->socket, DOCTYPE, strlen(DOCTYPE), 0) == -1) - { - purple_debug_error("bonjour", "Unable to start a conversation\n"); - purple_debug_warning("bonjour", "send error: %s\n", strerror(errno)); - conversation = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bb->name, data->account); - purple_conversation_write(conversation, NULL, - _("Unable to send the message, the conversation couldn't be started."), - PURPLE_MESSAGE_SYSTEM, time(NULL)); - close(bb->conversation->socket); - purple_input_remove(bb->conversation->watcher_id); + ret = _send_data(pb, message) >= 0; - /* Free all the data related to the conversation */ - g_free(bb->conversation->buddy_name); - g_free(bb->conversation); - bb->conversation = NULL; - g_free(message); - return 0; - } - - bb->conversation->stream_started = TRUE; - } - - /* Send the message */ - ret = (_send_data(bb->conversation->socket, message) == -1); g_free(message); - if (ret == -1) - return -10000; - - return 1; + return ret; } void -bonjour_jabber_close_conversation(BonjourJabber *data, PurpleBuddy *gb) +bonjour_jabber_close_conversation(BonjourJabberConversation *bconv) { - BonjourBuddy *bb = (BonjourBuddy*)gb->proto_data; - - if (bb->conversation != NULL) + if (bconv != NULL) { - /* Send the end of the stream to the other end of the conversation */ - send(bb->conversation->socket, STREAM_END, strlen(STREAM_END), 0); - /* Close the socket and remove the watcher */ - close(bb->conversation->socket); - purple_input_remove(bb->conversation->watcher_id); + if (bconv->socket >= 0) { + /* Send the end of the stream to the other end of the conversation */ + if (bconv->stream_started) + send(bconv->socket, STREAM_END, strlen(STREAM_END), 0); + /* TODO: We're really supposed to wait for "</stream:stream>" before closing the socket */ + close(bconv->socket); + } + if (bconv->rx_handler != -1) + purple_input_remove(bconv->rx_handler); + if (bconv->tx_handler > 0) + purple_input_remove(bconv->tx_handler); /* Free all the data related to the conversation */ - g_free(bb->conversation->buddy_name); - g_free(bb->conversation); - bb->conversation = NULL; + purple_circ_buffer_destroy(bconv->tx_buf); + if (bconv->connect_data != NULL) + purple_proxy_connect_cancel(bconv->connect_data); + if (bconv->stream_data != NULL) { + struct _stream_start_data *ss = bconv->stream_data; + g_free(ss->msg); + g_free(ss); + } + g_free(bconv); } } @@ -657,12 +839,15 @@ /* Close all the conversation sockets and remove all the watchers after sending end streams */ if (data->account->gc != NULL) { - GSList *buddies; - GSList *l; + GSList *buddies, *l; - buddies = purple_find_buddies(data->account, data->account->username); - for (l = buddies; l; l = l->next) - bonjour_jabber_close_conversation(data, l->data); + buddies = purple_find_buddies(data->account, purple_account_get_username(data->account)); + for (l = buddies; l; l = l->next) { + BonjourBuddy *bb = ((PurpleBuddy*) l->data)->proto_data; + bonjour_jabber_close_conversation(bb->conversation); + bb->conversation = NULL; + } + g_slist_free(buddies); } }
--- a/libpurple/protocols/bonjour/jabber.h Fri Jun 08 03:19:13 2007 +0000 +++ b/libpurple/protocols/bonjour/jabber.h Sat Jun 09 04:12:47 2007 +0000 @@ -27,9 +27,7 @@ #define _BONJOUR_JABBER_H_ #include "account.h" - -#define STREAM_END "</stream:stream>" -#define DOCTYPE "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<stream:stream xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\">" +#include "circbuffer.h" typedef struct _BonjourJabber { @@ -42,10 +40,12 @@ typedef struct _BonjourJabberConversation { gint socket; - gint watcher_id; - gchar* buddy_name; + guint rx_handler; + guint tx_handler; + PurpleCircBuffer *tx_buf; gboolean stream_started; - gint message_id; + PurpleProxyConnectData *connect_data; + gpointer stream_data; } BonjourJabberConversation; /** @@ -58,7 +58,7 @@ int bonjour_jabber_send_message(BonjourJabber *data, const gchar *to, const gchar *body); -void bonjour_jabber_close_conversation(BonjourJabber *data, PurpleBuddy *gb); +void bonjour_jabber_close_conversation(BonjourJabberConversation *bconv); void bonjour_jabber_stop(BonjourJabber *data);
--- a/libpurple/protocols/bonjour/mdns_common.c Fri Jun 08 03:19:13 2007 +0000 +++ b/libpurple/protocols/bonjour/mdns_common.c Sat Jun 09 04:12:47 2007 +0000 @@ -162,7 +162,7 @@ #ifdef USE_BONJOUR_APPLE /* hack: for win32, we need to stop listening to the advertisement pipe too */ - purple_input_remove(data->advertisement_fd); + purple_input_remove(data->advertisement_handler); DNSServiceRefDeallocate(data->advertisement); DNSServiceRefDeallocate(data->browser);
--- a/libpurple/protocols/bonjour/mdns_types.h Fri Jun 08 03:19:13 2007 +0000 +++ b/libpurple/protocols/bonjour/mdns_types.h Sat Jun 09 04:12:47 2007 +0000 @@ -38,7 +38,7 @@ DNSServiceRef advertisement; DNSServiceRef browser; - int advertisement_fd; /* hack... windows bonjour is broken, so we have to have this */ + int advertisement_handler; /* hack... windows bonjour is broken, so we have to have this */ #else /* USE_BONJOUR_HOWL */ sw_discovery session; sw_discovery_oid session_id;
--- a/libpurple/protocols/bonjour/mdns_win32.c Fri Jun 08 03:19:13 2007 +0000 +++ b/libpurple/protocols/bonjour/mdns_win32.c Sat Jun 09 04:12:47 2007 +0000 @@ -280,7 +280,7 @@ { /* hack: Bonjour on windows is broken. We don't care about the callback but we have to listen anyway */ gint advertisement_fd = DNSServiceRefSockFD(data->advertisement); - data->advertisement_fd = purple_input_add(advertisement_fd, PURPLE_INPUT_READ, _mdns_handle_event, data->advertisement); + data->advertisement_handler = purple_input_add(advertisement_fd, PURPLE_INPUT_READ, _mdns_handle_event, data->advertisement); } }
--- a/libpurple/protocols/jabber/jabber.c Fri Jun 08 03:19:13 2007 +0000 +++ b/libpurple/protocols/jabber/jabber.c Sat Jun 09 04:12:47 2007 +0000 @@ -1075,8 +1075,10 @@ /* lets make sure our buddy icon is up to date * before we go letting people know we're here */ img = purple_buddy_icons_find_account_icon(js->gc->account); - jabber_set_buddy_icon(js->gc, img); - purple_imgstore_unref(img); + if(NULL != img) { + jabber_set_buddy_icon(js->gc, img); + purple_imgstore_unref(img); + } /* now we can alert the core that we're ready to send status */ purple_connection_set_state(js->gc, PURPLE_CONNECTED);
--- a/libpurple/protocols/simple/simple.c Fri Jun 08 03:19:13 2007 +0000 +++ b/libpurple/protocols/simple/simple.c Sat Jun 09 04:12:47 2007 +0000 @@ -1243,7 +1243,7 @@ foundxpidf = TRUE; if(tmp2) { *tmp2 = ','; - tmp = tmp2; + tmp = tmp2 + 1; while(*tmp == ' ') tmp++; } else tmp = 0;
--- a/libpurple/win32/libc_interface.c Fri Jun 08 03:19:13 2007 +0000 +++ b/libpurple/win32/libc_interface.c Sat Jun 09 04:12:47 2007 +0000 @@ -1,6 +1,6 @@ /* * purple - * + * * Copyright (C) 2002-2003, Herman Bloggs <hermanator12002@yahoo.com> * * This program is free software; you can redistribute it and/or modify @@ -74,7 +74,7 @@ int ret; ret = connect( socket, addr, length ); - + if( ret == SOCKET_ERROR ) { errno = WSAGetLastError(); if( errno == WSAEWOULDBLOCK ) @@ -129,6 +129,8 @@ if ((ret = sendto(socket, buf, len, flags, to, tolen) ) == SOCKET_ERROR) { errno = WSAGetLastError(); + if(errno == WSAEWOULDBLOCK || errno == WSAEINPROGRESS) + errno = EAGAIN; return -1; } return ret; @@ -302,7 +304,7 @@ if(wpurple_is_socket(fd)) { if((ret = recv(fd, buf, size, 0)) == SOCKET_ERROR) { errno = WSAGetLastError(); - if(errno == WSAEWOULDBLOCK) + if(errno == WSAEWOULDBLOCK || errno == WSAEINPROGRESS) errno = EAGAIN; return -1; } @@ -330,7 +332,7 @@ if (ret == SOCKET_ERROR) { errno = WSAGetLastError(); - if(errno == WSAEWOULDBLOCK) + if(errno == WSAEWOULDBLOCK || errno == WSAEINPROGRESS) errno = EAGAIN; return -1; } @@ -350,7 +352,7 @@ if((ret = recv(fd, buf, len, flags)) == SOCKET_ERROR) { errno = WSAGetLastError(); - if(errno == WSAEWOULDBLOCK) + if(errno == WSAEWOULDBLOCK || errno == WSAEINPROGRESS) errno = EAGAIN; return -1; } else { @@ -392,7 +394,7 @@ z->tz_minuteswest = _timezone/60; z->tz_dsttime = _daylight; } - + if (p != 0) { _ftime(&timebuffer); p->tv_sec = timebuffer.time; /* seconds since 1-1-1970 */ @@ -1044,7 +1046,7 @@ * Returns: zero if the pathname refers to an existing file system * object that has all the tested permissions, or -1 otherwise or on * error. - * + * * Since: 2.8 */ int @@ -1056,7 +1058,7 @@ wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL); int retval; int save_errno; - + if (wfilename == NULL) { errno = EINVAL; @@ -1072,7 +1074,7 @@ return retval; } else - { + { gchar *cp_filename = g_locale_from_utf8 (filename, -1, NULL, NULL, NULL); int retval; int save_errno;
--- a/pidgin/gtkaccount.c Fri Jun 08 03:19:13 2007 +0000 +++ b/pidgin/gtkaccount.c Sat Jun 09 04:12:47 2007 +0000 @@ -1024,7 +1024,7 @@ if (dialog->proxy_frame != NULL) gtk_widget_destroy(dialog->proxy_frame); - frame = pidgin_make_frame(parent, _("Pro_xy Options")); + frame = pidgin_make_frame(parent, _("Proxy Options")); dialog->proxy_frame = gtk_widget_get_parent(gtk_widget_get_parent(frame)); gtk_box_reorder_child(GTK_BOX(parent), dialog->proxy_frame, 1);
--- a/pidgin/gtkpounce.c Fri Jun 08 03:19:13 2007 +0000 +++ b/pidgin/gtkpounce.c Sat Jun 09 04:12:47 2007 +0000 @@ -783,7 +783,7 @@ gtk_widget_show(table); dialog->on_away = - gtk_check_button_new_with_mnemonic(_("P_ounce only when my status is not available")); + gtk_check_button_new_with_mnemonic(_("P_ounce only when my status is not Available")); gtk_table_attach(GTK_TABLE(table), dialog->on_away, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);