# HG changeset patch # User Marcus Lundblad # Date 1233511478 0 # Node ID 03541b3adb387ca4430374a169a595bcbc52cee6 # Parent feea711ac242327745014c3353b813e06009e4b8# Parent e6683ec9d3105bec4c150ece00770454e8fec030 propagate from branch 'im.pidgin.pidgin' (head f3cf3ba10ebc911a27833496dcc4d4dca3de66c5) to branch 'im.pidgin.cpw.malu.xmpp.idle' (head 8a78a27a5123f05441fd5df8c423b57929973128) diff -r feea711ac242 -r 03541b3adb38 COPYRIGHT --- a/COPYRIGHT Sun Feb 01 18:00:05 2009 +0000 +++ b/COPYRIGHT Sun Feb 01 18:04:38 2009 +0000 @@ -314,6 +314,7 @@ Ted Percival Eduardo Pérez Matt Perry +Luke Petre Diego Petten Nathan Peterson Sebastián E. Peyrott diff -r feea711ac242 -r 03541b3adb38 ChangeLog --- a/ChangeLog Sun Feb 01 18:00:05 2009 +0000 +++ b/ChangeLog Sun Feb 01 18:04:38 2009 +0000 @@ -2,17 +2,24 @@ version 2.5.5 (??/??/????): libpurple: - * Fix transfer of buddy icons, custom smileys, and files from the - latest Windows Live Messenger 9 official client. (Thomas - Gibson-Robinson) * Fix a crash when removing an account with an unknown protocol id. - * Large (multi-part) messages on MSN are now correctly re-combined. * Beta support for SSL connections for AIM and ICQ accounts. To enable, check the "Use SSL" option from the Advanced tab when editing your AIM or ICQ account. (Paul Aurich) * Fix retrieval of ICQ status messages from users of ICQ 6.x, Miranda, and other libpurple clients (fixes with libpurple users only on statuses other than Available). (Daniel Ljungborg) + * Fix a memory leak in SILC. (Luke Petre) + + MSN: + * Fix transfer of buddy icons, custom smileys, and files from the + latest Windows Live Messenger 9 official client. (Thomas + Gibson-Robinson) + * Large (multi-part) messages are now correctly re-combined. + * Federated/Yahoo! buddies should now stop creating sync issues at + every signin. You may need to remove duplicates in the Address + Book. See the FAQ for more information. + * Messages from Yahoo! buddies are no longer silently dropped. Finch: * Allow rebinding keys to change the focused widget (details in the diff -r feea711ac242 -r 03541b3adb38 ChangeLog.win32 --- a/ChangeLog.win32 Sun Feb 01 18:00:05 2009 +0000 +++ b/ChangeLog.win32 Sun Feb 01 18:04:38 2009 +0000 @@ -1,3 +1,8 @@ +version 2.5.5 (??/??/2009): + * Remove the "Flash window when chat messages are received" pref from + the Windows Pidgin Options plugin - the Message Notification plugin + does this (and much more). + version 2.5.4 (01/12/2009): * Fix the "Hang on Exit" issue that a number of users encountered. * Updated GTK+ to 2.14.6 diff -r feea711ac242 -r 03541b3adb38 libpurple/network.c --- a/libpurple/network.c Sun Feb 01 18:00:05 2009 +0000 +++ b/libpurple/network.c Sun Feb 01 18:04:38 2009 +0000 @@ -74,8 +74,12 @@ /* Mutex for the other global vars */ static GStaticMutex mutex = G_STATIC_MUTEX_INIT; -static gboolean network_initialized; -static HANDLE network_change_handle; +static gboolean network_initialized = FALSE; +static HANDLE network_change_handle = NULL; +static int (WSAAPI *MyWSANSPIoctl) ( + HANDLE hLookup, DWORD dwControlCode, LPVOID lpvInBuffer, + DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer, + LPDWORD lpcbBytesReturned, LPWSACOMPLETION lpCompletion) = NULL; #endif struct _PurpleNetworkListenData { @@ -538,27 +542,28 @@ return FALSE; } +static gboolean _print_debug_msg(gpointer data) { + gchar *msg = data; + purple_debug_warning("network", msg); + g_free(msg); + return FALSE; +} + static gpointer wpurple_network_change_thread(gpointer data) { WSAQUERYSET qs; WSAEVENT *nla_event; - time_t last_trigger = time(NULL); - - int (WSAAPI *MyWSANSPIoctl) ( - HANDLE hLookup, DWORD dwControlCode, LPVOID lpvInBuffer, - DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer, - LPDWORD lpcbBytesReturned, LPWSACOMPLETION lpCompletion) = NULL; - - if (!(MyWSANSPIoctl = (void*) wpurple_find_and_loadproc("ws2_32.dll", "WSANSPIoctl"))) { - g_thread_exit(NULL); - return NULL; - } + time_t last_trigger = time(NULL) - 31; + char buf[4096]; + WSAQUERYSET *res = (LPWSAQUERYSET) buf; + DWORD size; if ((nla_event = WSACreateEvent()) == WSA_INVALID_EVENT) { int errorid = WSAGetLastError(); gchar *msg = g_win32_error_message(errorid); - purple_debug_warning("network", "Couldn't create WSA event. " - "Message: %s (%d).\n", msg, errorid); + purple_timeout_add(0, _print_debug_msg, + g_strdup_printf("Couldn't create WSA event. " + "Message: %s (%d).\n", msg, errorid)); g_free(msg); g_thread_exit(NULL); return NULL; @@ -579,30 +584,26 @@ return NULL; } - memset(&qs, 0, sizeof(WSAQUERYSET)); - qs.dwSize = sizeof(WSAQUERYSET); - qs.dwNameSpace = NS_NLA; - if (WSALookupServiceBegin(&qs, 0, &network_change_handle) == SOCKET_ERROR) { - int errorid = WSAGetLastError(); - gchar *msg = g_win32_error_message(errorid); - purple_debug_warning("network", "Couldn't retrieve NLA SP lookup handle. " - "NLA service is probably not running. Message: %s (%d).\n", - msg, errorid); - g_free(msg); - WSACloseEvent(nla_event); - g_static_mutex_unlock(&mutex); - g_thread_exit(NULL); - return NULL; + if (network_change_handle == NULL) { + memset(&qs, 0, sizeof(WSAQUERYSET)); + qs.dwSize = sizeof(WSAQUERYSET); + qs.dwNameSpace = NS_NLA; + if (WSALookupServiceBegin(&qs, 0, &network_change_handle) == SOCKET_ERROR) { + int errorid = WSAGetLastError(); + gchar *msg = g_win32_error_message(errorid); + purple_timeout_add(0, _print_debug_msg, + g_strdup_printf("Couldn't retrieve NLA SP lookup handle. " + "NLA service is probably not running. Message: %s (%d).\n", + msg, errorid)); + g_free(msg); + WSACloseEvent(nla_event); + g_static_mutex_unlock(&mutex); + g_thread_exit(NULL); + return NULL; + } } g_static_mutex_unlock(&mutex); - /* Make sure at least 30 seconds have elapsed since the last - * notification so we don't peg the cpu if this keeps changing. */ - if ((time(NULL) - last_trigger) < 30) - Sleep(30000); - - last_trigger = time(NULL); - memset(&completion, 0, sizeof(WSACOMPLETION)); completion.Type = NSP_NOTIFY_EVENT; overlapped.hEvent = nla_event; @@ -610,18 +611,34 @@ if (MyWSANSPIoctl(network_change_handle, SIO_NSP_NOTIFY_CHANGE, NULL, 0, NULL, 0, &retLen, &completion) == SOCKET_ERROR) { int errorid = WSAGetLastError(); + if (errorid == WSA_INVALID_HANDLE) { + purple_timeout_add(0, _print_debug_msg, + g_strdup("Invalid NLA handle; resetting.\n")); + g_static_mutex_lock(&mutex); + retval = WSALookupServiceEnd(network_change_handle); + network_change_handle = NULL; + g_static_mutex_unlock(&mutex); + continue; /* WSA_IO_PENDING indicates successful async notification will happen */ - if (errorid != WSA_IO_PENDING) { + } else if (errorid != WSA_IO_PENDING) { gchar *msg = g_win32_error_message(errorid); - purple_debug_warning("network", "Unable to wait for changes. Message: %s (%d).\n", - msg, errorid); + purple_timeout_add(0, _print_debug_msg, + g_strdup_printf("Unable to wait for changes. Message: %s (%d).\n", + msg, errorid)); g_free(msg); } } + /* Make sure at least 30 seconds have elapsed since the last + * notification so we don't peg the cpu if this keeps changing. */ + if ((time(NULL) - last_trigger) < 30) + Sleep(30000); + /* This will block until NLA notifies us */ retval = WaitForSingleObjectEx(nla_event, WSA_INFINITE, TRUE); + last_trigger = time(NULL); + g_static_mutex_lock(&mutex); if (network_initialized == FALSE) { /* Time to die */ @@ -631,8 +648,14 @@ return NULL; } - retval = WSALookupServiceEnd(network_change_handle); - network_change_handle = NULL; + size = sizeof(buf); + while ((retval = WSALookupServiceNext(network_change_handle, 0, &size, res)) == ERROR_SUCCESS) { + /*purple_timeout_add(0, _print_debug_msg, + g_strdup_printf("thread found network '%s'\n", + res->lpszServiceInstanceName ? res->lpszServiceInstanceName : "(NULL)"));*/ + size = sizeof(buf); + } + WSAResetEvent(nla_event); g_static_mutex_unlock(&mutex); @@ -768,11 +791,12 @@ if (cnt < 0) /* Assume there is a network */ current_network_count = 1; /* Don't listen for network changes if we can't tell anyway */ - else - { + else { current_network_count = cnt; - if (!g_thread_create(wpurple_network_change_thread, NULL, FALSE, &err)) - purple_debug_error("network", "Couldn't create Network Monitor thread: %s\n", err ? err->message : ""); + if ((MyWSANSPIoctl = (void*) wpurple_find_and_loadproc("ws2_32.dll", "WSANSPIoctl"))) { + if (!g_thread_create(wpurple_network_change_thread, NULL, FALSE, &err)) + purple_debug_error("network", "Couldn't create Network Monitor thread: %s\n", err ? err->message : ""); + } } #endif @@ -848,10 +872,12 @@ msg, errorid); g_free(msg); } + network_change_handle = NULL; + } g_static_mutex_unlock(&mutex); #endif purple_signal_unregister(purple_network_get_handle(), - "network-configuration-changed"); + "network-configuration-changed"); } diff -r feea711ac242 -r 03541b3adb38 libpurple/protocols/msn/contact.c --- a/libpurple/protocols/msn/contact.c Sun Feb 01 18:00:05 2009 +0000 +++ b/libpurple/protocols/msn/contact.c Sun Feb 01 18:04:38 2009 +0000 @@ -158,6 +158,113 @@ state->action |= action; } +/*************************************************************** + * General SOAP handling + ***************************************************************/ + +static const char * +msn_contact_operation_str(MsnCallbackAction action) +{ + /* Make sure this is large enough when adding more */ + static char buf[BUF_LEN]; + buf[0] = '\0'; + + if (action & MSN_ADD_BUDDY) + strcat(buf, "Adding Buddy,"); + if (action & MSN_MOVE_BUDDY) + strcat(buf, "Moving Buddy,"); + if (action & MSN_ACCEPTED_BUDDY) + strcat(buf, "Accepted Buddy,"); + if (action & MSN_DENIED_BUDDY) + strcat(buf, "Denied Buddy,"); + if (action & MSN_ADD_GROUP) + strcat(buf, "Adding Group,"); + if (action & MSN_DEL_GROUP) + strcat(buf, "Deleting Group,"); + if (action & MSN_RENAME_GROUP) + strcat(buf, "Renaming Group,"); + if (action & MSN_UPDATE_INFO) + strcat(buf, "Updating Contact Info,"); + + return buf; +} + +static gboolean msn_contact_request(MsnCallbackState *state); + +static void +msn_contact_request_cb(MsnSoapMessage *req, MsnSoapMessage *resp, + gpointer data) +{ + MsnCallbackState *state = data; + xmlnode *fault; + char *faultcode_str; + + if (resp == NULL) { + purple_debug_error("msn", + "Operation {%s} failed. No response received from server.\n", + msn_contact_operation_str(state->action)); + return; + } + + fault = xmlnode_get_child(resp->xml, "Body/Fault"); + + if (fault == NULL) { + /* No errors */ + if (state->cb) + ((MsnSoapCallback)state->cb)(req, resp, data); + msn_callback_state_free(state); + return; + } + + faultcode_str = xmlnode_get_data(xmlnode_get_child(fault, "faultcode")); + + if (faultcode_str && g_str_equal(faultcode_str, "q0:BadContextToken")) { + purple_debug_info("msn", + "Contact Operation {%s} failed because of bad token." + " Updating token now and retrying operation.\n", + msn_contact_operation_str(state->action)); + /* Token has expired, so renew it, and try again later */ + msn_nexus_update_token(state->session->nexus, MSN_AUTH_CONTACTS, + (GSourceFunc)msn_contact_request, data); + } + else + { + if (state->cb) { + ((MsnSoapCallback)state->cb)(req, resp, data); + } else { + /* We don't know how to respond to this faultcode, so log it */ + char *str = xmlnode_to_str(fault, NULL); + purple_debug_error("msn", "Operation {%s} Failed, SOAP Fault was: %s\n", + msn_contact_operation_str(state->action), str); + g_free(str); + } + msn_callback_state_free(state); + } + + g_free(faultcode_str); +} + +static gboolean +msn_contact_request(MsnCallbackState *state) +{ + if (state->token == NULL) + state->token = xmlnode_get_child(state->body, + "Header/ABAuthHeader/TicketToken"); + /* delete old & replace with new token */ + xmlnode_free(state->token->child); + xmlnode_insert_data(state->token, + msn_nexus_get_token_str(state->session->nexus, MSN_AUTH_CONTACTS), -1); + msn_soap_message_send(state->session, + msn_soap_message_new(state->post_action, xmlnode_copy(state->body)), + MSN_CONTACT_SERVER, state->post_url, FALSE, + msn_contact_request_cb, state); + return FALSE; +} + +/*************************************************************** + * Address Book and Membership List Operations + ***************************************************************/ + /*get MSN member role utility*/ static MsnListId msn_get_memberrole(const char *role) @@ -180,9 +287,10 @@ static void msn_create_address_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data) { + MsnCallbackState *state = data; if (resp && xmlnode_get_child(resp->xml, "Body/Fault") == NULL) { purple_debug_info("msn", "Address Book successfully created!\n"); - msn_get_address_book((MsnSession *)data, MSN_PS_INITIAL, NULL, NULL); + msn_get_address_book(state->session, MSN_PS_INITIAL, NULL, NULL); } else { purple_debug_info("msn", "Address Book creation failed!\n"); } @@ -192,7 +300,7 @@ msn_create_address_book(MsnSession *session) { gchar *body; - gchar *token_str; + MsnCallbackState *state; g_return_if_fail(session != NULL); g_return_if_fail(session->user != NULL); @@ -200,17 +308,15 @@ purple_debug_info("msn", "Creating an Address Book.\n"); - token_str = g_markup_escape_text( - msn_nexus_get_token_str(session->nexus, MSN_AUTH_CONTACTS), -1); body = g_strdup_printf(MSN_ADD_ADDRESSBOOK_TEMPLATE, - token_str, session->user->passport); - g_free(token_str); + session->user->passport); - msn_soap_message_send(session, - msn_soap_message_new(MSN_ADD_ADDRESSBOOK_SOAP_ACTION, - xmlnode_from_str(body, -1)), - MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL, FALSE, - msn_create_address_cb, session); + state = msn_callback_state_new(session); + state->body = xmlnode_from_str(body, -1); + state->post_action = MSN_ADD_ADDRESSBOOK_SOAP_ACTION; + state->post_url = MSN_ADDRESS_BOOK_POST_URL; + state->cb = msn_create_address_cb; + msn_contact_request(state); g_free(body); } @@ -243,7 +349,7 @@ g_free(name); } } - + purple_debug_info("msn", "CL: %s name: %s, Type: %s, MembershipID: %s, NetworkID: %u\n", node, passport, type, member_id == NULL ? "(null)" : member_id, nid); @@ -362,8 +468,8 @@ msn_get_contact_list_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data) { - GetContactListCbData *cb_data = data; - MsnSession *session = cb_data->session; + MsnCallbackState *state = data; + MsnSession *session = state->session; g_return_if_fail(session != NULL); @@ -379,7 +485,7 @@ dynamicItemLastChange = purple_account_get_string(session->account, "dynamicItemLastChange", NULL); - if (cb_data->which == MSN_PS_INITIAL) { + if (state->partner_scenario == MSN_PS_INITIAL) { #ifdef MSN_PARTIAL_LISTS /* XXX: this should be enabled when we can correctly do partial syncs with the server. Currently we need to retrieve the whole @@ -390,8 +496,6 @@ #endif } } - - g_free(cb_data); } /*SOAP get contact list*/ @@ -401,8 +505,7 @@ { gchar *body = NULL; gchar *update_str = NULL; - gchar *token_str; - GetContactListCbData cb_data = { session, partner_scenario }; + MsnCallbackState *state; const gchar *partner_scenario_str = MsnSoapPartnerScenarioText[partner_scenario]; purple_debug_misc("msn", "Getting Contact List.\n"); @@ -412,17 +515,16 @@ update_str = g_strdup_printf(MSN_GET_CONTACT_UPDATE_XML, update_time); } - token_str = g_markup_escape_text( - msn_nexus_get_token_str(session->nexus, MSN_AUTH_CONTACTS), -1); body = g_strdup_printf(MSN_GET_CONTACT_TEMPLATE, partner_scenario_str, - token_str, update_str ? update_str : ""); - g_free(token_str); + update_str ? update_str : ""); - msn_soap_message_send(session, - msn_soap_message_new(MSN_GET_CONTACT_SOAP_ACTION, - xmlnode_from_str(body, -1)), - MSN_CONTACT_SERVER, MSN_GET_CONTACT_POST_URL, FALSE, - msn_get_contact_list_cb, g_memdup(&cb_data, sizeof(cb_data))); + state = msn_callback_state_new(session); + state->partner_scenario = partner_scenario; + state->body = xmlnode_from_str(body, -1); + state->post_action = MSN_GET_CONTACT_SOAP_ACTION; + state->post_url = MSN_GET_CONTACT_POST_URL; + state->cb = msn_get_contact_list_cb; + msn_contact_request(state); g_free(update_str); g_free(body); @@ -525,7 +627,7 @@ for(contactNode = xmlnode_get_child(node, "Contact"); contactNode; contactNode = xmlnode_get_next_twin(contactNode)) { - xmlnode *contactId, *contactInfo, *contactType, *passportName, *displayName, *guid, *groupIds, *messenger_user; + xmlnode *contactId, *contactInfo, *contactType, *passportName, *displayName, *guid, *groupIds; xmlnode *annotation; MsnUser *user; @@ -556,58 +658,52 @@ continue; /* Not adding own account as buddy to buddylist */ } - /* ignore non-messenger contacts */ - if ((messenger_user = xmlnode_get_child(contactInfo, "isMessengerUser"))) { - char *is_messenger_user = xmlnode_get_data(messenger_user); - - if(is_messenger_user && !strcmp(is_messenger_user, "false")) { - g_free(is_messenger_user); - continue; - } - - g_free(is_messenger_user); - } - passportName = xmlnode_get_child(contactInfo, "passportName"); if (passportName == NULL) { xmlnode *emailsNode, *contactEmailNode, *emailNode; xmlnode *messengerEnabledNode; char *msnEnabled; - /*TODO: add it to the none-instant Messenger group and recognize as email Membership*/ - /*Yahoo User?*/ + /*TODO: add it to the non-instant Messenger group and recognize as email Membership*/ + /* Yahoo/Federated User? */ emailsNode = xmlnode_get_child(contactInfo, "emails"); if (emailsNode == NULL) { /*TODO: need to support the Mobile type*/ continue; } for (contactEmailNode = xmlnode_get_child(emailsNode, "ContactEmail"); contactEmailNode; - contactEmailNode = xmlnode_get_next_twin(contactEmailNode) ){ - if (!(messengerEnabledNode = xmlnode_get_child(contactEmailNode, "isMessengerEnabled"))) { - /* XXX: Should this be a continue instead of a break? It seems like it'd cause unpredictable results otherwise. */ - break; - } + contactEmailNode = xmlnode_get_next_twin(contactEmailNode)) { + if (!(messengerEnabledNode = xmlnode_get_child(contactEmailNode, "isMessengerEnabled"))) + continue; msnEnabled = xmlnode_get_data(messengerEnabledNode); - if ((emailNode = xmlnode_get_child(contactEmailNode, "email"))) { - g_free(passport); - passport = xmlnode_get_data(emailNode); - } + if (msnEnabled && !strcmp(msnEnabled, "true")) { + if ((emailNode = xmlnode_get_child(contactEmailNode, "email"))) + passport = xmlnode_get_data(emailNode); - if (msnEnabled && !strcmp(msnEnabled, "true")) { /*Messenger enabled, Get the Passport*/ - purple_debug_info("msn", "AB Yahoo User %s\n", passport ? passport : "(null)"); + purple_debug_info("msn", "AB Yahoo/Federated User %s\n", passport ? passport : "(null)"); g_free(msnEnabled); break; - } else { - /*TODO maybe we can just ignore it in Purple?*/ - purple_debug_info("msn", "AB Other type user\n"); } g_free(msnEnabled); } } else { + xmlnode *messenger_user; + /* ignore non-messenger contacts */ + if ((messenger_user = xmlnode_get_child(contactInfo, "isMessengerUser"))) { + char *is_messenger_user = xmlnode_get_data(messenger_user); + + if (is_messenger_user && !strcmp(is_messenger_user, "false")) { + g_free(is_messenger_user); + continue; + } + + g_free(is_messenger_user); + } + passport = xmlnode_get_data(passportName); } @@ -777,10 +873,8 @@ static void msn_get_address_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data) { - MsnSession *session = data; - - if (resp == NULL) - return; + MsnCallbackState *state = data; + MsnSession *session = state->session; g_return_if_fail(session != NULL); @@ -809,7 +903,7 @@ const char *dynamicItemLastChange) { char *body, *update_str = NULL; - gchar *token_str; + MsnCallbackState *state; purple_debug_misc("msn", "Getting Address Book\n"); @@ -819,19 +913,16 @@ else if (LastChanged != NULL) update_str = g_strdup_printf(MSN_GET_ADDRESS_UPDATE_XML, LastChanged); - token_str = g_markup_escape_text( - msn_nexus_get_token_str(session->nexus, MSN_AUTH_CONTACTS), -1); body = g_strdup_printf(MSN_GET_ADDRESS_TEMPLATE, MsnSoapPartnerScenarioText[partner_scenario], - token_str, update_str ? update_str : ""); - g_free(token_str); - msn_soap_message_send(session, - msn_soap_message_new(MSN_GET_ADDRESS_SOAP_ACTION, - xmlnode_from_str(body, -1)), - MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL, FALSE, - msn_get_address_cb, session); + state = msn_callback_state_new(session); + state->body = xmlnode_from_str(body, -1); + state->post_action = MSN_GET_ADDRESS_SOAP_ACTION; + state->post_url = MSN_ADDRESS_BOOK_POST_URL; + state->cb = msn_get_address_cb; + msn_contact_request(state); g_free(update_str); g_free(body); @@ -841,105 +932,6 @@ * Contact Operations ***************************************************************/ -static const char * -msn_contact_operation_str(MsnCallbackAction action) -{ - /* Make sure this is large enough when adding more */ - static char buf[BUF_LEN]; - buf[0] = '\0'; - - if (action & MSN_ADD_BUDDY) - strcat(buf, "Adding Buddy,"); - if (action & MSN_MOVE_BUDDY) - strcat(buf, "Moving Buddy,"); - if (action & MSN_ACCEPTED_BUDDY) - strcat(buf, "Accepted Buddy,"); - if (action & MSN_DENIED_BUDDY) - strcat(buf, "Denied Buddy,"); - if (action & MSN_ADD_GROUP) - strcat(buf, "Adding Group,"); - if (action & MSN_DEL_GROUP) - strcat(buf, "Deleting Group,"); - if (action & MSN_RENAME_GROUP) - strcat(buf, "Renaming Group,"); - if (action & MSN_UPDATE_INFO) - strcat(buf, "Updating Contact Info,"); - - return buf; -} - -static gboolean msn_contact_request(MsnCallbackState *state); - -static void -msn_contact_request_cb(MsnSoapMessage *req, MsnSoapMessage *resp, - gpointer data) -{ - MsnCallbackState *state = data; - xmlnode *fault; - char *faultcode_str; - - if (resp == NULL) { - purple_debug_error("msn", - "Operation {%s} failed. No response received from server.\n", - msn_contact_operation_str(state->action)); - return; - } - - fault = xmlnode_get_child(resp->xml, "Body/Fault"); - - if (fault == NULL) { - /* No errors */ - if (state->cb) - ((MsnSoapCallback)state->cb)(req, resp, data); - msn_callback_state_free(state); - return; - } - - faultcode_str = xmlnode_get_data(xmlnode_get_child(fault, "faultcode")); - - if (faultcode_str && g_str_equal(faultcode_str, "q0:BadContextToken")) { - purple_debug_info("msn", - "Contact Operation {%s} failed because of bad token." - " Updating token now and retrying operation.\n", - msn_contact_operation_str(state->action)); - /* Token has expired, so renew it, and try again later */ - msn_nexus_update_token(state->session->nexus, MSN_AUTH_CONTACTS, - (GSourceFunc)msn_contact_request, data); - } - else - { - if (state->cb) { - ((MsnSoapCallback)state->cb)(req, resp, data); - } else { - /* We don't know how to respond to this faultcode, so log it */ - char *str = xmlnode_to_str(fault, NULL); - purple_debug_error("msn", "Operation {%s} Failed, SOAP Fault was: %s\n", - msn_contact_operation_str(state->action), str); - g_free(str); - } - msn_callback_state_free(state); - } - - g_free(faultcode_str); -} - -static gboolean -msn_contact_request(MsnCallbackState *state) -{ - if (state->token == NULL) - state->token = xmlnode_get_child(state->body, - "Header/ABAuthHeader/TicketToken"); - /* delete old & replace with new token */ - xmlnode_free(state->token->child); - xmlnode_insert_data(state->token, - msn_nexus_get_token_str(state->session->nexus, MSN_AUTH_CONTACTS), -1); - msn_soap_message_send(state->session, - msn_soap_message_new(state->post_action, xmlnode_copy(state->body)), - MSN_CONTACT_SERVER, state->post_url, FALSE, - msn_contact_request_cb, state); - return FALSE; -} - static void msn_add_contact_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data) diff -r feea711ac242 -r 03541b3adb38 libpurple/protocols/msn/contact.h --- a/libpurple/protocols/msn/contact.h Sun Feb 01 18:00:05 2009 +0000 +++ b/libpurple/protocols/msn/contact.h Sun Feb 01 18:04:38 2009 +0000 @@ -52,7 +52,7 @@ ""\ ""\ "false"\ - "%s"\ + "EMPTY"\ ""\ ""\ ""\ @@ -94,7 +94,7 @@ ""\ ""\ "false"\ - "%s"\ + "EMPTY"\ ""\ ""\ ""\ @@ -135,7 +135,7 @@ ""\ ""\ "false"\ - "%s"\ + "EMPTY"\ ""\ ""\ ""\ @@ -619,6 +619,15 @@ MSN_UPDATE_INFO = 0x80 } MsnCallbackAction; +typedef enum +{ + MSN_PS_INITIAL, + MSN_PS_SAVE_CONTACT, + MSN_PS_PENDING_LIST, + MSN_PS_CONTACT_API, + MSN_PS_BLOCK_UNBLOCK +} MsnSoapPartnerScenario; + typedef struct _MsnCallbackState MsnCallbackState; struct _MsnCallbackState @@ -636,19 +645,12 @@ const gchar *post_action; const gchar *post_url; MsnSoapCallback cb; + /* For msn_get_contact_list only */ + MsnSoapPartnerScenario partner_scenario; }; typedef enum { - MSN_PS_INITIAL, - MSN_PS_SAVE_CONTACT, - MSN_PS_PENDING_LIST, - MSN_PS_CONTACT_API, - MSN_PS_BLOCK_UNBLOCK -} MsnSoapPartnerScenario; - -typedef enum -{ MSN_UPDATE_DISPLAY, /* Real display name */ MSN_UPDATE_ALIAS, /* Aliased display name */ MSN_UPDATE_COMMENT diff -r feea711ac242 -r 03541b3adb38 libpurple/protocols/msn/msg.c --- a/libpurple/protocols/msn/msg.c Sun Feb 01 18:00:05 2009 +0000 +++ b/libpurple/protocols/msn/msg.c Sun Feb 01 18:04:38 2009 +0000 @@ -23,6 +23,7 @@ */ #include "msn.h" #include "msg.h" +#include "msnutils.h" MsnMessage * msn_message_new(MsnMsgType type) @@ -804,3 +805,174 @@ g_string_free(str, TRUE); } + +/************************************************************************** + * Message Handlers + **************************************************************************/ +void +msn_plain_msg(MsnCmdProc *cmdproc, MsnMessage *msg) +{ + PurpleConnection *gc; + const char *body; + char *body_str; + char *body_enc; + char *body_final; + size_t body_len; + const char *passport; + const char *value; + + gc = cmdproc->session->account->gc; + + body = msn_message_get_bin_data(msg, &body_len); + body_str = g_strndup(body, body_len); + body_enc = g_markup_escape_text(body_str, -1); + g_free(body_str); + + passport = msg->remote_user; + + if (!strcmp(passport, "messenger@microsoft.com") && + strstr(body, "immediate security update")) + { + return; + } + +#if 0 + if ((value = msn_message_get_attr(msg, "User-Agent")) != NULL) + { + purple_debug_misc("msn", "User-Agent = '%s'\n", value); + } +#endif + + if ((value = msn_message_get_attr(msg, "X-MMS-IM-Format")) != NULL) + { + char *pre, *post; + + msn_parse_format(value, &pre, &post); + + body_final = g_strdup_printf("%s%s%s", pre ? pre : "", + body_enc ? body_enc : "", post ? post : ""); + + g_free(pre); + g_free(post); + g_free(body_enc); + } + else + { + body_final = body_enc; + } + + if (cmdproc->servconn->type == MSN_SERVCONN_SB) { + MsnSwitchBoard *swboard = cmdproc->data; + + swboard->flag |= MSN_SB_FLAG_IM; + + if (swboard->current_users > 1 || + ((swboard->conv != NULL) && + purple_conversation_get_type(swboard->conv) == PURPLE_CONV_TYPE_CHAT)) + { + /* If current_users is always ok as it should then there is no need to + * check if this is a chat. */ + if (swboard->current_users <= 1) + purple_debug_misc("msn", "plain_msg: current_users(%d)\n", + swboard->current_users); + + serv_got_chat_in(gc, swboard->chat_id, passport, 0, body_final, + time(NULL)); + if (swboard->conv == NULL) + { + swboard->conv = purple_find_chat(gc, swboard->chat_id); + swboard->flag |= MSN_SB_FLAG_IM; + } + } + else + { + serv_got_im(gc, passport, body_final, 0, time(NULL)); + if (swboard->conv == NULL) + { + swboard->conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, + passport, purple_connection_get_account(gc)); + swboard->flag |= MSN_SB_FLAG_IM; + } + } + + } else { + serv_got_im(gc, passport, body_final, 0, time(NULL)); + } + + g_free(body_final); +} + +void +msn_control_msg(MsnCmdProc *cmdproc, MsnMessage *msg) +{ + PurpleConnection *gc; + char *passport; + + gc = cmdproc->session->account->gc; + passport = msg->remote_user; + + if (msn_message_get_attr(msg, "TypingUser") == NULL) + return; + + if (cmdproc->servconn->type == MSN_SERVCONN_SB) { + MsnSwitchBoard *swboard = cmdproc->data; + + if (swboard->current_users == 1) + { + serv_got_typing(gc, passport, MSN_TYPING_RECV_TIMEOUT, + PURPLE_TYPING); + } + + } else { + serv_got_typing(gc, passport, MSN_TYPING_RECV_TIMEOUT, + PURPLE_TYPING); + } +} + +void +msn_datacast_msg(MsnCmdProc *cmdproc, MsnMessage *msg) +{ + GHashTable *body; + const char *id; + body = msn_message_get_hashtable_from_body(msg); + + id = g_hash_table_lookup(body, "ID"); + + if (!strcmp(id, "1")) { + /* Nudge */ + PurpleAccount *account; + const char *user; + + account = cmdproc->session->account; + user = msg->remote_user; + + if (cmdproc->servconn->type == MSN_SERVCONN_SB) { + MsnSwitchBoard *swboard = cmdproc->data; + if (swboard->current_users > 1 || + ((swboard->conv != NULL) && + purple_conversation_get_type(swboard->conv) == PURPLE_CONV_TYPE_CHAT)) + purple_prpl_got_attention_in_chat(account->gc, swboard->chat_id, user, MSN_NUDGE); + + else + purple_prpl_got_attention(account->gc, user, MSN_NUDGE); + + } else { + purple_prpl_got_attention(account->gc, user, MSN_NUDGE); + } + + } else if (!strcmp(id, "2")) { + /* Wink */ + + } else if (!strcmp(id, "3")) { + /* Voiceclip */ + + } else if (!strcmp(id, "4")) { + /* Action */ + + } else { + purple_debug_warning("msn", "Got unknown datacast with ID %s.\n", id); + } + + g_hash_table_destroy(body); +} + diff -r feea711ac242 -r 03541b3adb38 libpurple/protocols/msn/msg.h --- a/libpurple/protocols/msn/msg.h Sun Feb 01 18:00:05 2009 +0000 +++ b/libpurple/protocols/msn/msg.h Sun Feb 01 18:04:38 2009 +0000 @@ -339,4 +339,10 @@ char *msn_message_to_string(MsnMessage *msg); +void msn_plain_msg(MsnCmdProc *cmdproc, MsnMessage *msg); + +void msn_control_msg(MsnCmdProc *cmdproc, MsnMessage *msg); + +void msn_datacast_msg(MsnCmdProc *cmdproc, MsnMessage *msg); + #endif /* _MSN_MSG_H_ */ diff -r feea711ac242 -r 03541b3adb38 libpurple/protocols/msn/notification.c --- a/libpurple/protocols/msn/notification.c Sun Feb 01 18:00:05 2009 +0000 +++ b/libpurple/protocols/msn/notification.c Sun Feb 01 18:04:38 2009 +0000 @@ -1094,8 +1094,10 @@ return; } - serv_got_alias(gc, passport, friendly); - msn_user_set_friendly_name(user, friendly); + if (msn_user_set_friendly_name(user, friendly)) { + serv_got_alias(gc, passport, friendly); + msn_update_contact(session, passport, MSN_UPDATE_DISPLAY, friendly); + } g_free(friendly); msn_user_set_object(user, msnobj); @@ -1220,7 +1222,7 @@ MsnObject *msnobj; unsigned long clientid; int networkid; - const char *state, *passport, *friendly, *old_friendly; + const char *state, *passport, *friendly; session = cmdproc->session; account = session->account; @@ -1234,11 +1236,10 @@ user = msn_userlist_find_user(session->userlist, passport); if (user == NULL) return; - old_friendly = msn_user_get_friendly_name(user); - if (!old_friendly || (old_friendly && (!friendly || strcmp(old_friendly, friendly)))) + if (msn_user_set_friendly_name(user, friendly)) { serv_got_alias(gc, passport, friendly); - msn_user_set_friendly_name(user, friendly); + msn_update_contact(session, passport, MSN_UPDATE_DISPLAY, friendly); } if (cmd->param_count == 6) @@ -2095,6 +2096,13 @@ msn_table_add_msg_type(cbs_table, "application/x-msmsgssystemmessage", system_msg); + /* generic message handlers */ + msn_table_add_msg_type(cbs_table, "text/plain", + msn_plain_msg); + msn_table_add_msg_type(cbs_table, "text/x-msmsgscontrol", + msn_control_msg); + msn_table_add_msg_type(cbs_table, "text/x-msnmsgr-datacast", + msn_datacast_msg); } void diff -r feea711ac242 -r 03541b3adb38 libpurple/protocols/msn/switchboard.c --- a/libpurple/protocols/msn/switchboard.c Sun Feb 01 18:00:05 2009 +0000 +++ b/libpurple/protocols/msn/switchboard.c Sun Feb 01 18:04:38 2009 +0000 @@ -887,113 +887,6 @@ * Message Handlers **************************************************************************/ static void -plain_msg(MsnCmdProc *cmdproc, MsnMessage *msg) -{ - PurpleConnection *gc; - MsnSwitchBoard *swboard; - const char *body; - char *body_str; - char *body_enc; - char *body_final; - size_t body_len; - const char *passport; - const char *value; - - gc = cmdproc->session->account->gc; - swboard = cmdproc->data; - - body = msn_message_get_bin_data(msg, &body_len); - body_str = g_strndup(body, body_len); - body_enc = g_markup_escape_text(body_str, -1); - g_free(body_str); - - passport = msg->remote_user; - - if (!strcmp(passport, "messenger@microsoft.com") && - strstr(body, "immediate security update")) - { - return; - } - -#if 0 - if ((value = msn_message_get_attr(msg, "User-Agent")) != NULL) - { - purple_debug_misc("msn", "User-Agent = '%s'\n", value); - } -#endif - - if ((value = msn_message_get_attr(msg, "X-MMS-IM-Format")) != NULL) - { - char *pre, *post; - - msn_parse_format(value, &pre, &post); - - body_final = g_strdup_printf("%s%s%s", pre ? pre : "", - body_enc ? body_enc : "", post ? post : ""); - - g_free(pre); - g_free(post); - g_free(body_enc); - } - else - { - body_final = body_enc; - } - - swboard->flag |= MSN_SB_FLAG_IM; - - if (swboard->current_users > 1 || - ((swboard->conv != NULL) && - purple_conversation_get_type(swboard->conv) == PURPLE_CONV_TYPE_CHAT)) - { - /* If current_users is always ok as it should then there is no need to - * check if this is a chat. */ - if (swboard->current_users <= 1) - purple_debug_misc("msn", "plain_msg: current_users(%d)\n", - swboard->current_users); - - serv_got_chat_in(gc, swboard->chat_id, passport, 0, body_final, - time(NULL)); - if (swboard->conv == NULL) - { - swboard->conv = purple_find_chat(gc, swboard->chat_id); - swboard->flag |= MSN_SB_FLAG_IM; - } - } - else - { - serv_got_im(gc, passport, body_final, 0, time(NULL)); - if (swboard->conv == NULL) - { - swboard->conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, - passport, purple_connection_get_account(gc)); - swboard->flag |= MSN_SB_FLAG_IM; - } - } - - g_free(body_final); -} - -static void -control_msg(MsnCmdProc *cmdproc, MsnMessage *msg) -{ - PurpleConnection *gc; - MsnSwitchBoard *swboard; - char *passport; - - gc = cmdproc->session->account->gc; - swboard = cmdproc->data; - passport = msg->remote_user; - - if (swboard->current_users == 1 && - msn_message_get_attr(msg, "TypingUser") != NULL) - { - serv_got_typing(gc, passport, MSN_TYPING_RECV_TIMEOUT, - PURPLE_TYPING); - } -} - -static void clientcaps_msg(MsnCmdProc *cmdproc, MsnMessage *msg) { #if 0 @@ -1012,49 +905,6 @@ #endif } -static void -datacast_msg(MsnCmdProc *cmdproc, MsnMessage *msg) -{ - GHashTable *body; - const char *id; - body = msn_message_get_hashtable_from_body(msg); - - id = g_hash_table_lookup(body, "ID"); - - if (!strcmp(id, "1")) { - /* Nudge */ - MsnSwitchBoard *swboard; - PurpleAccount *account; - const char *user; - - swboard = cmdproc->data; - account = cmdproc->session->account; - user = msg->remote_user; - - if (swboard->current_users > 1 || - ((swboard->conv != NULL) && - purple_conversation_get_type(swboard->conv) == PURPLE_CONV_TYPE_CHAT)) - purple_prpl_got_attention_in_chat(account->gc, swboard->chat_id, user, MSN_NUDGE); - - else - purple_prpl_got_attention(account->gc, user, MSN_NUDGE); - - } else if (!strcmp(id, "2")) { - /* Wink */ - - } else if (!strcmp(id, "3")) { - /* Voiceclip */ - - } else if (!strcmp(id, "4")) { - /* Action */ - - } else { - purple_debug_warning("msn", "Got unknown datacast with ID %s.\n", id); - } - - g_hash_table_destroy(body); -} - /************************************************************************** * Connect stuff **************************************************************************/ @@ -1372,9 +1222,9 @@ /* Register the message type callbacks. */ msn_table_add_msg_type(cbs_table, "text/plain", - plain_msg); + msn_plain_msg); msn_table_add_msg_type(cbs_table, "text/x-msmsgscontrol", - control_msg); + msn_control_msg); msn_table_add_msg_type(cbs_table, "text/x-clientcaps", clientcaps_msg); msn_table_add_msg_type(cbs_table, "text/x-clientinfo", @@ -1384,9 +1234,9 @@ msn_table_add_msg_type(cbs_table, "text/x-mms-emoticon", msn_emoticon_msg); msn_table_add_msg_type(cbs_table, "text/x-mms-animemoticon", - msn_emoticon_msg); + msn_emoticon_msg); msn_table_add_msg_type(cbs_table, "text/x-msnmsgr-datacast", - datacast_msg); + msn_datacast_msg); #if 0 msn_table_add_msg_type(cbs_table, "text/x-msmmsginvite", msn_invite_msg); diff -r feea711ac242 -r 03541b3adb38 libpurple/protocols/msn/user.c --- a/libpurple/protocols/msn/user.c Sun Feb 01 18:00:05 2009 +0000 +++ b/libpurple/protocols/msn/user.c Sun Feb 01 18:04:38 2009 +0000 @@ -177,13 +177,18 @@ user->passport = g_strdup(passport); } -void +gboolean msn_user_set_friendly_name(MsnUser *user, const char *name) { g_return_if_fail(user != NULL); + if (user->friendly_name && name && !strcmp(user->friendly_name, name)) + return FALSE; + g_free(user->friendly_name); user->friendly_name = g_strdup(name); + + return TRUE; } void diff -r feea711ac242 -r 03541b3adb38 libpurple/protocols/msn/user.h --- a/libpurple/protocols/msn/user.h Sun Feb 01 18:00:05 2009 +0000 +++ b/libpurple/protocols/msn/user.h Sun Feb 01 18:04:38 2009 +0000 @@ -178,8 +178,10 @@ * * @param user The user. * @param name The friendly name. + * + * @returns TRUE is name actually changed, FALSE otherwise. */ -void msn_user_set_friendly_name(MsnUser *user, const char *name); +gboolean msn_user_set_friendly_name(MsnUser *user, const char *name); /** * Sets the buddy icon for a local user. diff -r feea711ac242 -r 03541b3adb38 libpurple/protocols/silc/silc.c --- a/libpurple/protocols/silc/silc.c Sun Feb 01 18:00:05 2009 +0000 +++ b/libpurple/protocols/silc/silc.c Sun Feb 01 18:04:38 2009 +0000 @@ -1357,6 +1357,7 @@ char tmp[256]; SilcClientEntry client_entry; SilcDList list; + gboolean free_list = FALSE; convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, im->nick, sg->account); @@ -1373,6 +1374,8 @@ im->nick, FALSE); if (!clients) goto err; + + free_list = TRUE; } silc_dlist_start(clients); @@ -1413,6 +1416,9 @@ purple_conversation_write(convo, NULL, tmp, PURPLE_MESSAGE_SYSTEM, time(NULL)); out: + if (free_list) { + silc_client_list_free(client, conn, clients); + } g_free(im->nick); g_free(im->message); silc_free(im); diff -r feea711ac242 -r 03541b3adb38 pidgin/plugins/win32/winprefs/winprefs.c --- a/pidgin/plugins/win32/winprefs/winprefs.c Sun Feb 01 18:00:05 2009 +0000 +++ b/pidgin/plugins/win32/winprefs/winprefs.c Sun Feb 01 18:04:38 2009 +0000 @@ -55,9 +55,8 @@ static const char *PREF_DBLIST_HEIGHT = "/plugins/gtk/win32/winprefs/dblist_height"; static const char *PREF_DBLIST_SIDE = "/plugins/gtk/win32/winprefs/dblist_side"; static const char *PREF_BLIST_ON_TOP = "/plugins/gtk/win32/winprefs/blist_on_top"; +/* Deprecated */ static const char *PREF_CHAT_BLINK = "/plugins/gtk/win32/winprefs/chat_blink"; - -/* Deprecated */ static const char *PREF_DBLIST_ON_TOP = "/plugins/gtk/win32/winprefs/dblist_on_top"; static PurplePlugin *handle = NULL; @@ -229,17 +228,6 @@ blist_set_ontop(FALSE); } -static gboolean -winpidgin_conv_chat_blink(PurpleAccount *account, const char *who, char **message, - PurpleConversation *conv, PurpleMessageFlags flags, void *data) -{ - if(purple_prefs_get_bool(PREF_CHAT_BLINK)) - winpidgin_conv_blink(conv, flags); - - return FALSE; -} - - /* * EXPORTED FUNCTIONS */ @@ -258,10 +246,6 @@ purple_signal_connect(pidgin_blist_get_handle(), "gtkblist-created", plugin, PURPLE_CALLBACK(blist_create_cb), NULL); - purple_signal_connect(pidgin_conversations_get_handle(), - "displaying-chat-msg", plugin, PURPLE_CALLBACK(winpidgin_conv_chat_blink), - NULL); - purple_signal_connect((void*)purple_get_core(), "quitting", plugin, PURPLE_CALLBACK(purple_quit_cb), NULL); @@ -336,11 +320,6 @@ _("Only when docked"), BLIST_TOP_DOCKED, NULL); - /* Conversations */ - vbox = pidgin_make_frame(ret, _("Conversations")); - pidgin_prefs_checkbox(_("_Flash window when chat messages are received"), - PREF_CHAT_BLINK, vbox); - gtk_widget_show_all(ret); return ret; } @@ -399,7 +378,6 @@ purple_prefs_add_bool(PREF_DBLIST_DOCKED, FALSE); purple_prefs_add_int(PREF_DBLIST_HEIGHT, 0); purple_prefs_add_int(PREF_DBLIST_SIDE, 0); - purple_prefs_add_bool(PREF_CHAT_BLINK, FALSE); /* Convert old preferences */ if(purple_prefs_exists(PREF_DBLIST_ON_TOP)) { @@ -413,6 +391,7 @@ purple_prefs_add_int(PREF_BLIST_ON_TOP, blist_top); } else purple_prefs_add_int(PREF_BLIST_ON_TOP, BLIST_TOP_NEVER); + purple_prefs_remove(PREF_CHAT_BLINK); } PURPLE_INIT_PLUGIN(winprefs, init_plugin, info)