# HG changeset patch # User Yoshiki Yazawa # Date 1197695868 0 # Node ID 2be2eec7d273a9e9911b1837639be94b348b398f # Parent e13759a83714ce57707fea2e85ac8b2f830d3ff0# Parent cc0809ec0c85a0876afed7de40184e3377792b14 propagate from branch 'im.pidgin.pidgin' (head e1e3e43c119da08c2f86638d37867881f3742d4c) to branch 'im.pidgin.pidgin.yaz' (head b4b1a0c7e3730e0fff77d9d340c1d2ad577d2a8f) diff -r e13759a83714 -r 2be2eec7d273 doc/pidgin.1.in --- a/doc/pidgin.1.in Sat Dec 15 05:15:31 2007 +0000 +++ b/doc/pidgin.1.in Sat Dec 15 05:17:48 2007 +0000 @@ -88,8 +88,8 @@ .TP .B Add Buddy Pounce A Buddy Pounce is a configurable automated action to be performed when the -buddy's state changes. This will open the \fBBuddy Pounce\fR dialog to be -discussed later. +buddy's state changes. This will open the \fBBuddy Pounce\fR dialog, which +will be discussed later. .TP .B View Log Pidgin is capable of automatically logging messages. These logs are @@ -118,7 +118,7 @@ .SH ACCOUNT EDITOR The account editor consists of a list of accounts and information about -them. It can be accessed by selecting \fBManage\fR from the Tools menu. +them. It can be accessed by selecting \fBManage\fR from the Accounts menu. Clicking \fIDelete\fR will delete the currently selected account. Clicking \fIAdd\fR or \fIModify\fR will invoke a \fBModify Account\fR window. Here, the user can add or alter account information. When creating diff -r e13759a83714 -r 2be2eec7d273 libpurple/protocols/bonjour/bonjour.c --- a/libpurple/protocols/bonjour/bonjour.c Sat Dec 15 05:15:31 2007 +0000 +++ b/libpurple/protocols/bonjour/bonjour.c Sat Dec 15 05:17:48 2007 +0000 @@ -109,7 +109,7 @@ gc->proto_data = bd = g_new0(BonjourData, 1); /* Start waiting for jabber connections (iChat style) */ - bd->jabber_data = g_new(BonjourJabber, 1); + bd->jabber_data = g_new0(BonjourJabber, 1); bd->jabber_data->port = BONJOUR_DEFAULT_PORT_INT; bd->jabber_data->account = account; diff -r e13759a83714 -r 2be2eec7d273 libpurple/protocols/bonjour/bonjour.h --- a/libpurple/protocols/bonjour/bonjour.h Sat Dec 15 05:15:31 2007 +0000 +++ b/libpurple/protocols/bonjour/bonjour.h Sat Dec 15 05:17:48 2007 +0000 @@ -44,7 +44,7 @@ { BonjourDnsSd *dns_sd_data; BonjourJabber *jabber_data; - GList *xfer_lists; + GSList *xfer_lists; } BonjourData; #endif /* _BONJOUR_H_ */ diff -r e13759a83714 -r 2be2eec7d273 libpurple/protocols/bonjour/bonjour_ft.c --- a/libpurple/protocols/bonjour/bonjour_ft.c Sat Dec 15 05:15:31 2007 +0000 +++ b/libpurple/protocols/bonjour/bonjour_ft.c Sat Dec 15 05:17:48 2007 +0000 @@ -149,7 +149,7 @@ static PurpleXfer* bonjour_si_xfer_find(BonjourData *bd, const char *sid, const char *from) { - GList *xfers = NULL; + GSList *xfers = NULL; PurpleXfer *xfer = NULL; XepXfer *xf = NULL; @@ -309,7 +309,7 @@ if(xf != NULL) { bd = (BonjourData*)xf->data; if(bd != NULL) { - bd->xfer_lists = g_list_remove(bd->xfer_lists, xfer); + bd->xfer_lists = g_slist_remove(bd->xfer_lists, xfer); purple_debug_info("bonjour", "B free xfer from lists(%p).\n", bd->xfer_lists); } if (xf->proxy_connection != NULL) @@ -359,7 +359,7 @@ purple_xfer_set_cancel_send_fnc(xfer, bonjour_xfer_cancel_send); purple_xfer_set_end_fnc(xfer, bonjour_xfer_end); - bd->xfer_lists = g_list_append(bd->xfer_lists, xfer); + bd->xfer_lists = g_slist_append(bd->xfer_lists, xfer); return xfer; } @@ -605,7 +605,7 @@ purple_xfer_set_cancel_recv_fnc(xfer, bonjour_xfer_cancel_recv); purple_xfer_set_end_fnc(xfer, bonjour_xfer_end); - bd->xfer_lists = g_list_append(bd->xfer_lists, xfer); + bd->xfer_lists = g_slist_append(bd->xfer_lists, xfer); purple_xfer_request(xfer); } diff -r e13759a83714 -r 2be2eec7d273 libpurple/protocols/bonjour/jabber.c --- a/libpurple/protocols/bonjour/jabber.c Sat Dec 15 05:15:31 2007 +0000 +++ b/libpurple/protocols/bonjour/jabber.c Sat Dec 15 05:17:48 2007 +0000 @@ -78,7 +78,7 @@ xep_iq_parse(xmlnode *packet, PurpleConnection *connection, PurpleBuddy *pb); static BonjourJabberConversation * -bonjour_jabber_conv_new(PurpleBuddy *pb) { +bonjour_jabber_conv_new(PurpleBuddy *pb, PurpleAccount *account, const char *ip) { BonjourJabberConversation *bconv = g_new0(BonjourJabberConversation, 1); bconv->socket = -1; @@ -86,13 +86,14 @@ bconv->tx_handler = 0; bconv->rx_handler = 0; bconv->pb = pb; + bconv->account = account; + bconv->ip = g_strdup(ip); bonjour_parser_setup(bconv); return bconv; } - static const char * _font_size_ichat_to_purple(int size) { @@ -204,39 +205,36 @@ g_free(body); } -struct _check_buddy_by_address_t { +struct _match_buddies_by_address_t { const char *address; - PurpleBuddy **pb; - BonjourJabber *bj; + GSList *matched_buddies; + BonjourJabber *jdata; }; static void -_check_buddy_by_address(gpointer key, gpointer value, gpointer data) +_match_buddies_by_address(gpointer key, gpointer value, gpointer data) { PurpleBuddy *pb = value; - BonjourBuddy *bb; - struct _check_buddy_by_address_t *cbba = data; + struct _match_buddies_by_address_t *mbba = data; /* * If the current PurpleBuddy's data is not null and the PurpleBuddy's account * is the same as the account requesting the check then continue to determine * whether one of the buddies IPs matches the target IP. */ - if (cbba->bj->account == pb->account) + if (mbba->jdata->account == pb->account && pb->proto_data != NULL) { - bb = pb->proto_data; - if (bb != NULL) { - const char *ip; - GSList *tmp = bb->ips; + const char *ip; + BonjourBuddy *bb = pb->proto_data; + GSList *tmp = bb->ips; - while(tmp) { - ip = tmp->data; - if (ip != NULL && g_ascii_strcasecmp(ip, cbba->address) == 0) { - *(cbba->pb) = pb; - break; - } - tmp = tmp->next; + while(tmp) { + ip = tmp->data; + if (ip != NULL && g_ascii_strcasecmp(ip, mbba->address) == 0) { + mbba->matched_buddies = g_slist_prepend(mbba->matched_buddies, pb); + break; } + tmp = tmp->next; } } } @@ -249,8 +247,6 @@ 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) { @@ -338,6 +334,7 @@ void bonjour_jabber_process_packet(PurpleBuddy *pb, xmlnode *packet) { g_return_if_fail(packet != NULL); + g_return_if_fail(pb != NULL); if (!strcmp(packet->name, "message")) _jabber_parse_and_write_message_to_ui(packet, pb); @@ -351,31 +348,31 @@ static void _client_socket_handler(gpointer data, gint socket, PurpleInputCondition condition) { - PurpleBuddy *pb = data; + BonjourJabberConversation *bconv = data; gint len, message_length; static char message[4096]; - /*TODO: use a static buffer */ - /* Read the data from the socket */ if ((len = recv(socket, message, sizeof(message) - 1, 0)) == -1) { /* There have been an error reading from the socket */ if (errno != EAGAIN) { - BonjourBuddy *bb = pb->proto_data; const char *err = g_strerror(errno); purple_debug_warning("bonjour", "receive error: %s\n", err ? err : "(null)"); - bonjour_jabber_close_conversation(bb->conversation); - bb->conversation = NULL; + bonjour_jabber_close_conversation(bconv); + if (bconv->pb != NULL) { + BonjourBuddy *bb = bconv->pb->proto_data; + 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 (len == 0) { /* The other end has closed the socket */ - purple_debug_warning("bonjour", "Connection closed (without stream end) by %s.\n", pb->name ? pb->name : "(null)"); - bonjour_jabber_stream_ended(pb); + purple_debug_warning("bonjour", "Connection closed (without stream end) by %s.\n", (bconv->pb && bconv->pb->name) ? bconv->pb->name : "(unknown)"); + bonjour_jabber_stream_ended(bconv); return; } else { message_length = len; @@ -389,30 +386,34 @@ purple_debug_info("bonjour", "Receive: -%s- %d bytes\n", message, len); - bonjour_parser_process(pb, message, message_length); + bonjour_parser_process(bconv, message, message_length); } -void bonjour_jabber_stream_ended(PurpleBuddy *pb) { - BonjourBuddy *bb = pb->proto_data; +void bonjour_jabber_stream_ended(BonjourJabberConversation *bconv) { - purple_debug_info("bonjour", "Recieved conversation close notification from %s.\n", pb->name); - - g_return_if_fail(bb != NULL); + purple_debug_info("bonjour", "Recieved conversation close notification from %s.\n", bconv->pb ? bconv->pb->name : "(unknown)"); /* Inform the user that the conversation has been closed */ - if (bb->conversation != NULL) { + if (bconv != NULL) { + BonjourBuddy *bb = NULL; + + if(bconv->pb != NULL) + bb = bconv->pb->proto_data; #if 0 - PurpleConversation *conv; - conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, pb->name, pb->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); + if(bconv->pb != NULL) { + PurpleConversation *conv; + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bconv->pb->name, bconv->pb->account); + if (conv != NULL) { + char *tmp = g_strdup_printf(_("%s has closed the conversation."), bconv->pb->name); + purple_conversation_write(conv, NULL, tmp, PURPLE_MESSAGE_SYSTEM, time(NULL)); + g_free(tmp); + } } #endif /* Close the socket, clear the watcher and free memory */ - bonjour_jabber_close_conversation(bb->conversation); - bb->conversation = NULL; + bonjour_jabber_close_conversation(bconv); + if(bb) + bb->conversation = NULL; } } @@ -425,9 +426,7 @@ static void _start_stream(gpointer data, gint source, PurpleInputCondition condition) { - PurpleBuddy *pb = data; - BonjourBuddy *bb = pb->proto_data; - BonjourJabberConversation *bconv = bb->conversation; + BonjourJabberConversation *bconv = data; struct _stream_start_data *ss = bconv->stream_data; int len, ret; @@ -441,23 +440,26 @@ else if (ret <= 0) { const char *err = g_strerror(errno); PurpleConversation *conv; - const char *ip = NULL; + const char *bname = bconv->buddy_name; + BonjourBuddy *bb = NULL; - /* For better or worse, use the first IP*/ - if (bb->ips) - ip = bb->ips->data; + if(bconv->pb) { + bb = bconv->pb->proto_data; + bname = purple_buddy_get_name(bconv->pb); + } - purple_debug_error("bonjour", "Error starting stream with buddy %s at %s:%d error: %s\n", - purple_buddy_get_name(pb), ip ? ip : "(null)", bb->port_p2pj, err ? err : "(null)"); + purple_debug_error("bonjour", "Error starting stream with buddy %s at %s error: %s\n", + bname ? bname : "(unknown)", bconv->ip, err ? err : "(null)"); - conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bb->name, pb->account); + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bname, bconv->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(bconv); - bb->conversation = NULL; + if(bb != NULL) + bb->conversation = NULL; return; } @@ -479,20 +481,27 @@ bconv->tx_handler = 0; bconv->sent_stream_start = FULLY_SENT; - bonjour_jabber_stream_started(pb); + bonjour_jabber_stream_started(bconv); } -static gboolean bonjour_jabber_send_stream_init(PurpleBuddy *pb, int client_socket) +static gboolean bonjour_jabber_send_stream_init(BonjourJabberConversation *bconv, int client_socket) { int ret, len; char *stream_start; - BonjourBuddy *bb = pb->proto_data; + const char *bname = bconv->buddy_name; + + if (bconv->pb != NULL) + bname = purple_buddy_get_name(bconv->pb); - stream_start = g_strdup_printf(DOCTYPE, purple_account_get_username(pb->account), - purple_buddy_get_name(pb)); + /* If we have no idea who "to" is, use an empty string. + * If we don't know now, it is because the other side isn't playing nice, so they can't complain. */ + if (bname == NULL) + bname = ""; + + stream_start = g_strdup_printf(DOCTYPE, purple_account_get_username(bconv->account), bname); len = strlen(stream_start); - bb->conversation->sent_stream_start = PARTIALLY_SENT; + bconv->sent_stream_start = PARTIALLY_SENT; /* Start the stream */ ret = send(client_socket, stream_start, len, 0); @@ -501,14 +510,18 @@ ret = 0; else if (ret <= 0) { const char *err = g_strerror(errno); - const char *ip = NULL; + + purple_debug_error("bonjour", "Error starting stream with buddy %s at %s error: %s\n", + (*bname) ? bname : "(unknown)", bconv->ip, err ? err : "(null)"); - /* For better or worse, use the first IP*/ - if (bb->ips) - ip = bb->ips->data; - - purple_debug_error("bonjour", "Error starting stream with buddy %s at %s:%d error: %s\n", - purple_buddy_get_name(pb), ip ? ip : "(null)", bb->port_p2pj, err ? err : "(null)"); + if (bconv->pb) { + PurpleConversation *conv; + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bname, bconv->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(client_socket); g_free(stream_start); @@ -520,63 +533,61 @@ if (ret < len) { struct _stream_start_data *ss = g_new(struct _stream_start_data, 1); ss->msg = g_strdup(stream_start + ret); - bb->conversation->stream_data = ss; + bconv->stream_data = ss; /* Finish sending the stream start */ - bb->conversation->tx_handler = purple_input_add(client_socket, - PURPLE_INPUT_WRITE, _start_stream, pb); + bconv->tx_handler = purple_input_add(client_socket, + PURPLE_INPUT_WRITE, _start_stream, bconv); } else - bb->conversation->sent_stream_start = FULLY_SENT; + bconv->sent_stream_start = FULLY_SENT; g_free(stream_start); return TRUE; } -static gboolean -_async_bonjour_jabber_close_conversation(gpointer data) { - BonjourJabberConversation *bconv = data; - bonjour_jabber_close_conversation(bconv); - return FALSE; -} +/* This gets called when we've successfully sent our + * AND when we've recieved a */ +void bonjour_jabber_stream_started(BonjourJabberConversation *bconv) { -void bonjour_jabber_stream_started(PurpleBuddy *pb) { - BonjourBuddy *bb = pb->proto_data; - BonjourJabberConversation *bconv = bb->conversation; - - if (bconv->sent_stream_start == NOT_SENT && !bonjour_jabber_send_stream_init(pb, bconv->socket)) { + if (bconv->sent_stream_start == NOT_SENT && !bonjour_jabber_send_stream_init(bconv, bconv->socket)) { const char *err = g_strerror(errno); - PurpleConversation *conv; - const char *ip = NULL; + const char *bname = bconv->buddy_name; - /* For better or worse, use the first IP*/ - if (bb->ips) - ip = bb->ips->data; + if (bconv->pb) + bname = purple_buddy_get_name(bconv->pb); + + purple_debug_error("bonjour", "Error starting stream with buddy %s at %s error: %s\n", + bname ? bname : "(unknown)", bconv->ip, err ? err : "(null)"); - purple_debug_error("bonjour", "Error starting stream with buddy %s at %s:%d error: %s\n", - purple_buddy_get_name(pb), ip ? ip : "(null)", bb->port_p2pj, err ? err : "(null)"); + if (bconv->pb) { + PurpleConversation *conv; + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bname, bconv->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)); + } - 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)); + /* We don't want to recieve anything else */ + close(bconv->socket); + bconv->socket = -1; - close(bconv->socket); /* This must be asynchronous because it destroys the parser and we * may be in the middle of parsing. */ - purple_timeout_add(0, _async_bonjour_jabber_close_conversation, bb->conversation); - bb->conversation = NULL; + async_bonjour_jabber_close_conversation(bconv); return; } - /* If the stream has been completely started, we can start doing stuff */ - if (bconv->sent_stream_start == FULLY_SENT && bconv->recv_stream_start && purple_circ_buffer_get_max_read(bconv->tx_buf) > 0) { + /* If the stream has been completely started and we know who we're talking to, we can start doing stuff. */ + /* I don't think the circ_buffer can actually contain anything without a buddy being associated, but lets be explicit. */ + if (bconv->sent_stream_start == FULLY_SENT && bconv->recv_stream_start + && bconv->pb && purple_circ_buffer_get_max_read(bconv->tx_buf) > 0) { /* Watch for when we can write the buffered messages */ bconv->tx_handler = purple_input_add(bconv->socket, PURPLE_INPUT_WRITE, - _send_data_write_cb, pb); + _send_data_write_cb, bconv->pb); /* We can probably write the data right now. */ - _send_data_write_cb(pb, bconv->socket, PURPLE_INPUT_WRITE); + _send_data_write_cb(bconv->pb, bconv->socket, PURPLE_INPUT_WRITE); } } @@ -584,15 +595,14 @@ static void _server_socket_handler(gpointer data, int server_socket, PurpleInputCondition condition) { - PurpleBuddy *pb = NULL; + BonjourJabber *jdata = data; struct sockaddr_in their_addr; /* connector's address information */ socklen_t sin_size = sizeof(struct sockaddr); int client_socket; int flags; - BonjourBuddy *bb; char *address_text = NULL; - PurpleBuddyList *bl = purple_get_blist(); - struct _check_buddy_by_address_t *cbba; + struct _match_buddies_by_address_t *mbba; + BonjourJabberConversation *bconv; /* Check that it is a read condition */ if (condition != PURPLE_INPUT_READ) @@ -607,39 +617,35 @@ /* Look for the buddy that has opened the conversation and fill information */ address_text = inet_ntoa(their_addr.sin_addr); purple_debug_info("bonjour", "Received incoming connection from %s.\n", address_text); - cbba = g_new0(struct _check_buddy_by_address_t, 1); - cbba->address = address_text; - cbba->pb = &pb; - cbba->bj = data; - g_hash_table_foreach(bl->buddies, _check_buddy_by_address, cbba); - g_free(cbba); - if (pb == NULL) - { + mbba = g_new0(struct _match_buddies_by_address_t, 1); + mbba->address = address_text; + mbba->jdata = jdata; + g_hash_table_foreach(purple_get_blist()->buddies, _match_buddies_by_address, mbba); + + if (mbba->matched_buddies == NULL) { purple_debug_info("bonjour", "We don't like invisible buddies, this is not a superheros comic\n"); + g_slist_free(mbba->matched_buddies); + g_free(mbba); close(client_socket); return; } - bb = pb->proto_data; - /* Check if the conversation has been previously started */ - /* This really shouldn't ever happen unless something weird is going on */ - if (bb->conversation == NULL) - { - bb->conversation = bonjour_jabber_conv_new(pb); + g_slist_free(mbba->matched_buddies); + g_free(mbba); - /* We wait for the stream start before doing anything else */ - bb->conversation->socket = client_socket; - bb->conversation->rx_handler = purple_input_add(client_socket, - PURPLE_INPUT_READ, _client_socket_handler, pb); + /* We've established that this *could* be from one of our buddies. + * Wait for the stream open to see if that matches too before assigning it. + */ + bconv = bonjour_jabber_conv_new(NULL, jdata->account, address_text); - } else { - purple_debug_warning("bonjour", "Ignoring incoming connection because an existing connection exists.\n"); - close(client_socket); - } + /* We wait for the stream start before doing anything else */ + bconv->socket = client_socket; + bconv->rx_handler = purple_input_add(client_socket, PURPLE_INPUT_READ, _client_socket_handler, bconv); + } gint -bonjour_jabber_start(BonjourJabber *data) +bonjour_jabber_start(BonjourJabber *jdata) { struct sockaddr_in my_addr; int yes = 1; @@ -647,20 +653,20 @@ gboolean bind_successful; /* Open a listening socket for incoming conversations */ - if ((data->socket = socket(PF_INET, SOCK_STREAM, 0)) < 0) + if ((jdata->socket = socket(PF_INET, SOCK_STREAM, 0)) < 0) { purple_debug_error("bonjour", "Cannot open socket: %s\n", g_strerror(errno)); - purple_connection_error_reason (data->account->gc, + purple_connection_error_reason (jdata->account->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Cannot open socket")); return -1; } /* Make the socket reusable */ - if (setsockopt(data->socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) != 0) + if (setsockopt(jdata->socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) != 0) { purple_debug_error("bonjour", "Error setting socket options: %s\n", g_strerror(errno)); - purple_connection_error_reason (data->account->gc, + purple_connection_error_reason (jdata->account->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Error setting socket options")); return -1; @@ -673,30 +679,30 @@ bind_successful = FALSE; for (i = 0; i < 10; i++) { - my_addr.sin_port = htons(data->port); - if (bind(data->socket, (struct sockaddr*)&my_addr, sizeof(struct sockaddr)) == 0) + my_addr.sin_port = htons(jdata->port); + if (bind(jdata->socket, (struct sockaddr*)&my_addr, sizeof(struct sockaddr)) == 0) { bind_successful = TRUE; break; } - data->port++; + jdata->port++; } /* On no! We tried 10 ports and could not bind to ANY of them */ if (!bind_successful) { purple_debug_error("bonjour", "Cannot bind socket: %s\n", g_strerror(errno)); - purple_connection_error_reason (data->account->gc, + purple_connection_error_reason (jdata->account->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Could not bind socket to port")); return -1; } /* Attempt to listen on the bound socket */ - if (listen(data->socket, 10) != 0) + if (listen(jdata->socket, 10) != 0) { purple_debug_error("bonjour", "Cannot listen on socket: %s\n", g_strerror(errno)); - purple_connection_error_reason (data->account->gc, + purple_connection_error_reason (jdata->account->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Could not listen on socket")); return -1; @@ -704,18 +710,18 @@ #if 0 /* TODO: Why isn't this being used? */ - data->socket = purple_network_listen(data->port, SOCK_STREAM); + data->socket = purple_network_listen(jdata->port, SOCK_STREAM); - if (data->socket == -1) + if (jdata->socket == -1) { purple_debug_error("bonjour", "No se ha podido crear el socket\n"); } #endif /* Open a watcher in the socket we have just opened */ - data->watcher_id = purple_input_add(data->socket, PURPLE_INPUT_READ, _server_socket_handler, data); + jdata->watcher_id = purple_input_add(jdata->socket, PURPLE_INPUT_READ, _server_socket_handler, jdata); - return data->port; + return jdata->port; } static void @@ -728,14 +734,9 @@ if (source < 0) { PurpleConversation *conv; - const char *ip = NULL; - - /* For better or worse, use the first IP*/ - if (bb->ips) - ip = bb->ips->data; purple_debug_error("bonjour", "Error connecting to buddy %s at %s:%d error: %s\n", - purple_buddy_get_name(pb), ip ? ip : "(null)", bb->port_p2pj, error ? error : "(null)"); + purple_buddy_get_name(pb), bb->conversation->ip, bb->port_p2pj, error ? error : "(null)"); conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bb->name, pb->account); if (conv != NULL) @@ -748,17 +749,12 @@ return; } - if (!bonjour_jabber_send_stream_init(pb, source)) { + if (!bonjour_jabber_send_stream_init(bb->conversation, source)) { const char *err = g_strerror(errno); PurpleConversation *conv; - const char *ip = NULL; - - /* For better or worse, use the first IP*/ - if (bb->ips) - ip = bb->ips->data; purple_debug_error("bonjour", "Error starting stream with buddy %s at %s:%d error: %s\n", - purple_buddy_get_name(pb), ip ? ip : "(null)", bb->port_p2pj, err ? err : "(null)"); + purple_buddy_get_name(pb), bb->conversation->ip, bb->port_p2pj, err ? err : "(null)"); conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bb->name, pb->account); if (conv != NULL) @@ -775,19 +771,116 @@ /* Start listening for the stream acknowledgement */ bb->conversation->socket = source; bb->conversation->rx_handler = purple_input_add(source, - PURPLE_INPUT_READ, _client_socket_handler, pb); + PURPLE_INPUT_READ, _client_socket_handler, bb->conversation); +} + +void +bonjour_jabber_conv_match_by_name(BonjourJabberConversation *bconv) { + PurpleBuddy *pb; + + g_return_if_fail(bconv->ip != NULL); + g_return_if_fail(bconv->pb == NULL); + + pb = purple_find_buddy(bconv->account, bconv->buddy_name); + if (pb && pb->proto_data) { + BonjourBuddy *bb = pb->proto_data; + const char *ip; + GSList *tmp = bb->ips; + + purple_debug_info("bonjour", "Found buddy %s for incoming conversation \"from\" attrib.\n", + purple_buddy_get_name(pb)); + + /* Check that one of the buddy's IPs matches */ + while(tmp) { + ip = tmp->data; + if (ip != NULL && g_ascii_strcasecmp(ip, bconv->ip) == 0) { + BonjourJabber *jdata = ((BonjourData*) bconv->account->gc->proto_data)->jabber_data; + + purple_debug_info("bonjour", "Matched buddy %s to incoming conversation \"from\" attrib and IP (%s)\n", + purple_buddy_get_name(pb), bconv->ip); + + /* Attach conv. to buddy and remove from pending list */ + jdata->pending_conversations = g_slist_remove(jdata->pending_conversations, bconv); + + /* Check if the buddy already has a conversation and, if so, replace it */ + if(bb->conversation != NULL && bb->conversation != bconv) + bonjour_jabber_close_conversation(bb->conversation); + + bconv->pb = pb; + bb->conversation = bconv; + + break; + } + tmp = tmp->next; + } + } + + /* We've failed to match a buddy - give up */ + if (bconv->pb == NULL) { + /* This must be asynchronous because it destroys the parser and we + * may be in the middle of parsing. + */ + async_bonjour_jabber_close_conversation(bconv); + } +} + + +void +bonjour_jabber_conv_match_by_ip(BonjourJabberConversation *bconv) { + BonjourJabber *jdata = ((BonjourData*) bconv->account->gc->proto_data)->jabber_data; + struct _match_buddies_by_address_t *mbba; + + mbba = g_new0(struct _match_buddies_by_address_t, 1); + mbba->address = bconv->ip; + mbba->jdata = jdata; + g_hash_table_foreach(purple_get_blist()->buddies, _match_buddies_by_address, mbba); + + /* If there is exactly one match, use it */ + if(mbba->matched_buddies != NULL) { + if(mbba->matched_buddies->next != NULL) + purple_debug_error("bonjour", "More than one buddy matched for ip %s.\n", bconv->ip); + else { + PurpleBuddy *pb = mbba->matched_buddies->data; + BonjourBuddy *bb = pb->proto_data; + + purple_debug_info("bonjour", "Matched buddy %s to incoming conversation using IP (%s)\n", + purple_buddy_get_name(pb), bconv->ip); + + /* Attach conv. to buddy and remove from pending list */ + jdata->pending_conversations = g_slist_remove(jdata->pending_conversations, bconv); + + /* Check if the buddy already has a conversation and, if so, replace it */ + if (bb->conversation != NULL && bb->conversation != bconv) + bonjour_jabber_close_conversation(bb->conversation); + + bconv->pb = pb; + bb->conversation = bconv; + } + } else + purple_debug_error("bonjour", "No buddies matched for ip %s.\n", bconv->ip); + + /* We've failed to match a buddy - give up */ + if (bconv->pb == NULL) { + /* This must be asynchronous because it destroys the parser and we + * may be in the middle of parsing. + */ + async_bonjour_jabber_close_conversation(bconv); + } + + g_slist_free(mbba->matched_buddies); + g_free(mbba); } static PurpleBuddy * -_find_or_start_conversation(BonjourJabber *data, const gchar *to) +_find_or_start_conversation(BonjourJabber *jdata, const gchar *to) { PurpleBuddy *pb = NULL; BonjourBuddy *bb = NULL; - g_return_val_if_fail(data != NULL, NULL); + g_return_val_if_fail(jdata != NULL, NULL); g_return_val_if_fail(to != NULL, NULL); - pb = purple_find_buddy(data->account, to); + pb = purple_find_buddy(jdata->account, to); if (pb == NULL || pb->proto_data == NULL) /* You can not send a message to an offline buddy */ return NULL; @@ -799,24 +892,21 @@ { PurpleProxyConnectData *connect_data; PurpleProxyInfo *proxy_info; - const char *ip = NULL; - /* For better or worse, use the first IP*/ - if (bb->ips) - ip = bb->ips->data; + const char *ip = bb->ips->data; purple_debug_info("bonjour", "Starting conversation with %s\n", to); /* Make sure that the account always has a proxy of "none". * This is kind of dirty, but proxy_connect_none() isn't exposed. */ - proxy_info = purple_account_get_proxy_info(data->account); + proxy_info = purple_account_get_proxy_info(jdata->account); if (proxy_info == NULL) { proxy_info = purple_proxy_info_new(); - purple_account_set_proxy_info(data->account, proxy_info); + purple_account_set_proxy_info(jdata->account, proxy_info); } purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_NONE); - connect_data = purple_proxy_connect(NULL, data->account, + connect_data = purple_proxy_connect(NULL, jdata->account, ip, bb->port_p2pj, _connected_to_buddy, pb); if (connect_data == NULL) { @@ -824,7 +914,7 @@ return NULL; } - bb->conversation = bonjour_jabber_conv_new(pb); + bb->conversation = bonjour_jabber_conv_new(pb, jdata->account, ip); 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. */ @@ -834,7 +924,7 @@ } int -bonjour_jabber_send_message(BonjourJabber *data, const gchar *to, const gchar *body) +bonjour_jabber_send_message(BonjourJabber *jdata, const gchar *to, const gchar *body) { xmlnode *message_node, *node, *node2; gchar *message; @@ -842,7 +932,7 @@ BonjourBuddy *bb; int ret; - pb = _find_or_start_conversation(data, to); + pb = _find_or_start_conversation(jdata, 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 */ @@ -853,7 +943,7 @@ message_node = xmlnode_new("message"); 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, "from", purple_account_get_username(jdata->account)); xmlnode_set_attrib(message_node, "type", "chat"); /* Enclose the message from the UI within a "font" node */ @@ -885,26 +975,57 @@ return ret; } +static gboolean +_async_bonjour_jabber_close_conversation_cb(gpointer data) { + BonjourJabberConversation *bconv = data; + bonjour_jabber_close_conversation(bconv); + return FALSE; +} + +void +async_bonjour_jabber_close_conversation(BonjourJabberConversation *bconv) { + BonjourJabber *jdata = ((BonjourData*) bconv->account->gc->proto_data)->jabber_data; + + jdata->pending_conversations = g_slist_remove(jdata->pending_conversations, bconv); + + /* Disconnect this conv. from the buddy here so it can't be disposed of twice.*/ + if(bconv->pb != NULL) { + BonjourBuddy *bb = bconv->pb->proto_data; + if (bb->conversation == bconv) + bb->conversation = NULL; + } + + purple_timeout_add(0, _async_bonjour_jabber_close_conversation_cb, bconv); +} + void bonjour_jabber_close_conversation(BonjourJabberConversation *bconv) { if (bconv != NULL) { - GList *xfers, *tmp_next; - BonjourData *bd = bconv->pb->account->gc->proto_data; + BonjourData *bd = NULL; + + if(PURPLE_CONNECTION_IS_VALID(bconv->account->gc)) { + bd = bconv->account->gc->proto_data; + bd->jabber_data->pending_conversations = g_slist_remove(bd->jabber_data->pending_conversations, bconv); + } /* Cancel any file transfers that are waiting to begin */ - xfers = bd->xfer_lists; - while(xfers != NULL) { - PurpleXfer *xfer = xfers->data; - tmp_next = xfers->next; - /* We only need to cancel this if it hasn't actually started transferring. */ - /* This will change if we ever support IBB transfers. */ - if (strcmp(xfer->who, bconv->pb->name) == 0 - && (purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_NOT_STARTED - || purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_UNKNOWN)) { - purple_xfer_cancel_remote(xfer); + /* There wont be any transfers if it hasn't been attached to a buddy */ + if (bconv->pb != NULL && bd != NULL) { + GSList *xfers, *tmp_next; + xfers = bd->xfer_lists; + while(xfers != NULL) { + PurpleXfer *xfer = xfers->data; + tmp_next = xfers->next; + /* We only need to cancel this if it hasn't actually started transferring. */ + /* This will change if we ever support IBB transfers. */ + if (strcmp(xfer->who, bconv->pb->name) == 0 + && (purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_NOT_STARTED + || purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_UNKNOWN)) { + purple_xfer_cancel_remote(xfer); + } + xfers = tmp_next; } - xfers = tmp_next; } /* Close the socket and remove the watcher */ @@ -933,25 +1054,26 @@ if (bconv->context != NULL) bonjour_parser_setup(bconv); + g_free(bconv->buddy_name); + g_free(bconv->ip); g_free(bconv); } } void -bonjour_jabber_stop(BonjourJabber *data) +bonjour_jabber_stop(BonjourJabber *jdata) { /* Close the server socket and remove the watcher */ - if (data->socket >= 0) - close(data->socket); - if (data->watcher_id > 0) - purple_input_remove(data->watcher_id); + if (jdata->socket >= 0) + close(jdata->socket); + if (jdata->watcher_id > 0) + purple_input_remove(jdata->watcher_id); /* Close all the conversation sockets and remove all the watchers after sending end streams */ - if (data->account->gc != NULL) - { + if (jdata->account->gc != NULL) { GSList *buddies, *l; - buddies = purple_find_buddies(data->account, purple_account_get_username(data->account)); + buddies = purple_find_buddies(jdata->account, NULL); for (l = buddies; l; l = l->next) { BonjourBuddy *bb = ((PurpleBuddy*) l->data)->proto_data; bonjour_jabber_close_conversation(bb->conversation); @@ -960,6 +1082,11 @@ g_slist_free(buddies); } + + while (jdata->pending_conversations != NULL) { + bonjour_jabber_close_conversation(jdata->pending_conversations->data); + jdata->pending_conversations = g_slist_delete_link(jdata->pending_conversations, jdata->pending_conversations); + } } XepIq * @@ -1056,7 +1183,7 @@ PurpleBuddy *pb = NULL; /* start the talk, reuse the message socket */ - pb = _find_or_start_conversation ((BonjourJabber*)iq->data, iq->to); + pb = _find_or_start_conversation((BonjourJabber*) iq->data, iq->to); /* Send the message */ if (pb != NULL) { /* Convert xml node into stream */ diff -r e13759a83714 -r 2be2eec7d273 libpurple/protocols/bonjour/jabber.h --- a/libpurple/protocols/bonjour/jabber.h Sat Dec 15 05:15:31 2007 +0000 +++ b/libpurple/protocols/bonjour/jabber.h Sat Dec 15 05:17:48 2007 +0000 @@ -38,7 +38,8 @@ gint port; gint socket; gint watcher_id; - PurpleAccount* account; + PurpleAccount *account; + GSList *pending_conversations; } BonjourJabber; typedef struct _BonjourJabberConversation @@ -54,6 +55,11 @@ xmlParserCtxt *context; xmlnode *current; PurpleBuddy *pb; + PurpleAccount *account; + + /* The following are only needed before attaching to a PurpleBuddy */ + gchar *buddy_name; + gchar *ip; } BonjourJabberConversation; /** @@ -68,14 +74,20 @@ void bonjour_jabber_close_conversation(BonjourJabberConversation *bconv); -void bonjour_jabber_stream_started(PurpleBuddy *pb); +void async_bonjour_jabber_close_conversation(BonjourJabberConversation *bconv); -void bonjour_jabber_stream_ended(PurpleBuddy *pb); +void bonjour_jabber_stream_started(BonjourJabberConversation *bconv); + +void bonjour_jabber_stream_ended(BonjourJabberConversation *bconv); void bonjour_jabber_process_packet(PurpleBuddy *pb, xmlnode *packet); void bonjour_jabber_stop(BonjourJabber *data); +void bonjour_jabber_conv_match_by_ip(BonjourJabberConversation *bconv); + +void bonjour_jabber_conv_match_by_name(BonjourJabberConversation *bconv); + typedef enum { XEP_IQ_SET, XEP_IQ_GET, diff -r e13759a83714 -r 2be2eec7d273 libpurple/protocols/bonjour/parser.c --- a/libpurple/protocols/bonjour/parser.c Sat Dec 15 05:15:31 2007 +0000 +++ b/libpurple/protocols/bonjour/parser.c Sat Dec 15 05:17:48 2007 +0000 @@ -31,26 +31,59 @@ #include "util.h" #include "xmlnode.h" +static gboolean +parse_from_attrib_and_find_buddy(BonjourJabberConversation *bconv, int nb_attributes, const xmlChar **attributes) { + int i; + + /* If the "from" attribute is specified, attach it to the conversation. */ + for(i=0; i < nb_attributes * 5; i+=5) { + if(!xmlStrcmp(attributes[i], (xmlChar*) "from")) { + int len = attributes[i+4] - attributes[i+3]; + bconv->buddy_name = g_strndup(attributes[i+3], len); + bonjour_jabber_conv_match_by_name(bconv); + + return (bconv->pb != NULL); + } + } + + return FALSE; +} + static void bonjour_parser_element_start_libxml(void *user_data, const xmlChar *element_name, const xmlChar *prefix, const xmlChar *namespace, int nb_namespaces, const xmlChar **namespaces, int nb_attributes, int nb_defaulted, const xmlChar **attributes) { - PurpleBuddy *pb = user_data; - BonjourBuddy *bb = pb->proto_data; - BonjourJabberConversation *bconv = bb->conversation; + BonjourJabberConversation *bconv = user_data; xmlnode *node; int i; - if(!element_name) { - return; - } else if(!xmlStrcmp(element_name, (xmlChar*) "stream")) { - bconv->recv_stream_start = TRUE; - bonjour_jabber_stream_started(pb); + g_return_if_fail(element_name != NULL); + + if(!xmlStrcmp(element_name, (xmlChar*) "stream")) { + if(!bconv->recv_stream_start) { + bconv->recv_stream_start = TRUE; + + if (bconv->pb == NULL) + parse_from_attrib_and_find_buddy(bconv, nb_attributes, attributes); + + bonjour_jabber_stream_started(bconv); + } } else { + /* If we haven't yet attached a buddy and this isn't "", + * try to get a "from" attribute as a last resort to match our buddy. */ + if(bconv->pb == NULL + && !(prefix && !xmlStrcmp(prefix, (xmlChar*) "stream") + && !xmlStrcmp(element_name, (xmlChar*) "features")) + && !parse_from_attrib_and_find_buddy(bconv, nb_attributes, attributes)) + /* We've run out of options for finding who the conversation is from + using explicitly specified stuff; see if we can make a good match + by using the IP */ + bonjour_jabber_conv_match_by_ip(bconv); + if(bconv->current) node = xmlnode_new_child(bconv->current, (const char*) element_name); else @@ -82,27 +115,19 @@ } } -static gboolean _async_bonjour_jabber_stream_ended_cb(gpointer data) { - bonjour_jabber_stream_ended((PurpleBuddy *) data); - return FALSE; -} - static void bonjour_parser_element_end_libxml(void *user_data, const xmlChar *element_name, const xmlChar *prefix, const xmlChar *namespace) { - PurpleBuddy *pb = user_data; - BonjourBuddy *bb = pb->proto_data; - BonjourJabberConversation *bconv = bb->conversation; + BonjourJabberConversation *bconv = user_data; if(!bconv->current) { /* We don't keep a reference to the start stream xmlnode, * so we have to check for it here to close the conversation */ - if(!xmlStrcmp(element_name, (xmlChar*) "stream")) { + if(!xmlStrcmp(element_name, (xmlChar*) "stream")) /* Asynchronously close the conversation to prevent bonjour_parser_setup() * being called from within this context */ - purple_timeout_add(0, _async_bonjour_jabber_stream_ended_cb, pb); - } + async_bonjour_jabber_close_conversation(bconv); return; } @@ -112,7 +137,7 @@ } else { xmlnode *packet = bconv->current; bconv->current = NULL; - bonjour_jabber_process_packet(pb, packet); + bonjour_jabber_process_packet(bconv->pb, packet); xmlnode_free(packet); } } @@ -120,9 +145,7 @@ static void bonjour_parser_element_text_libxml(void *user_data, const xmlChar *text, int text_len) { - PurpleBuddy *pb = user_data; - BonjourBuddy *bb = pb->proto_data; - BonjourJabberConversation *bconv = bb->conversation; + BonjourJabberConversation *bconv = user_data; if(!bconv->current) return; @@ -184,21 +207,17 @@ } -void bonjour_parser_process(PurpleBuddy *pb, const char *buf, int len) +void bonjour_parser_process(BonjourJabberConversation *bconv, const char *buf, int len) { - BonjourBuddy *bb = pb->proto_data; - g_return_if_fail(bb != NULL); - g_return_if_fail(bb->conversation != NULL); - - if (bb->conversation->context == NULL) { + if (bconv->context == NULL) { /* libxml inconsistently starts parsing on creating the * parser, so do a ParseChunk right afterwards to force it. */ - bb->conversation->context = xmlCreatePushParserCtxt(&bonjour_parser_libxml, pb, buf, len, NULL); - xmlParseChunk(bb->conversation->context, "", 0, 0); - } else if (xmlParseChunk(bb->conversation->context, buf, len, 0) < 0) { + bconv->context = xmlCreatePushParserCtxt(&bonjour_parser_libxml, bconv, buf, len, NULL); + xmlParseChunk(bconv->context, "", 0, 0); + } else if (xmlParseChunk(bconv->context, buf, len, 0) < 0) /* TODO: What should we do here - I assume we should display an error or something (maybe just print something to the conv?) */ purple_debug_error("bonjour", "Error parsing xml.\n"); - } + } diff -r e13759a83714 -r 2be2eec7d273 libpurple/protocols/bonjour/parser.h --- a/libpurple/protocols/bonjour/parser.h Sat Dec 15 05:15:31 2007 +0000 +++ b/libpurple/protocols/bonjour/parser.h Sat Dec 15 05:17:48 2007 +0000 @@ -28,6 +28,6 @@ #include "jabber.h" void bonjour_parser_setup(BonjourJabberConversation *bconv); -void bonjour_parser_process(PurpleBuddy *pb, const char *buf, int len); +void bonjour_parser_process(BonjourJabberConversation *bconv, const char *buf, int len); #endif /* _PURPLE_BONJOUR_PARSER_H_ */ diff -r e13759a83714 -r 2be2eec7d273 libpurple/protocols/simple/sipmsg.c --- a/libpurple/protocols/simple/sipmsg.c Sat Dec 15 05:15:31 2007 +0000 +++ b/libpurple/protocols/simple/sipmsg.c Sat Dec 15 05:17:48 2007 +0000 @@ -45,7 +45,10 @@ line = g_strndup(msg, tmp - msg); smsg = sipmsg_parse_header(line); - smsg->body = g_strdup(tmp + 4); + if(smsg != NULL) + smsg->body = g_strdup(tmp + 4); + else + purple_debug_error("SIMPLE", "No header parsed from line: %s\n", line); g_free(line); return smsg; diff -r e13759a83714 -r 2be2eec7d273 pidgin/gtkconn.c --- a/pidgin/gtkconn.c Sat Dec 15 05:15:31 2007 +0000 +++ b/pidgin/gtkconn.c Sat Dec 15 05:17:48 2007 +0000 @@ -184,36 +184,39 @@ static void pidgin_connection_network_connected () { - GList *list = purple_accounts_get_all_active(); + GList *list, *l; PidginBuddyList *gtkblist = pidgin_blist_get_default_gtk_blist(); if(gtkblist) pidgin_status_box_set_network_available(PIDGIN_STATUS_BOX(gtkblist->statusbox), TRUE); - while (list) { - PurpleAccount *account = (PurpleAccount*)list->data; + l = list = purple_accounts_get_all_active(); + while (l) { + PurpleAccount *account = (PurpleAccount*)l->data; g_hash_table_remove(auto_reconns, account); if (purple_account_is_disconnected(account)) do_signon(account); - list = list->next; + l = l->next; } + g_list_free(list); } static void pidgin_connection_network_disconnected () { - GList *l = purple_accounts_get_all_active(); + GList *list, *l; PidginBuddyList *gtkblist = pidgin_blist_get_default_gtk_blist(); PurplePluginProtocolInfo *prpl_info = NULL; PurpleConnection *gc = NULL; - + if(gtkblist) pidgin_status_box_set_network_available(PIDGIN_STATUS_BOX(gtkblist->statusbox), FALSE); + l = list = purple_accounts_get_all_active(); while (l) { PurpleAccount *a = (PurpleAccount*)l->data; if (!purple_account_is_disconnected(a)) { gc = purple_account_get_connection(a); - if (gc && gc->prpl) + if (gc && gc->prpl) prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl); if (prpl_info) { if (prpl_info->keepalive) @@ -224,6 +227,7 @@ } l = l->next; } + g_list_free(list); } static void pidgin_connection_notice(PurpleConnection *gc, const char *text) diff -r e13759a83714 -r 2be2eec7d273 pidgin/gtkconv.c --- a/pidgin/gtkconv.c Sat Dec 15 05:15:31 2007 +0000 +++ b/pidgin/gtkconv.c Sat Dec 15 05:17:48 2007 +0000 @@ -4420,16 +4420,17 @@ lines = gtk_text_buffer_get_line_count(buffer); - /* Show a maximum of 4 lines */ - lines = MIN(lines, 4); - wrapped_lines = MIN(wrapped_lines, 4); + /* Show a maximum of 4 lines, minimum of 2 */ + lines = MIN(MAX(lines, 2), 4); + wrapped_lines = MIN(MAX(wrapped_lines, 2), 4); pad_top = gtk_text_view_get_pixels_above_lines(GTK_TEXT_VIEW(gtkconv->entry)); pad_bottom = gtk_text_view_get_pixels_below_lines(GTK_TEXT_VIEW(gtkconv->entry)); pad_inside = gtk_text_view_get_pixels_inside_wrap(GTK_TEXT_VIEW(gtkconv->entry)); - height = (oneline.height + pad_top + pad_bottom) * MAX(lines, 2); - height += (oneline.height + pad_inside) * (wrapped_lines - lines); + height = (oneline.height + pad_top + pad_bottom) * lines; + if (wrapped_lines > lines) + height += (oneline.height + pad_inside) * (wrapped_lines - lines); gtkconv->auto_resize = TRUE; g_idle_add(reset_auto_resize_cb, gtkconv); diff -r e13759a83714 -r 2be2eec7d273 pidgin/win32/gtkwin32dep.c --- a/pidgin/win32/gtkwin32dep.c Sat Dec 15 05:15:31 2007 +0000 +++ b/pidgin/win32/gtkwin32dep.c Sat Dec 15 05:17:48 2007 +0000 @@ -40,6 +40,7 @@ #include "debug.h" #include "notify.h" +#include "network.h" #include "resource.h" #include "idletrack.h" @@ -51,6 +52,7 @@ #include "gtkwin32dep.h" #include "win32dep.h" #include "gtkconv.h" +#include "gtkconn.h" #include "util.h" #include "wspell.h" @@ -64,6 +66,7 @@ typedef BOOL (CALLBACK* LPFNFLASHWINDOWEX)(PFLASHWINFO); static LPFNFLASHWINDOWEX MyFlashWindowEx = NULL; +static gboolean pwm_handles_connections = TRUE; /* @@ -202,6 +205,43 @@ #define PIDGIN_WM_FOCUS_REQUEST (WM_APP + 13) #define PIDGIN_WM_PROTOCOL_HANDLE (WM_APP + 14) +static void* +winpidgin_netconfig_changed_cb(void *data) +{ + pwm_handles_connections = FALSE; + + return NULL; +} + +static void* +winpidgin_get_handle(void) +{ + static int handle; + + return &handle; +} + +static gboolean +winpidgin_pwm_reconnect() +{ + purple_signal_disconnect(purple_network_get_handle(), "network-configuration-changed", + winpidgin_get_handle(), PURPLE_CALLBACK(winpidgin_netconfig_changed_cb)); + + if (pwm_handles_connections == TRUE) { + PurpleConnectionUiOps *ui_ops = pidgin_connections_get_ui_ops(); + + purple_debug_info("winpidgin", "Resumed from standby, reconnecting accounts.\n"); + + if (ui_ops != NULL && ui_ops->network_connected != NULL) + ui_ops->network_connected(); + } else { + purple_debug_info("winpidgin", "Resumed from standby, gtkconn will handle reconnecting.\n"); + pwm_handles_connections = TRUE; + } + + return FALSE; +} + static LRESULT CALLBACK message_window_handler(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { if (msg == PIDGIN_WM_FOCUS_REQUEST) { @@ -213,6 +253,28 @@ purple_debug_info("winpidgin", "Got protocol handler request: %s\n", proto_msg ? proto_msg : ""); purple_got_protocol_handler_uri(proto_msg); return TRUE; + } else if (msg == WM_POWERBROADCAST) { + if (wparam == PBT_APMQUERYSUSPEND) { + purple_debug_info("winpidgin", "Windows requesting permission to suspend.\n"); + return TRUE; + } else if (wparam == PBT_APMSUSPEND) { + PurpleConnectionUiOps *ui_ops = pidgin_connections_get_ui_ops(); + + purple_debug_info("winpidgin", "Entering system standby, disconnecting accounts.\n"); + + if (ui_ops != NULL && ui_ops->network_disconnected != NULL) + ui_ops->network_disconnected(); + + purple_signal_connect(purple_network_get_handle(), "network-configuration-changed", winpidgin_get_handle(), + PURPLE_CALLBACK(winpidgin_netconfig_changed_cb), NULL); + + return TRUE; + } else if (wparam == PBT_APMRESUMESUSPEND) { + purple_debug_info("winpidgin", "Resuming from system standby.\n"); + /* TODO: It seems like it'd be wise to use the NLA message, if possible, instead of this. */ + purple_timeout_add_seconds(1, winpidgin_pwm_reconnect, NULL); + return TRUE; + } } return DefWindowProc(hwnd, msg, wparam, lparam); @@ -242,7 +304,7 @@ /* Create the window */ if(!(win_hwnd = CreateWindow(wname, TEXT("WinpidginMsgWin"), 0, 0, 0, 0, 0, - HWND_MESSAGE, NULL, winpidgin_exe_hinstance(), 0))) { + NULL, NULL, winpidgin_exe_hinstance(), 0))) { purple_debug_error("winpidgin", "Unable to create message window.\n"); return NULL;