From 21029d0fe2b7b11512d2cc67495d590e9df53f85 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 20 Mar 2010 13:56:27 +0000 Subject: Add MSNP11 challenge code which I'll need for doing this SOAP stuff. --- protocols/msn/msn.h | 7 +++- protocols/msn/msn_util.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 101 insertions(+), 2 deletions(-) diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h index 84914bc3..4799e226 100644 --- a/protocols/msn/msn.h +++ b/protocols/msn/msn.h @@ -1,7 +1,7 @@ /********************************************************************\ * BitlBee -- An IRC to other IM-networks gateway * * * - * Copyright 2002-2004 Wilmer van der Gaast and others * + * Copyright 2002-2010 Wilmer van der Gaast and others * \********************************************************************/ /* MSN module */ @@ -40,6 +40,10 @@ #define QRY_NAME "msmsgs@msnmsgr.com" #define QRY_CODE "Q1P7W2E4J9R8U3S5" +/* This should be MSN Messenger 7.0.0813 */ +#define MSNP11_PROD_KEY "CFHUR$52U_{VIX5T" +#define MSNP11_PROD_ID "PROD0101{0RM?UBW" + #define MSN_SB_NEW -24062002 #define MSN_MESSAGE_HEADERS "MIME-Version: 1.0\r\n" \ @@ -160,6 +164,7 @@ char **msn_linesplit( char *line ); int msn_handler( struct msn_handler_data *h ); char *msn_http_encode( const char *input ); void msn_msgq_purge( struct im_connection *ic, GSList **list ); +char *msn_p11_challenge( char *challenge ); /* tables.c */ const struct msn_away_state *msn_away_state_by_number( int number ); diff --git a/protocols/msn/msn_util.c b/protocols/msn/msn_util.c index 668a8b8a..59363439 100644 --- a/protocols/msn/msn_util.c +++ b/protocols/msn/msn_util.c @@ -1,7 +1,7 @@ /********************************************************************\ * BitlBee -- An IRC to other IM-networks gateway * * * - * Copyright 2002-2004 Wilmer van der Gaast and others * + * Copyright 2002-2010 Wilmer van der Gaast and others * \********************************************************************/ /* MSN module - Miscellaneous utilities */ @@ -25,6 +25,7 @@ #include "nogaim.h" #include "msn.h" +#include "md5.h" #include int msn_write( struct im_connection *ic, char *s, int len ) @@ -376,3 +377,96 @@ void msn_msgq_purge( struct im_connection *ic, GSList **list ) imcb_log( ic, "%s", ret->str ); g_string_free( ret, TRUE ); } + +unsigned int little_endian( unsigned int dw ) +{ +#if defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN + return dw; +#else + /* We're still not sure if this machine is big endian since the + constants above are not that portable. Don't swap bytes, just + force-compose a 32-bit little endian integer. */ + unsigned int ret = 0, i; + char *dst = (char*) (&ret + 1); + + for (i = 0; i < 4; i ++) + { + *(--dst) = dw >> 24; + dw <<= 8; + } + + return ret; +#endif +} + +/* Copied and heavily modified from http://tmsnc.sourceforge.net/chl.c */ + +char *msn_p11_challenge( char *challenge ) +{ + char *output, buf[256]; + md5_state_t md5c; + unsigned char md5Hash[16], *newHash; + unsigned int *md5Parts, *chlStringParts, newHashParts[5]; + long long nHigh = 0, nLow = 0; + int i, n; + + /* Create the MD5 hash */ + md5_init(&md5c); + md5_append(&md5c, (unsigned char*) challenge, strlen(challenge)); + md5_append(&md5c, (unsigned char*) MSNP11_PROD_KEY, strlen(MSNP11_PROD_KEY)); + md5_finish(&md5c, md5Hash); + + /* Split it into four integers */ + md5Parts = (unsigned int *)md5Hash; + for (i = 0; i < 4; i ++) + { + md5Parts[i] = little_endian(md5Parts[i]); + + /* & each integer with 0x7FFFFFFF */ + /* and save one unmodified array for later */ + newHashParts[i] = md5Parts[i]; + md5Parts[i] &= 0x7FFFFFFF; + } + + /* make a new string and pad with '0' */ + n = g_snprintf(buf, sizeof(buf)-5, "%s%s00000000", challenge, MSNP11_PROD_ID); + /* truncate at an 8-byte boundary */ + buf[n&=~7] = '\0'; + + /* split into integers */ + chlStringParts = (unsigned int *)buf; + + /* this is magic */ + for (i = 0; i < (n / 4) - 1; i += 2) + { + long long temp; + + chlStringParts[i] = little_endian(chlStringParts[i]); + chlStringParts[i+1] = little_endian(chlStringParts[i+1]); + + temp = (md5Parts[0] * (((0x0E79A9C1 * (long long)chlStringParts[i]) % 0x7FFFFFFF)+nHigh) + md5Parts[1])%0x7FFFFFFF; + nHigh = (md5Parts[2] * (((long long)chlStringParts[i+1]+temp) % 0x7FFFFFFF) + md5Parts[3]) % 0x7FFFFFFF; + nLow = nLow + nHigh + temp; + } + nHigh = (nHigh+md5Parts[1]) % 0x7FFFFFFF; + nLow = (nLow+md5Parts[3]) % 0x7FFFFFFF; + + newHashParts[0] ^= nHigh; + newHashParts[1] ^= nLow; + newHashParts[2] ^= nHigh; + newHashParts[3] ^= nLow; + + /* swap more bytes if big endian */ + for (i = 0; i < 4; i ++) + newHashParts[i] = little_endian(newHashParts[i]); + + /* make a string of the parts */ + newHash = (unsigned char *)newHashParts; + + /* convert to hexadecimal */ + output = g_new(char, 33); + for (i = 0; i < 16; i ++) + sprintf(output + i * 2, "%02x", newHash[i]); + + return output; +} -- cgit v1.2.3 From e5a8118236442d51eb202a8bdebe5866449554e4 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 20 Mar 2010 17:27:23 +0000 Subject: Added soap.c with a fairly reusable SOAP framework and simple code for sending offline messages. It works somewhat, just that Pidgin shows the messages as empty. :-( --- protocols/msn/Makefile | 2 +- protocols/msn/msn.c | 2 + protocols/msn/msn.h | 9 ++- protocols/msn/ns.c | 2 + protocols/msn/sb.c | 12 +++ protocols/msn/soap.c | 216 +++++++++++++++++++++++++++++++++++++++++++++++++ protocols/msn/soap.h | 85 +++++++++++++++++++ 7 files changed, 325 insertions(+), 3 deletions(-) create mode 100644 protocols/msn/soap.c create mode 100644 protocols/msn/soap.h diff --git a/protocols/msn/Makefile b/protocols/msn/Makefile index 6a588613..911f47bd 100644 --- a/protocols/msn/Makefile +++ b/protocols/msn/Makefile @@ -9,7 +9,7 @@ -include ../../Makefile.settings # [SH] Program variables -objects = msn.o msn_util.o ns.o passport.o sb.o tables.o +objects = msn.o msn_util.o ns.o passport.o sb.o soap.o tables.o CFLAGS += -Wall LFLAGS += -r diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c index 8930847d..49ce9298 100644 --- a/protocols/msn/msn.c +++ b/protocols/msn/msn.c @@ -99,6 +99,8 @@ static void msn_logout( struct im_connection *ic ) g_free( md->grouplist[--md->groupcount] ); g_free( md->grouplist ); + g_free( md->passport_token ); + g_free( md ); } diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h index 4799e226..d57ff796 100644 --- a/protocols/msn/msn.h +++ b/protocols/msn/msn.h @@ -41,8 +41,11 @@ #define QRY_CODE "Q1P7W2E4J9R8U3S5" /* This should be MSN Messenger 7.0.0813 */ -#define MSNP11_PROD_KEY "CFHUR$52U_{VIX5T" -#define MSNP11_PROD_ID "PROD0101{0RM?UBW" +//#define MSNP11_PROD_KEY "CFHUR$52U_{VIX5T" +//#define MSNP11_PROD_ID "PROD0101{0RM?UBW" + +#define MSNP11_PROD_KEY "O4BG@C7BWLYQX?5G" +#define MSNP11_PROD_ID "PROD01065C%ZFN6F" #define MSN_SB_NEW -24062002 @@ -67,6 +70,8 @@ struct msn_data struct msn_handler_data *handler; int trId; + char *passport_token; + char *lock_key; GSList *msgq; GSList *switchboards; diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index d78d753a..f9c8ab29 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -736,6 +736,8 @@ static void msn_auth_got_passport_token( struct msn_auth_data *mad ) { char buf[1024]; + md->passport_token = g_strdup( mad->token ); + g_snprintf( buf, sizeof( buf ), "USR %d TWN S %s\r\n", ++md->trId, mad->token ); msn_write( ic, buf, strlen( buf ) ); } diff --git a/protocols/msn/sb.c b/protocols/msn/sb.c index e9526234..920e7f61 100644 --- a/protocols/msn/sb.c +++ b/protocols/msn/sb.c @@ -28,6 +28,7 @@ #include "msn.h" #include "passport.h" #include "md5.h" +#include "soap.h" static gboolean msn_sb_callback( gpointer data, gint source, b_input_condition cond ); static int msn_sb_command( gpointer data, char **cmd, int num_parts ); @@ -605,6 +606,17 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts ) int num = atoi( cmd[0] ); const struct msn_status_code *err = msn_status_by_number( num ); + if( num == 217 ) + { + GSList *l; + + for( l = sb->msgq; l; l = l->next ) + { + struct msn_message *m = l->data; + msn_soap_oim_send( ic, m->who, m->text ); + } + } + imcb_error( ic, "Error reported by switchboard server: %s", err->text ); if( err->flags & STATUS_SB_FATAL ) diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c new file mode 100644 index 00000000..d3a022ec --- /dev/null +++ b/protocols/msn/soap.c @@ -0,0 +1,216 @@ +/** soap.c + * + * SOAP-related functions. Some manager at Microsoft apparently thought + * MSNP wasn't XMLy enough so someone stepped up and changed that. This + * is the result. + * + * Copyright (C) 2010 Wilmer van der Gaast + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that is will be useful, + * bit WITHOU ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "http_client.h" +#include "soap.h" +#include "msn.h" +#include "bitlbee.h" +#include "url.h" +#include "misc.h" +#include "base64.h" +#include "xmltree.h" +#include +#include + +typedef enum +{ + MSN_SOAP_OK, + MSN_SOAP_RETRY, + MSN_SOAP_ABORT, +} msn_soap_result_t; + +struct msn_soap_req_data; + +typedef int (*msn_soap_func) ( struct msn_soap_req_data * ); + +struct msn_soap_req_data +{ + void *data; + struct im_connection *ic; + int ttl; + + char *url, *action, *payload; + struct http_request *http_req; + + const struct xt_handler_entry *xml_parser; + msn_soap_func build_request, handle_response, free_data; +}; + +struct msn_soap_oim_send_data +{ + char *to; + char *msg; + int number; + int need_retry; +}; + +static int msn_soap_send_request( struct msn_soap_req_data *req ); + +static int msn_soap_start( struct im_connection *ic, + void *data, + msn_soap_func build_request, + const struct xt_handler_entry *xml_parser, + msn_soap_func handle_response, + msn_soap_func free_data ) +{ + struct msn_soap_req_data *req = g_new0( struct msn_soap_req_data, 1 ); + + req->ic = ic; + req->data = data; + req->xml_parser = xml_parser; + req->build_request = build_request; + req->handle_response = handle_response; + req->free_data = free_data; + req->ttl = 3; + + return msn_soap_send_request( req ); +} + +static void msn_soap_handle_response( struct http_request *http_req ); + +static int msn_soap_send_request( struct msn_soap_req_data *soap_req ) +{ + char *http_req; + url_t url; + + soap_req->build_request( soap_req ); + + url_set( &url, soap_req->url ); + http_req = g_strdup_printf( SOAP_HTTP_REQUEST, url.file, url.host, + soap_req->action, strlen( soap_req->payload ), soap_req->payload ); + + soap_req->http_req = http_dorequest( url.host, url.port, url.proto == PROTO_HTTPS, + http_req, msn_soap_handle_response, soap_req ); + + return soap_req->http_req != NULL; +} + +static void msn_soap_handle_response( struct http_request *http_req ) +{ + struct msn_soap_req_data *soap_req = http_req->data; + int st; + + if( http_req->body_size > 0 ) + { + struct xt_parser *parser; + + parser = xt_new( soap_req->xml_parser, soap_req ); + xt_feed( parser, http_req->reply_body, http_req->body_size ); + xt_handle( parser, NULL, -1 ); + xt_free( parser ); + } + + st = soap_req->handle_response( soap_req ); + + if( st == MSN_SOAP_RETRY && --soap_req->ttl ) + msn_soap_send_request( soap_req ); + else + { + soap_req->free_data( soap_req ); + g_free( soap_req->url ); + g_free( soap_req->action ); + g_free( soap_req->payload ); + g_free( soap_req ); + } +} + +static int msn_soap_oim_build_request( struct msn_soap_req_data *soap_req ) +{ + struct msn_soap_oim_send_data *oim = soap_req->data; + struct im_connection *ic = soap_req->ic; + struct msn_data *md = ic->proto_data; + char *display_name_b64; + + display_name_b64 = tobase64( ic->displayname ); + + soap_req->url = g_strdup( SOAP_OIM_SEND_URL ); + soap_req->action = g_strdup( SOAP_OIM_ACTION_URL ); + soap_req->payload = g_markup_printf_escaped( SOAP_OIM_SEND_PAYLOAD, + ic->acc->user, display_name_b64, oim->to, md->passport_token, + MSNP11_PROD_ID, md->lock_key ? : "", oim->number, oim->number, oim->msg ); + + g_free( display_name_b64 ); + + return 1; +} + +static xt_status msn_soap_oim_send_challenge( struct xt_node *node, gpointer data ) +{ + struct msn_soap_req_data *soap_req = data; + struct msn_soap_oim_send_data *oim = soap_req->data; + struct im_connection *ic = soap_req->ic; + struct msn_data *md = ic->proto_data; + + g_free( md->lock_key ); + md->lock_key = msn_p11_challenge( node->text ); + + oim->need_retry = 1; + + return XT_HANDLED; +} + +static const struct xt_handler_entry msn_soap_oim_send_parser[] = { + { "LockKeyChallenge", "detail", msn_soap_oim_send_challenge }, + { NULL, NULL, NULL } +}; + +static int msn_soap_oim_handle_response( struct msn_soap_req_data *soap_req ) +{ + struct msn_soap_oim_send_data *oim = soap_req->data; + + if( soap_req->http_req->status_code == 500 && oim->need_retry ) + { + oim->need_retry = 0; + return MSN_SOAP_RETRY; + } + else if( soap_req->http_req->status_code == 200 ) + return MSN_SOAP_OK; + else + return MSN_SOAP_ABORT; +} + +static int msn_soap_oim_free_data( struct msn_soap_req_data *soap_req ) +{ + struct msn_soap_oim_send_data *oim = soap_req->data; + + g_free( oim->to ); + g_free( oim->msg ); + g_free( oim ); + + return 0; +} + +int msn_soap_oim_send( struct im_connection *ic, const char *to, const char *msg ) +{ + struct msn_soap_oim_send_data *data; + + data = g_new0( struct msn_soap_oim_send_data, 1 ); + data->to = g_strdup( to ); + data->msg = tobase64( msg ); + data->number = 1; + + return msn_soap_start( ic, data, msn_soap_oim_build_request, + msn_soap_oim_send_parser, + msn_soap_oim_handle_response, + msn_soap_oim_free_data ); +} diff --git a/protocols/msn/soap.h b/protocols/msn/soap.h new file mode 100644 index 00000000..4e7d6627 --- /dev/null +++ b/protocols/msn/soap.h @@ -0,0 +1,85 @@ +/* soap.h + * + * SOAP-related functions. Some manager at Microsoft apparently thought + * MSNP wasn't XMLy enough so someone stepped up and changed that. This + * is the result. + * + * Copyright (C) 2010 Wilmer van der Gaast + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that is will be useful, + * bit WITHOU ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Thanks to http://msnpiki.msnfanatic.com/ for lots of info on this! */ + +#ifndef __SOAP_H__ +#define __SOAP_H__ + +#include +#include +#include +#include +#ifndef _WIN32 +#include +#include +#include +#include +#endif +#include "nogaim.h" + + +#define SOAP_HTTP_REQUEST \ +"POST %s HTTP/1.0\r\n" \ +"Host: %s\r\n" \ +"Accept: */*\r\n" \ +"SOAPAction: \"%s\"\r\n" \ +"User-Agent: BitlBee " BITLBEE_VERSION "\r\n" \ +"Content-Type: text/xml; charset=utf-8\r\n" \ +"Content-Length: %d\r\n" \ +"Cache-Control: no-cache\r\n" \ +"\r\n" \ +"%s" + + +#define SOAP_OIM_SEND_URL "https://ows.messenger.msn.com/OimWS/oim.asmx" +#define SOAP_OIM_ACTION_URL "http://messenger.msn.com/ws/2004/09/oim/Store" + +#define SOAP_OIM_SEND_PAYLOAD \ +"" \ +"" \ +"" \ + "" \ + "" \ + "" \ + "" \ + "http://messenger.msn.com" \ + "%d" \ + "" \ +"" \ +"" \ + "text" \ + "MIME-Version: 1.0\r\n" \ + "Content-Type: text/plain; charset=UTF-8\r\n" \ + "Content-Transfer-Encoding: base64\r\n" \ + "X-OIM-Message-Type: OfflineMessage\r\n" \ + "X-OIM-Run-Id: {89527393-8723-4F4F-8005-287532973298}\r\n" \ + "X-OIM-Sequence-Num: %d\r\n" \ + "\r\n" \ + "%s" \ + "" \ +"" \ +"" + +int msn_soap_oim_send( struct im_connection *ic, const char *to, const char *msg ); + +#endif /* __SOAP_H__ */ -- cgit v1.2.3 From ffb6dea650db7671d2414b1a9541cf0baba8ff11 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 20 Mar 2010 21:58:04 +0000 Subject: Killing some memory leaks. --- protocols/msn/msn.c | 1 + protocols/msn/soap.c | 10 +++++++--- protocols/msn/soap.h | 3 ++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c index 49ce9298..4d859346 100644 --- a/protocols/msn/msn.c +++ b/protocols/msn/msn.c @@ -100,6 +100,7 @@ static void msn_logout( struct im_connection *ic ) g_free( md->grouplist ); g_free( md->passport_token ); + g_free( md->lock_key ); g_free( md ); } diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c index d3a022ec..f329cea9 100644 --- a/protocols/msn/soap.c +++ b/protocols/msn/soap.c @@ -102,6 +102,8 @@ static int msn_soap_send_request( struct msn_soap_req_data *soap_req ) soap_req->http_req = http_dorequest( url.host, url.port, url.proto == PROTO_HTTPS, http_req, msn_soap_handle_response, soap_req ); + g_free( http_req ); + return soap_req->http_req != NULL; } @@ -122,14 +124,16 @@ static void msn_soap_handle_response( struct http_request *http_req ) st = soap_req->handle_response( soap_req ); + g_free( soap_req->url ); + g_free( soap_req->action ); + g_free( soap_req->payload ); + soap_req->url = soap_req->action = soap_req->payload = NULL; + if( st == MSN_SOAP_RETRY && --soap_req->ttl ) msn_soap_send_request( soap_req ); else { soap_req->free_data( soap_req ); - g_free( soap_req->url ); - g_free( soap_req->action ); - g_free( soap_req->payload ); g_free( soap_req ); } } diff --git a/protocols/msn/soap.h b/protocols/msn/soap.h index 4e7d6627..687cc282 100644 --- a/protocols/msn/soap.h +++ b/protocols/msn/soap.h @@ -68,7 +68,8 @@ "" \ "" \ "text" \ - "MIME-Version: 1.0\r\n" \ + "" \ + "MIME-Version: 1.0\r\n" \ "Content-Type: text/plain; charset=UTF-8\r\n" \ "Content-Transfer-Encoding: base64\r\n" \ "X-OIM-Message-Type: OfflineMessage\r\n" \ -- cgit v1.2.3 From bc090f0c3bc243de277a8e04f906384838d95e35 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 20 Mar 2010 22:42:59 +0000 Subject: Error reporting and added a msgq_send function. Need to put some more intelligence into it later. --- protocols/msn/sb.c | 16 +++++----------- protocols/msn/soap.c | 54 +++++++++++++++++++++++++++++++++++++++++++--------- protocols/msn/soap.h | 1 + 3 files changed, 51 insertions(+), 20 deletions(-) diff --git a/protocols/msn/sb.c b/protocols/msn/sb.c index 920e7f61..461bd483 100644 --- a/protocols/msn/sb.c +++ b/protocols/msn/sb.c @@ -606,18 +606,12 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts ) int num = atoi( cmd[0] ); const struct msn_status_code *err = msn_status_by_number( num ); + /* If the person is offline, send an offline message instead, + and don't report an error. */ if( num == 217 ) - { - GSList *l; - - for( l = sb->msgq; l; l = l->next ) - { - struct msn_message *m = l->data; - msn_soap_oim_send( ic, m->who, m->text ); - } - } - - imcb_error( ic, "Error reported by switchboard server: %s", err->text ); + msn_soap_oim_send_queue( ic, &sb->msgq ); + else + imcb_error( ic, "Error reported by switchboard server: %s", err->text ); if( err->flags & STATUS_SB_FATAL ) { diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c index f329cea9..82ecfea2 100644 --- a/protocols/msn/soap.c +++ b/protocols/msn/soap.c @@ -56,14 +56,6 @@ struct msn_soap_req_data msn_soap_func build_request, handle_response, free_data; }; -struct msn_soap_oim_send_data -{ - char *to; - char *msg; - int number; - int need_retry; -}; - static int msn_soap_send_request( struct msn_soap_req_data *req ); static int msn_soap_start( struct im_connection *ic, @@ -138,6 +130,17 @@ static void msn_soap_handle_response( struct http_request *http_req ) } } + +/* oim_send: Sending offline messages */ + +struct msn_soap_oim_send_data +{ + char *to; + char *msg; + int number; + int need_retry; +}; + static int msn_soap_oim_build_request( struct msn_soap_req_data *soap_req ) { struct msn_soap_oim_send_data *oim = soap_req->data; @@ -182,15 +185,21 @@ static int msn_soap_oim_handle_response( struct msn_soap_req_data *soap_req ) { struct msn_soap_oim_send_data *oim = soap_req->data; - if( soap_req->http_req->status_code == 500 && oim->need_retry ) + if( soap_req->http_req->status_code == 500 && oim->need_retry && soap_req->ttl > 0 ) { oim->need_retry = 0; return MSN_SOAP_RETRY; } else if( soap_req->http_req->status_code == 200 ) + { + imcb_log( soap_req->ic, "Offline message successfully delivered to %s", oim->to ); return MSN_SOAP_OK; + } else + { + imcb_log( soap_req->ic, "Failed to deliver offline message to %s:\n%s", oim->to, oim->msg ); return MSN_SOAP_ABORT; + } } static int msn_soap_oim_free_data( struct msn_soap_req_data *soap_req ) @@ -218,3 +227,30 @@ int msn_soap_oim_send( struct im_connection *ic, const char *to, const char *msg msn_soap_oim_handle_response, msn_soap_oim_free_data ); } + +int msn_soap_oim_send_queue( struct im_connection *ic, GSList **msgq ) +{ + GSList *l; + char *n = NULL; + + for( l = *msgq; l; l = l->next ) + { + struct msn_message *m = l->data; + + if( n == NULL ) + n = m->who; + if( strcmp( n, m->who ) == 0 ) + msn_soap_oim_send( ic, m->who, m->text ); + } + + while( *msgq != NULL ) + { + struct msn_message *m = (*msgq)->data; + + g_free( m->who ); + g_free( m->text ); + g_free( m ); + + *msgq = g_slist_remove( *msgq, m ); + } +} diff --git a/protocols/msn/soap.h b/protocols/msn/soap.h index 687cc282..3db2d59d 100644 --- a/protocols/msn/soap.h +++ b/protocols/msn/soap.h @@ -82,5 +82,6 @@ "" int msn_soap_oim_send( struct im_connection *ic, const char *to, const char *msg ); +int msn_soap_oim_send_queue( struct im_connection *ic, GSList **msgq ); #endif /* __SOAP_H__ */ -- cgit v1.2.3 From ee6cc946dc4ee82cb641df94a6ba101e99253af2 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 8 Aug 2010 16:25:13 +0100 Subject: Use local memory in http_encode() instead of malloc(). --- lib/misc.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/misc.c b/lib/misc.c index fe2ff17c..04418524 100644 --- a/lib/misc.c +++ b/lib/misc.c @@ -263,11 +263,10 @@ void http_decode( char *s ) /* This fuction is safe, but make sure you call it safely as well! */ void http_encode( char *s ) { - char *t; + char t[strlen(s)+1]; int i, j; - t = g_strdup( s ); - + strcpy( t, s ); for( i = j = 0; t[i]; i ++, j ++ ) { /* if( t[i] <= ' ' || ((unsigned char *)t)[i] >= 128 || t[i] == '%' ) */ @@ -282,8 +281,6 @@ void http_encode( char *s ) } } s[j] = 0; - - g_free( t ); } /* Strip newlines from a string. Modifies the string passed to it. */ -- cgit v1.2.3 From 5fecede7db56a41cf9d6ecb2b821f5a833ce0f59 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 8 Aug 2010 18:29:43 +0100 Subject: Enough changes to successfully login up to (but not including) fetching the contact list. --- protocols/msn/ns.c | 12 +++++++++--- protocols/msn/sb.c | 1 + protocols/msn/soap.c | 3 ++- protocols/msn/soap.h | 2 +- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index 40c4cdec..897650a6 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -72,7 +72,7 @@ gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ) md->handler->fd = md->fd; md->handler->rxq = g_new0( char, 1 ); - g_snprintf( s, sizeof( s ), "VER %d MSNP8 CVR0\r\n", ++md->trId ); + g_snprintf( s, sizeof( s ), "VER %d MSNP14 CVR0\r\n", ++md->trId ); if( msn_write( ic, s, strlen( s ) ) ) { ic->inpa = b_input_add( md->fd, B_EV_IO_READ, msn_ns_callback, ic ); @@ -112,7 +112,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( strcmp( cmd[0], "VER" ) == 0 ) { - if( cmd[2] && strncmp( cmd[2], "MSNP8", 5 ) != 0 ) + if( cmd[2] && strncmp( cmd[2], "MSNP14", 5 ) != 0 ) { imcb_error( ic, "Unsupported protocol" ); imc_logout( ic, FALSE ); @@ -229,7 +229,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) return( 0 ); } } - else if( num_parts >= 7 && strcmp( cmd[2], "OK" ) == 0 ) + else if( strcmp( cmd[2], "OK" ) == 0 ) { if( num_parts == 7 ) msn_ns_got_display_name( ic, cmd[4] ); @@ -655,6 +655,12 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) } } } + else if( strcmp( cmd[0], "GCF" ) == 0 ) + { + /* Coming up is cmd[2] bytes of stuff we're supposed to + censore. Meh. */ + md->handler->msglen = atoi( cmd[2] ); + } else if( isdigit( cmd[0][0] ) ) { int num = atoi( cmd[0] ); diff --git a/protocols/msn/sb.c b/protocols/msn/sb.c index 10425708..1eb919e3 100644 --- a/protocols/msn/sb.c +++ b/protocols/msn/sb.c @@ -29,6 +29,7 @@ #include "passport.h" #include "md5.h" #include "soap.h" +#include "invitation.h" static gboolean msn_sb_callback( gpointer data, gint source, b_input_condition cond ); static int msn_sb_command( gpointer data, char **cmd, int num_parts ); diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c index 82ecfea2..4d623a9d 100644 --- a/protocols/msn/soap.c +++ b/protocols/msn/soap.c @@ -154,7 +154,8 @@ static int msn_soap_oim_build_request( struct msn_soap_req_data *soap_req ) soap_req->action = g_strdup( SOAP_OIM_ACTION_URL ); soap_req->payload = g_markup_printf_escaped( SOAP_OIM_SEND_PAYLOAD, ic->acc->user, display_name_b64, oim->to, md->passport_token, - MSNP11_PROD_ID, md->lock_key ? : "", oim->number, oim->number, oim->msg ); + MSNP11_PROD_ID, md->lock_key ? md->lock_key : "", + oim->number, oim->number, oim->msg ); g_free( display_name_b64 ); diff --git a/protocols/msn/soap.h b/protocols/msn/soap.h index 3db2d59d..307ac1bc 100644 --- a/protocols/msn/soap.h +++ b/protocols/msn/soap.h @@ -73,7 +73,7 @@ "Content-Type: text/plain; charset=UTF-8\r\n" \ "Content-Transfer-Encoding: base64\r\n" \ "X-OIM-Message-Type: OfflineMessage\r\n" \ - "X-OIM-Run-Id: {89527393-8723-4F4F-8005-287532973298}\r\n" \ + "X-OIM-Run-Id: {F9A6C9DD-0D94-4E85-9CC6-F9D118CC1CAF}\r\n" \ "X-OIM-Sequence-Num: %d\r\n" \ "\r\n" \ "%s" \ -- cgit v1.2.3 From 7db65b7df08a3c7cab28e065b2ffa3d9941ceccb Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 9 Aug 2010 20:04:55 +0100 Subject: Not working yet, but some code for fetching the membership list. Apparently an upgrade to MSNP15 is needed. Oh well. --- protocols/msn/ns.c | 4 ++-- protocols/msn/soap.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++-- protocols/msn/soap.h | 29 ++++++++++++++++++++++++++- 3 files changed, 84 insertions(+), 5 deletions(-) diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index 897650a6..8236b731 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -28,6 +28,7 @@ #include "msn.h" #include "passport.h" #include "md5.h" +#include "soap.h" static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition cond ); static int msn_ns_command( gpointer data, char **cmd, int num_parts ); @@ -238,8 +239,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) imcb_log( ic, "Authenticated, getting buddy list" ); - g_snprintf( buf, sizeof( buf ), "SYN %d 0\r\n", ++md->trId ); - return( msn_write( ic, buf, strlen( buf ) ) ); + msn_soap_memlist_request( ic ); } else { diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c index 4d623a9d..252bddeb 100644 --- a/protocols/msn/soap.c +++ b/protocols/msn/soap.c @@ -82,14 +82,22 @@ static void msn_soap_handle_response( struct http_request *http_req ); static int msn_soap_send_request( struct msn_soap_req_data *soap_req ) { + struct msn_data *md = soap_req->ic->proto_data; char *http_req; + char *pom, *s; url_t url; soap_req->build_request( soap_req ); + pom = g_new0( char, strlen( md->passport_token ) * 3 ); + strcpy( pom, md->passport_token + 2 ); + if( ( s = strchr( pom, '&' ) ) ) + *s = '\0'; + url_set( &url, soap_req->url ); http_req = g_strdup_printf( SOAP_HTTP_REQUEST, url.file, url.host, - soap_req->action, strlen( soap_req->payload ), soap_req->payload ); + soap_req->action, pom, + strlen( soap_req->payload ), soap_req->payload ); soap_req->http_req = http_dorequest( url.host, url.port, url.proto == PROTO_HTTPS, http_req, msn_soap_handle_response, soap_req ); @@ -151,7 +159,7 @@ static int msn_soap_oim_build_request( struct msn_soap_req_data *soap_req ) display_name_b64 = tobase64( ic->displayname ); soap_req->url = g_strdup( SOAP_OIM_SEND_URL ); - soap_req->action = g_strdup( SOAP_OIM_ACTION_URL ); + soap_req->action = g_strdup( SOAP_OIM_SEND_ACTION ); soap_req->payload = g_markup_printf_escaped( SOAP_OIM_SEND_PAYLOAD, ic->acc->user, display_name_b64, oim->to, md->passport_token, MSNP11_PROD_ID, md->lock_key ? md->lock_key : "", @@ -255,3 +263,47 @@ int msn_soap_oim_send_queue( struct im_connection *ic, GSList **msgq ) *msgq = g_slist_remove( *msgq, m ); } } + + +/* memlist: Fetching the membership list (NOT address book) */ + +#if 0 +struct msn_soap_oim_send_data +{ + char *to; + char *msg; + int number; + int need_retry; +}; +#endif + +static int msn_soap_memlist_build_request( struct msn_soap_req_data *soap_req ) +{ + soap_req->url = g_strdup( SOAP_MEMLIST_URL ); + soap_req->action = g_strdup( SOAP_MEMLIST_ACTION ); + soap_req->payload = g_strdup( SOAP_MEMLIST_PAYLOAD ); + + return 1; +} + +static const struct xt_handler_entry msn_soap_memlist_parser[] = { + { NULL, NULL, NULL } +}; + +static int msn_soap_memlist_handle_response( struct msn_soap_req_data *soap_req ) +{ + return 0; +} + +static int msn_soap_memlist_free_data( struct msn_soap_req_data *soap_req ) +{ + return 0; +} + +int msn_soap_memlist_request( struct im_connection *ic ) +{ + return msn_soap_start( ic, NULL, msn_soap_memlist_build_request, + msn_soap_memlist_parser, + msn_soap_memlist_handle_response, + msn_soap_memlist_free_data ); +} diff --git a/protocols/msn/soap.h b/protocols/msn/soap.h index 307ac1bc..78808fdf 100644 --- a/protocols/msn/soap.h +++ b/protocols/msn/soap.h @@ -45,6 +45,7 @@ "SOAPAction: \"%s\"\r\n" \ "User-Agent: BitlBee " BITLBEE_VERSION "\r\n" \ "Content-Type: text/xml; charset=utf-8\r\n" \ +"Cookie: MSPAuth=%s\r\n" \ "Content-Length: %d\r\n" \ "Cache-Control: no-cache\r\n" \ "\r\n" \ @@ -52,7 +53,7 @@ #define SOAP_OIM_SEND_URL "https://ows.messenger.msn.com/OimWS/oim.asmx" -#define SOAP_OIM_ACTION_URL "http://messenger.msn.com/ws/2004/09/oim/Store" +#define SOAP_OIM_SEND_ACTION "http://messenger.msn.com/ws/2004/09/oim/Store" #define SOAP_OIM_SEND_PAYLOAD \ "" \ @@ -84,4 +85,30 @@ int msn_soap_oim_send( struct im_connection *ic, const char *to, const char *msg ); int msn_soap_oim_send_queue( struct im_connection *ic, GSList **msgq ); + +#define SOAP_MEMLIST_URL "https://byrdr.omega.contacts.msn.com/abservice/SharingService.asmx" +#define SOAP_MEMLIST_ACTION "http://www.msn.com/webservices/AddressBook/FindMembership" + +#define SOAP_MEMLIST_PAYLOAD \ +"" \ +"" \ + "" \ + "" \ + "CFE80F9D-180F-4399-82AB-413F33A1FA11" \ + "false" \ + "Initial" \ + "" \ + "" \ + "false" \ + "" \ + "" \ + "" \ + "MessengerInvitationSocialNetworkSpaceProfile" \ + "" \ + "" \ +"" + +int msn_soap_memlist_request( struct im_connection *ic ); + + #endif /* __SOAP_H__ */ -- cgit v1.2.3 From 523fb2324a351e9607ad2a803c6e866c5175aa16 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 11 Aug 2010 09:08:39 +0100 Subject: Implement MSNP15 SSO (Sadistic Sign-On). --- lib/sha1.c | 47 +++++++++++++ lib/sha1.h | 1 + lib/ssl_client.h | 2 + lib/ssl_openssl.c | 24 +++++++ protocols/msn/Makefile | 2 +- protocols/msn/msn.c | 3 +- protocols/msn/msn.h | 3 +- protocols/msn/msn_util.c | 41 +++++------ protocols/msn/ns.c | 32 +++------ protocols/msn/sb.c | 6 ++ protocols/msn/soap.c | 175 ++++++++++++++++++++++++++++++++++++++++++++--- protocols/msn/soap.h | 71 ++++++++++++++++++- 12 files changed, 343 insertions(+), 64 deletions(-) diff --git a/lib/sha1.c b/lib/sha1.c index ee4fcc19..7ee90640 100644 --- a/lib/sha1.c +++ b/lib/sha1.c @@ -35,6 +35,7 @@ * */ +#include #include "sha1.h" /* @@ -373,3 +374,49 @@ static void sha1_pad(sha1_state_t * context) sha1_process_block(context); } + +#define HMAC_BLOCK_SIZE 64 + +/* BitlBee addition: */ +void sha1_hmac(const char *key_, size_t key_len, const char *payload, size_t payload_len, uint8_t Message_Digest[sha1_hash_size]) +{ + sha1_state_t sha1; + uint8_t hash[sha1_hash_size]; + uint8_t key[HMAC_BLOCK_SIZE+1]; + int i; + + if( key_len == 0 ) + key_len = strlen( key_ ); + if( payload_len == 0 ) + payload_len = strlen( payload ); + + /* Create K. If our current key is >64 chars we have to hash it, + otherwise just pad. */ + memset( key, 0, HMAC_BLOCK_SIZE + 1 ); + if( key_len > HMAC_BLOCK_SIZE ) + { + sha1_init( &sha1 ); + sha1_append( &sha1, (uint8_t*) key_, key_len ); + sha1_finish( &sha1, key ); + } + else + { + memcpy( key, key_, key_len ); + } + + /* Inner part: H(K XOR 0x36, text) */ + sha1_init( &sha1 ); + for( i = 0; i < HMAC_BLOCK_SIZE; i ++ ) + key[i] ^= 0x36; + sha1_append( &sha1, key, HMAC_BLOCK_SIZE ); + sha1_append( &sha1, (const uint8_t*) payload, payload_len ); + sha1_finish( &sha1, hash ); + + /* Final result: H(K XOR 0x5C, inner stuff) */ + sha1_init( &sha1 ); + for( i = 0; i < HMAC_BLOCK_SIZE; i ++ ) + key[i] ^= 0x36 ^ 0x5c; + sha1_append( &sha1, key, HMAC_BLOCK_SIZE ); + sha1_append( &sha1, hash, sha1_hash_size ); + sha1_finish( &sha1, Message_Digest ); +} diff --git a/lib/sha1.h b/lib/sha1.h index 4ef8ac92..a87410eb 100644 --- a/lib/sha1.h +++ b/lib/sha1.h @@ -66,5 +66,6 @@ typedef struct SHA1Context { G_MODULE_EXPORT int sha1_init(sha1_state_t *); G_MODULE_EXPORT int sha1_append(sha1_state_t *, const uint8_t *, unsigned int); G_MODULE_EXPORT int sha1_finish(sha1_state_t *, uint8_t Message_Digest[sha1_hash_size]); +G_MODULE_EXPORT void sha1_hmac(const char *key_, size_t key_len, const char *payload, size_t payload_len, uint8_t Message_Digest[sha1_hash_size]); #endif diff --git a/lib/ssl_client.h b/lib/ssl_client.h index 0a8e82d8..787d528a 100644 --- a/lib/ssl_client.h +++ b/lib/ssl_client.h @@ -77,3 +77,5 @@ G_MODULE_EXPORT int ssl_getfd( void *conn ); adding an event handler to the queue. (And it should perform exactly the same action as the handler that just received the SSL_AGAIN.) */ G_MODULE_EXPORT b_input_condition ssl_getdirection( void *conn ); + +G_MODULE_EXPORT size_t ssl_des3_encrypt(const unsigned char *key, size_t key_len, const unsigned char *input, size_t input_len, const unsigned char *iv, unsigned char **res); diff --git a/lib/ssl_openssl.c b/lib/ssl_openssl.c index 8abff390..1c70eb0f 100644 --- a/lib/ssl_openssl.c +++ b/lib/ssl_openssl.c @@ -271,3 +271,27 @@ b_input_condition ssl_getdirection( void *conn ) { return( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ? B_EV_IO_WRITE : B_EV_IO_READ ); } + +size_t ssl_des3_encrypt(const unsigned char *key, size_t key_len, const unsigned char *input, size_t input_len, const unsigned char *iv, unsigned char **res) +{ + OpenSSL_add_all_algorithms(); + int output_length = 0; + + *res = g_new0(unsigned char, 72); + + EVP_CIPHER_CTX ctx; + /* Don't set key or IV because we will modify the parameters */ + EVP_CIPHER_CTX_init(&ctx); + EVP_CipherInit_ex(&ctx, EVP_des_ede3_cbc(), NULL, NULL, NULL, 1); + EVP_CIPHER_CTX_set_key_length(&ctx, key_len); + EVP_CIPHER_CTX_set_padding(&ctx, 0); + /* We finished modifying parameters so now we can set key and IV */ + EVP_CipherInit_ex(&ctx, NULL, NULL, key, iv, 1); + EVP_CipherUpdate(&ctx, *res, &output_length, input, input_len); + EVP_CipherFinal_ex(&ctx, *res, &output_length); + + EVP_CIPHER_CTX_cleanup(&ctx); + EVP_cleanup(); + + return output_length; +} diff --git a/protocols/msn/Makefile b/protocols/msn/Makefile index b9c7ed28..28fe81c9 100644 --- a/protocols/msn/Makefile +++ b/protocols/msn/Makefile @@ -42,4 +42,4 @@ msn_mod.o: $(objects) @echo '*' Linking msn_mod.o @$(LD) $(LFLAGS) $(objects) -o msn_mod.o - +soap.o: soap.h soap.c diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c index 6222e1b6..10c27a1d 100644 --- a/protocols/msn/msn.c +++ b/protocols/msn/msn.c @@ -102,7 +102,8 @@ static void msn_logout( struct im_connection *ic ) while( md->groupcount > 0 ) g_free( md->grouplist[--md->groupcount] ); g_free( md->grouplist ); - g_free( md->passport_token ); + g_free( md->tokens[0] ); + g_free( md->tokens[1] ); g_free( md->lock_key ); while( md->grpq ) diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h index f060000a..d4f3442e 100644 --- a/protocols/msn/msn.h +++ b/protocols/msn/msn.h @@ -75,7 +75,7 @@ struct msn_data struct msn_handler_data *handler; int trId; - char *passport_token; + char *tokens[2]; char *lock_key; GSList *msgq, *grpq; @@ -170,6 +170,7 @@ extern GSList *msn_switchboards; /* ns.c */ gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ); +void msn_auth_got_passport_token( struct im_connection *ic, char *token ); /* msn_util.c */ int msn_write( struct im_connection *ic, char *s, int len ); diff --git a/protocols/msn/msn_util.c b/protocols/msn/msn_util.c index 954ee716..65b12476 100644 --- a/protocols/msn/msn_util.c +++ b/protocols/msn/msn_util.c @@ -33,6 +33,12 @@ int msn_write( struct im_connection *ic, char *s, int len ) struct msn_data *md = ic->proto_data; int st; + if( getenv( "BITLBEE_DEBUG" ) ) + { + write( 2, "->NS:", 5 ); + write( 2, s, len ); + } + st = write( md->fd, s, len ); if( st != len ) { @@ -280,6 +286,12 @@ int msn_handler( struct msn_handler_data *h ) if( st <= 0 ) return( -1 ); + if( getenv( "BITLBEE_DEBUG" ) ) + { + write( 2, "->C:", 4 ); + write( 2, h->rxq + h->rxlen - st, st ); + } + while( st ) { int i; @@ -445,27 +457,6 @@ gboolean msn_set_display_name( struct im_connection *ic, const char *rawname ) return msn_write( ic, buf, strlen( buf ) ) != 0; } -unsigned int little_endian( unsigned int dw ) -{ -#if defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN - return dw; -#else - /* We're still not sure if this machine is big endian since the - constants above are not that portable. Don't swap bytes, just - force-compose a 32-bit little endian integer. */ - unsigned int ret = 0, i; - char *dst = (char*) (&ret + 1); - - for (i = 0; i < 4; i ++) - { - *(--dst) = dw >> 24; - dw <<= 8; - } - - return ret; -#endif -} - /* Copied and heavily modified from http://tmsnc.sourceforge.net/chl.c */ char *msn_p11_challenge( char *challenge ) { @@ -486,7 +477,7 @@ char *msn_p11_challenge( char *challenge ) md5Parts = (unsigned int *)md5Hash; for (i = 0; i < 4; i ++) { - md5Parts[i] = little_endian(md5Parts[i]); + md5Parts[i] = GUINT32_TO_LE(md5Parts[i]); /* & each integer with 0x7FFFFFFF */ /* and save one unmodified array for later */ @@ -507,8 +498,8 @@ char *msn_p11_challenge( char *challenge ) { long long temp; - chlStringParts[i] = little_endian(chlStringParts[i]); - chlStringParts[i+1] = little_endian(chlStringParts[i+1]); + chlStringParts[i] = GUINT32_TO_LE(chlStringParts[i]); + chlStringParts[i+1] = GUINT32_TO_LE(chlStringParts[i+1]); temp = (md5Parts[0] * (((0x0E79A9C1 * (long long)chlStringParts[i]) % 0x7FFFFFFF)+nHigh) + md5Parts[1])%0x7FFFFFFF; nHigh = (md5Parts[2] * (((long long)chlStringParts[i+1]+temp) % 0x7FFFFFFF) + md5Parts[3]) % 0x7FFFFFFF; @@ -524,7 +515,7 @@ char *msn_p11_challenge( char *challenge ) /* swap more bytes if big endian */ for (i = 0; i < 4; i ++) - newHashParts[i] = little_endian(newHashParts[i]); + newHashParts[i] = GUINT32_TO_LE(newHashParts[i]); /* make a string of the parts */ newHash = (unsigned char *)newHashParts; diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index 8236b731..f0d6a58d 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -34,7 +34,6 @@ static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition c static int msn_ns_command( gpointer data, char **cmd, int num_parts ); static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts ); -static void msn_auth_got_passport_token( struct msn_auth_data *mad ); static gboolean msn_ns_got_display_name( struct im_connection *ic, char *name ); gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ) @@ -73,7 +72,7 @@ gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ) md->handler->fd = md->fd; md->handler->rxq = g_new0( char, 1 ); - g_snprintf( s, sizeof( s ), "VER %d MSNP14 CVR0\r\n", ++md->trId ); + g_snprintf( s, sizeof( s ), "VER %d MSNP15 CVR0\r\n", ++md->trId ); if( msn_write( ic, s, strlen( s ) ) ) { ic->inpa = b_input_add( md->fd, B_EV_IO_READ, msn_ns_callback, ic ); @@ -113,7 +112,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( strcmp( cmd[0], "VER" ) == 0 ) { - if( cmd[2] && strncmp( cmd[2], "MSNP14", 5 ) != 0 ) + if( cmd[2] && strncmp( cmd[2], "MSNP15", 5 ) != 0 ) { imcb_error( ic, "Unsupported protocol" ); imc_logout( ic, FALSE ); @@ -127,7 +126,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) else if( strcmp( cmd[0], "CVR" ) == 0 ) { /* We don't give a damn about the information we just received */ - g_snprintf( buf, sizeof( buf ), "USR %d TWN I %s\r\n", ++md->trId, ic->acc->user ); + g_snprintf( buf, sizeof( buf ), "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user ); return( msn_write( ic, buf, strlen( buf ) ) ); } else if( strcmp( cmd[0], "XFR" ) == 0 ) @@ -220,15 +219,10 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) } else if( strcmp( cmd[0], "USR" ) == 0 ) { - if( num_parts == 5 && strcmp( cmd[2], "TWN" ) == 0 && strcmp( cmd[3], "S" ) == 0 ) + if( num_parts >= 6 && strcmp( cmd[2], "SSO" ) == 0 && + strcmp( cmd[3], "S" ) == 0 ) { - /* Time for some Passport black magic... */ - if( !passport_get_token( msn_auth_got_passport_token, ic, ic->acc->user, ic->acc->pass, cmd[4] ) ) - { - imcb_error( ic, "Error while contacting Passport server" ); - imc_logout( ic, TRUE ); - return( 0 ); - } + msn_soap_passport_sso_request( ic, cmd[4], cmd[5] ); } else if( strcmp( cmd[2], "OK" ) == 0 ) { @@ -774,9 +768,8 @@ static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int return( 1 ); } -static void msn_auth_got_passport_token( struct msn_auth_data *mad ) +void msn_auth_got_passport_token( struct im_connection *ic, char *token ) { - struct im_connection *ic = mad->data; struct msn_data *md; /* Dead connection? */ @@ -784,20 +777,13 @@ static void msn_auth_got_passport_token( struct msn_auth_data *mad ) return; md = ic->proto_data; - if( mad->token ) + { char buf[1024]; - md->passport_token = g_strdup( mad->token ); - - g_snprintf( buf, sizeof( buf ), "USR %d TWN S %s\r\n", ++md->trId, mad->token ); + g_snprintf( buf, sizeof( buf ), "USR %d SSO S %s %s\r\n", ++md->trId, md->tokens[0], token ); msn_write( ic, buf, strlen( buf ) ); } - else - { - imcb_error( ic, "Error during Passport authentication: %s", mad->error ); - imc_logout( ic, TRUE ); - } } static gboolean msn_ns_got_display_name( struct im_connection *ic, char *name ) diff --git a/protocols/msn/sb.c b/protocols/msn/sb.c index 1eb919e3..07e94072 100644 --- a/protocols/msn/sb.c +++ b/protocols/msn/sb.c @@ -39,6 +39,12 @@ int msn_sb_write( struct msn_switchboard *sb, char *s, int len ) { int st; + if( getenv( "BITLBEE_DEBUG" ) ) + { + write( 2, "->SB:", 5 ); + write( 2, s, len ); + } + st = write( sb->fd, s, len ); if( st != len ) { diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c index 252bddeb..e837986e 100644 --- a/protocols/msn/soap.c +++ b/protocols/msn/soap.c @@ -27,6 +27,7 @@ #include "bitlbee.h" #include "url.h" #include "misc.h" +#include "sha1.h" #include "base64.h" #include "xmltree.h" #include @@ -82,27 +83,25 @@ static void msn_soap_handle_response( struct http_request *http_req ); static int msn_soap_send_request( struct msn_soap_req_data *soap_req ) { - struct msn_data *md = soap_req->ic->proto_data; char *http_req; - char *pom, *s; + char *soap_action = NULL; url_t url; soap_req->build_request( soap_req ); - pom = g_new0( char, strlen( md->passport_token ) * 3 ); - strcpy( pom, md->passport_token + 2 ); - if( ( s = strchr( pom, '&' ) ) ) - *s = '\0'; + if( soap_req->action ) + soap_action = g_strdup_printf( "SOAPAction: \"%s\"\r\n", soap_req->action ); url_set( &url, soap_req->url ); http_req = g_strdup_printf( SOAP_HTTP_REQUEST, url.file, url.host, - soap_req->action, pom, + soap_action ? soap_action : "", strlen( soap_req->payload ), soap_req->payload ); soap_req->http_req = http_dorequest( url.host, url.port, url.proto == PROTO_HTTPS, http_req, msn_soap_handle_response, soap_req ); g_free( http_req ); + g_free( soap_action ); return soap_req->http_req != NULL; } @@ -139,6 +138,160 @@ static void msn_soap_handle_response( struct http_request *http_req ) } +/* passport_sso: Authentication MSNP15+ */ + +struct msn_soap_passport_sso_data +{ + char *policy; + char *nonce; + char *secret; +}; + +static int msn_soap_passport_sso_build_request( struct msn_soap_req_data *soap_req ) +{ + struct msn_soap_passport_sso_data *sd = soap_req->data; + struct im_connection *ic = soap_req->ic; + + soap_req->url = g_strdup( SOAP_PASSPORT_SSO_URL ); + soap_req->payload = g_markup_printf_escaped( SOAP_PASSPORT_SSO_PAYLOAD, + ic->acc->user, ic->acc->pass, sd->policy ); + + return MSN_SOAP_OK; +} + +static xt_status msn_soap_passport_sso_token( struct xt_node *node, gpointer data ) +{ + struct msn_soap_req_data *soap_req = data; + struct msn_soap_passport_sso_data *sd = soap_req->data; + struct msn_data *md = soap_req->ic->proto_data; + struct xt_node *p; + char *id; + + if( ( id = xt_find_attr( node, "Id" ) ) == NULL ) + return XT_HANDLED; + id += strlen( id ) - 1; + if( *id == '1' && + ( p = node->parent ) && ( p = p->parent ) && + ( p = xt_find_node( p->children, "wst:RequestedProofToken" ) ) && + ( p = xt_find_node( p->children, "wst:BinarySecret" ) ) && + p->text ) + sd->secret = g_strdup( p->text ); + + if( *id == '1' ) + md->tokens[0] = g_strdup( node->text ); + else if( *id == '2' ) + md->tokens[1] = g_strdup( node->text ); + + return XT_HANDLED; +} + +static const struct xt_handler_entry msn_soap_passport_sso_parser[] = { + { "wsse:BinarySecurityToken", "wst:RequestedSecurityToken", msn_soap_passport_sso_token }, + { NULL, NULL, NULL } +}; + +static char *msn_key_fuckery( char *key, int key_len, char *type ) +{ + unsigned char hash1[20+strlen(type)+1]; + unsigned char hash2[20]; + char *ret; + + sha1_hmac( key, key_len, type, 0, hash1 ); + strcpy( (char*) hash1 + 20, type ); + sha1_hmac( key, key_len, (char*) hash1, sizeof( hash1 ) - 1, hash2 ); + + /* This is okay as hash1 is read completely before it's overwritten. */ + sha1_hmac( key, key_len, (char*) hash1, 20, hash1 ); + sha1_hmac( key, key_len, (char*) hash1, sizeof( hash1 ) - 1, hash1 ); + + ret = g_malloc( 24 ); + memcpy( ret, hash2, 20 ); + memcpy( ret + 20, hash1, 4 ); + return ret; +} + +static int msn_soap_passport_sso_handle_response( struct msn_soap_req_data *soap_req ) +{ + struct msn_soap_passport_sso_data *sd = soap_req->data; + struct im_connection *ic = soap_req->ic; + char *key1, *key2, *key3, *blurb64; + int key1_len; + unsigned char *padnonce, *des3res; + struct + { + unsigned int uStructHeaderSize; // 28. Does not count data + unsigned int uCryptMode; // CRYPT_MODE_CBC (1) + unsigned int uCipherType; // TripleDES (0x6603) + unsigned int uHashType; // SHA1 (0x8004) + unsigned int uIVLen; // 8 + unsigned int uHashLen; // 20 + unsigned int uCipherLen; // 72 + unsigned char iv[8]; + unsigned char hash[20]; + unsigned char cipherbytes[72]; + } blurb = { + GUINT32_TO_LE( 28 ), + GUINT32_TO_LE( 1 ), + GUINT32_TO_LE( 0x6603 ), + GUINT32_TO_LE( 0x8004 ), + GUINT32_TO_LE( 8 ), + GUINT32_TO_LE( 20 ), + GUINT32_TO_LE( 72 ), + }; + + key1_len = base64_decode( sd->secret, (unsigned char**) &key1 ); + + key2 = msn_key_fuckery( key1, key1_len, "WS-SecureConversationSESSION KEY HASH" ); + key3 = msn_key_fuckery( key1, key1_len, "WS-SecureConversationSESSION KEY ENCRYPTION" ); + + sha1_hmac( key2, 24, sd->nonce, 0, blurb.hash ); + padnonce = g_malloc( strlen( sd->nonce ) + 8 ); + strcpy( (char*) padnonce, sd->nonce ); + memset( padnonce + strlen( sd->nonce ), 8, 8 ); + + random_bytes( blurb.iv, 8 ); + + ssl_des3_encrypt( (unsigned char*) key3, 24, padnonce, strlen( sd->nonce ) + 8, blurb.iv, &des3res ); + memcpy( blurb.cipherbytes, des3res, 72 ); + + blurb64 = base64_encode( (unsigned char*) &blurb, sizeof( blurb ) ); + msn_auth_got_passport_token( ic, blurb64 ); + + g_free( padnonce ); + g_free( blurb64 ); + g_free( des3res ); + g_free( key1 ); + g_free( key2 ); + g_free( key3 ); + + return MSN_SOAP_OK; +} + +static int msn_soap_passport_sso_free_data( struct msn_soap_req_data *soap_req ) +{ + struct msn_soap_passport_sso_data *sd = soap_req->data; + + g_free( sd->policy ); + g_free( sd->nonce ); + g_free( sd->secret ); + + return MSN_SOAP_OK; +} + +int msn_soap_passport_sso_request( struct im_connection *ic, const char *policy, const char *nonce ) +{ + struct msn_soap_passport_sso_data *sd = g_new0( struct msn_soap_passport_sso_data, 1 ); + + sd->policy = g_strdup( policy ); + sd->nonce = g_strdup( nonce ); + + return msn_soap_start( ic, sd, msn_soap_passport_sso_build_request, + msn_soap_passport_sso_parser, + msn_soap_passport_sso_handle_response, + msn_soap_passport_sso_free_data ); +} + + /* oim_send: Sending offline messages */ struct msn_soap_oim_send_data @@ -161,13 +314,13 @@ static int msn_soap_oim_build_request( struct msn_soap_req_data *soap_req ) soap_req->url = g_strdup( SOAP_OIM_SEND_URL ); soap_req->action = g_strdup( SOAP_OIM_SEND_ACTION ); soap_req->payload = g_markup_printf_escaped( SOAP_OIM_SEND_PAYLOAD, - ic->acc->user, display_name_b64, oim->to, md->passport_token, + ic->acc->user, display_name_b64, oim->to, "bla", //md->passport_token, MSNP11_PROD_ID, md->lock_key ? md->lock_key : "", oim->number, oim->number, oim->msg ); g_free( display_name_b64 ); - return 1; + return MSN_SOAP_OK; } static xt_status msn_soap_oim_send_challenge( struct xt_node *node, gpointer data ) @@ -219,7 +372,7 @@ static int msn_soap_oim_free_data( struct msn_soap_req_data *soap_req ) g_free( oim->msg ); g_free( oim ); - return 0; + return MSN_SOAP_OK; } int msn_soap_oim_send( struct im_connection *ic, const char *to, const char *msg ) @@ -262,6 +415,8 @@ int msn_soap_oim_send_queue( struct im_connection *ic, GSList **msgq ) *msgq = g_slist_remove( *msgq, m ); } + + return 1; } diff --git a/protocols/msn/soap.h b/protocols/msn/soap.h index 78808fdf..5fbac3c4 100644 --- a/protocols/msn/soap.h +++ b/protocols/msn/soap.h @@ -42,16 +42,81 @@ "POST %s HTTP/1.0\r\n" \ "Host: %s\r\n" \ "Accept: */*\r\n" \ -"SOAPAction: \"%s\"\r\n" \ "User-Agent: BitlBee " BITLBEE_VERSION "\r\n" \ "Content-Type: text/xml; charset=utf-8\r\n" \ -"Cookie: MSPAuth=%s\r\n" \ -"Content-Length: %d\r\n" \ +"%s" \ +"Content-Length: %zd\r\n" \ "Cache-Control: no-cache\r\n" \ "\r\n" \ "%s" +#define SOAP_PASSPORT_SSO_URL "https://login.live.com/RST.srf" +#define SOAP_PASSPORT_SSO_URL_MSN "https://msnia.login.live.com/pp550/RST.srf" + +#define SOAP_PASSPORT_SSO_PAYLOAD \ +"" \ + "
" \ + "" \ + "{7108E71A-9926-4FCB-BCC9-9A9D3F32E423}" \ + "4" \ + "1" \ + "" \ + "AQAAAAIAAABsYwQAAAAxMDMz" \ + "" \ + "" \ + "" \ + "%s" \ + "%s" \ + "" \ + "" \ + "
" \ + "" \ + "" \ + "" \ + "http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue" \ + "" \ + "" \ + "http://Passport.NET/tb" \ + "" \ + "" \ + "" \ + "" \ + "http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue" \ + "" \ + "" \ + "messengerclear.live.com" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue" \ + "" \ + "" \ + "contacts.msn.com" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ +"
" + +int msn_soap_passport_sso_request( struct im_connection *ic, const char *policy, const char *nonce ); + + #define SOAP_OIM_SEND_URL "https://ows.messenger.msn.com/OimWS/oim.asmx" #define SOAP_OIM_SEND_ACTION "http://messenger.msn.com/ws/2004/09/oim/Store" -- cgit v1.2.3 From 7f34ce254c1a1587e5560456dd11acb29345206d Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Thu, 12 Aug 2010 00:03:33 +0100 Subject: Get contact list/address book info. Next step: We have to send it back. Seriously. Wish I were joking. --- protocols/msn/msn.c | 13 +++++ protocols/msn/msn.h | 15 +++++ protocols/msn/soap.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++---- protocols/msn/soap.h | 33 ++++++++++- 4 files changed, 202 insertions(+), 13 deletions(-) diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c index 10c27a1d..0b9cffc2 100644 --- a/protocols/msn/msn.c +++ b/protocols/msn/msn.c @@ -333,6 +333,16 @@ static char *set_eval_display_name( set_t *set, char *value ) return msn_set_display_name( ic, value ) ? value : NULL; } +static void msn_buddy_data_add( bee_user_t *bu ) +{ + bu->data = g_new0( struct msn_buddy_data, 1 ); +} + +static void msn_buddy_data_free( bee_user_t *bu ) +{ + g_free( bu->data ); +} + void msn_initmodule() { struct prpl *ret = g_new0(struct prpl, 1); @@ -359,6 +369,9 @@ void msn_initmodule() ret->rem_deny = msn_rem_deny; ret->send_typing = msn_send_typing; ret->handle_cmp = g_strcasecmp; + ret->buddy_data_add = msn_buddy_data_add; + ret->buddy_data_free = msn_buddy_data_free; + //ret->transfer_request = msn_ftp_transfer_request; register_protocol(ret); diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h index d4f3442e..757359fe 100644 --- a/protocols/msn/msn.h +++ b/protocols/msn/msn.h @@ -150,6 +150,21 @@ struct msn_handler_data int (*exec_message) ( gpointer data, char *msg, int msglen, char **cmd, int count ); }; +typedef enum +{ + MSN_BUDDY_FL = 1, + MSN_BUDDY_AL = 2, + MSN_BUDDY_BL = 4, + MSN_BUDDY_RL = 8, + MSN_BUDDY_PL = 16, +} msn_buddy_flags_t; + +struct msn_buddy_data +{ + char *cid; + msn_buddy_flags_t flags; +}; + /* Bitfield values for msn_status_code.flags */ #define STATUS_FATAL 1 #define STATUS_SB_FATAL 2 diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c index e837986e..62d58200 100644 --- a/protocols/msn/soap.c +++ b/protocols/msn/soap.c @@ -422,32 +422,61 @@ int msn_soap_oim_send_queue( struct im_connection *ic, GSList **msgq ) /* memlist: Fetching the membership list (NOT address book) */ -#if 0 -struct msn_soap_oim_send_data -{ - char *to; - char *msg; - int number; - int need_retry; -}; -#endif - static int msn_soap_memlist_build_request( struct msn_soap_req_data *soap_req ) { + struct msn_data *md = soap_req->ic->proto_data; + soap_req->url = g_strdup( SOAP_MEMLIST_URL ); soap_req->action = g_strdup( SOAP_MEMLIST_ACTION ); - soap_req->payload = g_strdup( SOAP_MEMLIST_PAYLOAD ); + soap_req->payload = g_markup_printf_escaped( SOAP_MEMLIST_PAYLOAD, md->tokens[1] ); return 1; } +static xt_status msn_soap_memlist_member( struct xt_node *node, gpointer data ) +{ + bee_user_t *bu; + struct msn_buddy_data *bd; + struct xt_node *p; + char *role = NULL, *handle = NULL; + struct msn_soap_req_data *soap_req = data; + struct im_connection *ic = soap_req->ic; + + if( ( p = node->parent ) && ( p = p->parent ) && + ( p = xt_find_node( p->children, "MemberRole" ) ) ) + role = p->text; + + if( ( p = xt_find_node( node->children, "PassportName" ) ) ) + handle = p->text; + + if( !role || !handle || + !( ( bu = bee_user_by_handle( ic->bee, ic, handle ) ) || + ( bu = bee_user_new( ic->bee, ic, handle, 0 ) ) ) ) + return XT_HANDLED; + + bd = bu->data; + if( strcmp( role, "Allow" ) == 0 ) + bd->flags |= MSN_BUDDY_AL; + else if( strcmp( role, "Block" ) == 0 ) + bd->flags |= MSN_BUDDY_BL; + else if( strcmp( role, "Reverse" ) == 0 ) + bd->flags |= MSN_BUDDY_RL; + else if( strcmp( role, "Pending" ) == 0 ) + bd->flags |= MSN_BUDDY_PL; + + return XT_HANDLED; +} + static const struct xt_handler_entry msn_soap_memlist_parser[] = { + { "Member", "Members", msn_soap_memlist_member }, { NULL, NULL, NULL } }; static int msn_soap_memlist_handle_response( struct msn_soap_req_data *soap_req ) { - return 0; + msn_soap_addressbook_request( soap_req->ic ); + + return MSN_SOAP_OK; } static int msn_soap_memlist_free_data( struct msn_soap_req_data *soap_req ) @@ -462,3 +491,104 @@ int msn_soap_memlist_request( struct im_connection *ic ) msn_soap_memlist_handle_response, msn_soap_memlist_free_data ); } + + +/* addressbook: Fetching the membership list (NOT address book) */ + +static int msn_soap_addressbook_build_request( struct msn_soap_req_data *soap_req ) +{ + struct msn_data *md = soap_req->ic->proto_data; + + soap_req->url = g_strdup( SOAP_ADDRESSBOOK_URL ); + soap_req->action = g_strdup( SOAP_ADDRESSBOOK_ACTION ); + soap_req->payload = g_markup_printf_escaped( SOAP_ADDRESSBOOK_PAYLOAD, md->tokens[1] ); + + return 1; +} + +static xt_status msn_soap_addressbook_group( struct xt_node *node, gpointer data ) +{ + struct xt_node *p; + char *id = NULL, *name = NULL; + struct msn_soap_req_data *soap_req = data; + struct im_connection *ic = soap_req->ic; + + if( ( p = node->parent ) && + ( p = xt_find_node( p->children, "groupId" ) ) ) + id = p->text; + + if( ( p = xt_find_node( node->children, "name" ) ) ) + name = p->text; + + printf( "%s %s\n", id, name ); + + return XT_HANDLED; +} + +static xt_status msn_soap_addressbook_contact( struct xt_node *node, gpointer data ) +{ + bee_user_t *bu; + struct msn_buddy_data *bd; + struct xt_node *p; + char *id = NULL, *type = NULL, *handle = NULL, *display_name = NULL; + struct msn_soap_req_data *soap_req = data; + struct im_connection *ic = soap_req->ic; + + if( ( p = node->parent ) && + ( p = xt_find_node( p->children, "contactId" ) ) ) + id = p->text; + if( ( p = xt_find_node( node->children, "contactType" ) ) ) + type = p->text; + if( ( p = xt_find_node( node->children, "passportName" ) ) ) + handle = p->text; + if( ( p = xt_find_node( node->children, "displayName" ) ) ) + display_name = p->text; + + if( type && g_strcasecmp( type, "me" ) == 0 ) + { + set_t *set = set_find( &ic->acc->set, "display_name" ); + g_free( set->value ); + set->value = g_strdup( display_name ); + + return XT_HANDLED; + } + + if( !( bu = bee_user_by_handle( ic->bee, ic, handle ) ) && + !( bu = bee_user_new( ic->bee, ic, handle, 0 ) ) ) + return XT_HANDLED; + + bd = bu->data; + bd->flags |= MSN_BUDDY_FL; + g_free( bd->cid ); + bd->cid = g_strdup( id ); + + imcb_rename_buddy( ic, handle, display_name ); + + printf( "%s %s %s %s\n", id, type, handle, display_name ); + + return XT_HANDLED; +} + +static const struct xt_handler_entry msn_soap_addressbook_parser[] = { + { "contactInfo", "Contact", msn_soap_addressbook_contact }, + { "groupInfo", "Group", msn_soap_addressbook_group }, + { NULL, NULL, NULL } +}; + +static int msn_soap_addressbook_handle_response( struct msn_soap_req_data *soap_req ) +{ + return MSN_SOAP_OK; +} + +static int msn_soap_addressbook_free_data( struct msn_soap_req_data *soap_req ) +{ + return 0; +} + +int msn_soap_addressbook_request( struct im_connection *ic ) +{ + return msn_soap_start( ic, NULL, msn_soap_addressbook_build_request, + msn_soap_addressbook_parser, + msn_soap_addressbook_handle_response, + msn_soap_addressbook_free_data ); +} diff --git a/protocols/msn/soap.h b/protocols/msn/soap.h index 5fbac3c4..9eb1caef 100644 --- a/protocols/msn/soap.h +++ b/protocols/msn/soap.h @@ -151,7 +151,7 @@ int msn_soap_oim_send( struct im_connection *ic, const char *to, const char *msg int msn_soap_oim_send_queue( struct im_connection *ic, GSList **msgq ); -#define SOAP_MEMLIST_URL "https://byrdr.omega.contacts.msn.com/abservice/SharingService.asmx" +#define SOAP_MEMLIST_URL "http://contacts.msn.com/abservice/SharingService.asmx" #define SOAP_MEMLIST_ACTION "http://www.msn.com/webservices/AddressBook/FindMembership" #define SOAP_MEMLIST_PAYLOAD \ @@ -165,6 +165,7 @@ int msn_soap_oim_send_queue( struct im_connection *ic, GSList **msgq ); "" \ "" \ "false" \ + "%s" \ "" \ "" \ "" \ @@ -176,4 +177,34 @@ int msn_soap_oim_send_queue( struct im_connection *ic, GSList **msgq ); int msn_soap_memlist_request( struct im_connection *ic ); +#define SOAP_ADDRESSBOOK_URL "http://contacts.msn.com/abservice/abservice.asmx" +#define SOAP_ADDRESSBOOK_ACTION "http://www.msn.com/webservices/AddressBook/ABFindAll" + +#define SOAP_ADDRESSBOOK_PAYLOAD \ +"" \ +"" \ + "" \ + "" \ + "CFE80F9D-180F-4399-82AB-413F33A1FA11" \ + "false" \ + "Initial" \ + "" \ + "" \ + "false" \ + "%s" \ + "" \ + "" \ + "" \ + "" \ + "00000000-0000-0000-0000-000000000000" \ + "Full" \ + "false" \ + "0001-01-01T00:00:00.0000000-08:00" \ + "" \ + "" \ +"" + +int msn_soap_addressbook_request( struct im_connection *ic ); + + #endif /* __SOAP_H__ */ -- cgit v1.2.3 From ca7de3ac72f0ef10613badecb7eb6cc9a10f996b Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Thu, 12 Aug 2010 23:13:26 +0100 Subject: Successful login (including contact list sync). \o/ --- protocols/msn/msn.c | 8 ++ protocols/msn/msn.h | 5 +- protocols/msn/msn_util.c | 12 +++ protocols/msn/ns.c | 200 +++++++++++++++++++++++------------------------ protocols/msn/soap.c | 1 + 5 files changed, 125 insertions(+), 101 deletions(-) diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c index 0b9cffc2..4de2d822 100644 --- a/protocols/msn/msn.c +++ b/protocols/msn/msn.c @@ -67,6 +67,7 @@ static void msn_login( account_t *acc ) md->ic = ic; md->away_state = msn_away_state_list; + md->domaintree = g_tree_new( msn_domaintree_cmp ); msn_connections = g_slist_append( msn_connections, ic ); } @@ -106,6 +107,9 @@ static void msn_logout( struct im_connection *ic ) g_free( md->tokens[1] ); g_free( md->lock_key ); + g_tree_destroy( md->domaintree ); + md->domaintree = NULL; + while( md->grpq ) { struct msn_groupadd *ga = md->grpq->data; @@ -335,11 +339,15 @@ static char *set_eval_display_name( set_t *set, char *value ) static void msn_buddy_data_add( bee_user_t *bu ) { + struct msn_data *md = bu->ic->proto_data; bu->data = g_new0( struct msn_buddy_data, 1 ); + g_tree_insert( md->domaintree, bu->handle, bu ); } static void msn_buddy_data_free( bee_user_t *bu ) { + struct msn_data *md = bu->ic->proto_data; + g_tree_remove( md->domaintree, bu->handle ); g_free( bu->data ); } diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h index 757359fe..6e447d7f 100644 --- a/protocols/msn/msn.h +++ b/protocols/msn/msn.h @@ -88,6 +88,7 @@ struct msn_data int buddycount; int groupcount; char **grouplist; + GTree *domaintree; }; struct msn_switchboard @@ -152,7 +153,7 @@ struct msn_handler_data typedef enum { - MSN_BUDDY_FL = 1, + MSN_BUDDY_FL = 1, /* Warning: FL,AL,BL *must* be 1,2,4. */ MSN_BUDDY_AL = 2, MSN_BUDDY_BL = 4, MSN_BUDDY_RL = 8, @@ -186,6 +187,7 @@ extern GSList *msn_switchboards; /* ns.c */ gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ); void msn_auth_got_passport_token( struct im_connection *ic, char *token ); +void msn_auth_got_contact_list( struct im_connection *ic ); /* msn_util.c */ int msn_write( struct im_connection *ic, char *s, int len ); @@ -200,6 +202,7 @@ char *msn_http_encode( const char *input ); void msn_msgq_purge( struct im_connection *ic, GSList **list ); gboolean msn_set_display_name( struct im_connection *ic, const char *rawname ); char *msn_p11_challenge( char *challenge ); +gint msn_domaintree_cmp( gconstpointer a_, gconstpointer b_ ); /* tables.c */ const struct msn_away_state *msn_away_state_by_number( int number ); diff --git a/protocols/msn/msn_util.c b/protocols/msn/msn_util.c index 65b12476..3a19d92f 100644 --- a/protocols/msn/msn_util.c +++ b/protocols/msn/msn_util.c @@ -527,3 +527,15 @@ char *msn_p11_challenge( char *challenge ) return output; } + +gint msn_domaintree_cmp( gconstpointer a_, gconstpointer b_ ) +{ + const char *a = a_, *b = b_; + gint ret; + + if( !( a = strchr( a, '@' ) ) || !( b = strchr( b, '@' ) ) || + ( ret = strcmp( a, b ) ) == 0 ) + ret = strcmp( a_, b_ ); + + return ret; +} diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index f0d6a58d..ffb21c47 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -26,15 +26,16 @@ #include #include "nogaim.h" #include "msn.h" -#include "passport.h" #include "md5.h" #include "soap.h" +#include "xmltree.h" static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition cond ); static int msn_ns_command( gpointer data, char **cmd, int num_parts ); static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts ); static gboolean msn_ns_got_display_name( struct im_connection *ic, char *name ); +static void msn_ns_send_adl( struct im_connection *ic ); gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ) { @@ -134,7 +135,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) char *server; int port; - if( num_parts == 6 && strcmp( cmd[2], "NS" ) == 0 ) + if( num_parts >= 6 && strcmp( cmd[2], "NS" ) == 0 ) { b_event_remove( ic->inpa ); ic->inpa = 0; @@ -155,7 +156,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) md->fd = proxy_connect( server, port, msn_ns_connected, ic ); } - else if( num_parts == 6 && strcmp( cmd[2], "SB" ) == 0 ) + else if( num_parts >= 6 && strcmp( cmd[2], "SB" ) == 0 ) { struct msn_switchboard *sb; @@ -260,109 +261,34 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) return( 0 ); } } - else if( strcmp( cmd[0], "SYN" ) == 0 ) + else if( strcmp( cmd[0], "BLP" ) == 0 ) { - if( num_parts == 5 ) - { - int i, groupcount; - - groupcount = atoi( cmd[4] ); - if( groupcount > 0 ) - { - /* valgrind says this is leaking memory, I'm guessing - that this happens during server redirects. */ - if( md->grouplist ) - { - for( i = 0; i < md->groupcount; i ++ ) - g_free( md->grouplist[i] ); - g_free( md->grouplist ); - } - - md->groupcount = groupcount; - md->grouplist = g_new0( char *, md->groupcount ); - } - - md->buddycount = atoi( cmd[3] ); - if( !*cmd[3] || md->buddycount == 0 ) - msn_logged_in( ic ); - } - else - { - /* Hrrm... This SYN reply doesn't really look like something we expected. - Let's assume everything is okay. */ - - msn_logged_in( ic ); - } + msn_ns_send_adl( ic ); } - else if( strcmp( cmd[0], "LST" ) == 0 ) + else if( strcmp( cmd[0], "ADL" ) == 0 ) { - int list; - - if( num_parts != 4 && num_parts != 5 ) - { - imcb_error( ic, "Syntax error" ); - imc_logout( ic, TRUE ); - return( 0 ); - } - - http_decode( cmd[2] ); - list = atoi( cmd[3] ); - - if( list & 1 ) /* FL */ + if( num_parts >= 3 && strcmp( cmd[2], "OK" ) == 0 ) { - char *group = NULL; - int num; + char buf[1024]; + char *fn_raw = set_getstr( &ic->acc->set, "display_name" ); + char *fn; - if( cmd[4] != NULL && sscanf( cmd[4], "%d", &num ) == 1 && num < md->groupcount ) - group = md->grouplist[num]; + if( fn_raw == NULL ) + fn_raw = ic->acc->user; + fn = g_malloc( strlen( fn_raw ) * 3 + 1 ); + strcpy( fn, fn_raw ); + http_encode( fn ); - imcb_add_buddy( ic, cmd[1], group ); - imcb_rename_buddy( ic, cmd[1], cmd[2] ); - } - if( list & 2 ) /* AL */ - { - ic->permit = g_slist_append( ic->permit, g_strdup( cmd[1] ) ); - } - if( list & 4 ) /* BL */ - { - ic->deny = g_slist_append( ic->deny, g_strdup( cmd[1] ) ); - } - if( list & 8 ) /* RL */ - { - if( ( list & 6 ) == 0 ) - msn_buddy_ask( ic, cmd[1], cmd[2] ); - } - - if( --md->buddycount == 0 ) - { - if( ic->flags & OPT_LOGGED_IN ) - { - imcb_log( ic, "Successfully transferred to different server" ); - g_snprintf( buf, sizeof( buf ), "CHG %d %s %d\r\n", ++md->trId, md->away_state->code, 0 ); - return( msn_write( ic, buf, strlen( buf ) ) ); - } - else - { - msn_logged_in( ic ); - } + g_snprintf( buf, sizeof( buf ), "PRP %d MFN %s\r\n", + ++md->trId, fn ); + g_free( fn ); + + msn_write( ic, buf, strlen( buf ) ); } } - else if( strcmp( cmd[0], "LSG" ) == 0 ) + else if( strcmp( cmd[0], "PRP" ) == 0 ) { - int num; - - if( num_parts != 4 ) - { - imcb_error( ic, "Syntax error" ); - imc_logout( ic, TRUE ); - return( 0 ); - } - - http_decode( cmd[2] ); - num = atoi( cmd[1] ); - - if( num < md->groupcount ) - md->grouplist[num] = g_strdup( cmd[2] ); + imcb_connected( ic ); } else if( strcmp( cmd[0], "CHL" ) == 0 ) { @@ -392,15 +318,15 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) { const struct msn_away_state *st; - if( num_parts != 6 ) + if( num_parts < 6 ) { imcb_error( ic, "Syntax error" ); imc_logout( ic, TRUE ); return( 0 ); } - http_decode( cmd[4] ); - imcb_rename_buddy( ic, cmd[3], cmd[4] ); + http_decode( cmd[5] ); + imcb_rename_buddy( ic, cmd[3], cmd[5] ); st = msn_away_state_by_code( cmd[2] ); if( !st ) @@ -786,6 +712,80 @@ void msn_auth_got_passport_token( struct im_connection *ic, char *token ) } } +void msn_auth_got_contact_list( struct im_connection *ic ) +{ + char buf[64]; + struct msn_data *md; + + /* Dead connection? */ + if( g_slist_find( msn_connections, ic ) == NULL ) + return; + + md = ic->proto_data; + + + g_snprintf( buf, sizeof( buf ), "BLP %d %s\r\n", ++md->trId, "BL" ); + msn_write( ic, buf, strlen( buf ) ); +} + +static gboolean msn_ns_send_adl_1( gpointer key, gpointer value, gpointer data ) +{ + struct xt_node *adl = data, *d, *c; + struct bee_user *bu = value; + struct msn_buddy_data *bd = bu->data; + char handle[strlen(bu->handle)]; + char *domain; + char l[4]; + + strcpy( handle, bu->handle ); + if( ( domain = strchr( handle, '@' ) ) == NULL ) /* WTF */ + return FALSE; + *domain = '\0'; + domain ++; + + if( ( d = adl->children ) == NULL || + g_strcasecmp( xt_find_attr( d, "n" ), domain ) != 0 ) + { + d = xt_new_node( "d", NULL, NULL ); + xt_add_attr( d, "n", domain ); + xt_insert_child( adl, d ); + } + + g_snprintf( l, sizeof( l ), "%d", bd->flags & 7 ); + c = xt_new_node( "c", NULL, NULL ); + xt_add_attr( c, "n", handle ); + xt_add_attr( c, "l", l ); + xt_add_attr( c, "t", "1" ); /* 1 means normal, 4 means mobile? */ + xt_insert_child( d, c ); + + return FALSE; +} + +static void msn_ns_send_adl( struct im_connection *ic ) +{ + struct xt_node *adl; + struct msn_data *md; + char *adls, buf[64]; + + /* Dead connection? */ + if( g_slist_find( msn_connections, ic ) == NULL ) + return; + + md = ic->proto_data; + + adl = xt_new_node( "ml", NULL, NULL ); + xt_add_attr( adl, "l", "1" ); + g_tree_foreach( md->domaintree, msn_ns_send_adl_1, adl ); + adls = xt_to_string( adl ); + + g_snprintf( buf, sizeof( buf ), "ADL %d %zd\r\n", ++md->trId, strlen( adls ) ); + if( msn_write( ic, buf, strlen( buf ) ) ) + msn_write( ic, adls, strlen( adls ) ); + + g_free( adls ); + xt_free_node( adl ); +} + static gboolean msn_ns_got_display_name( struct im_connection *ic, char *name ) { set_t *s; diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c index 62d58200..bb664861 100644 --- a/protocols/msn/soap.c +++ b/protocols/msn/soap.c @@ -577,6 +577,7 @@ static const struct xt_handler_entry msn_soap_addressbook_parser[] = { static int msn_soap_addressbook_handle_response( struct msn_soap_req_data *soap_req ) { + msn_auth_got_contact_list( soap_req->ic ); return MSN_SOAP_OK; } -- cgit v1.2.3 From be7a180689ba5dc2b1cd1dc14f55c59246e238ed Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Thu, 12 Aug 2010 23:38:30 +0100 Subject: Proper responses to CHL challenges. Clean up bee_users before calling prpl->logout() since the buddy_data functions would like some structs to still exist. --- protocols/msn/msn.h | 15 +++++++++------ protocols/msn/ns.c | 25 +++++++++++++------------ protocols/nogaim.c | 16 ++++++++-------- 3 files changed, 30 insertions(+), 26 deletions(-) diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h index 6e447d7f..d788260c 100644 --- a/protocols/msn/msn.h +++ b/protocols/msn/msn.h @@ -38,15 +38,18 @@ #define debug( text... ) #endif -#define QRY_NAME "msmsgs@msnmsgr.com" -#define QRY_CODE "Q1P7W2E4J9R8U3S5" - -/* This should be MSN Messenger 7.0.0813 */ -//#define MSNP11_PROD_KEY "CFHUR$52U_{VIX5T" -//#define MSNP11_PROD_ID "PROD0101{0RM?UBW" +/* This should be MSN Messenger 7.0.0813 +#define MSNP11_PROD_KEY "CFHUR$52U_{VIX5T" +#define MSNP11_PROD_ID "PROD0101{0RM?UBW" +*/ +/* Some other version. #define MSNP11_PROD_KEY "O4BG@C7BWLYQX?5G" #define MSNP11_PROD_ID "PROD01065C%ZFN6F" +*/ + +#define MSNP11_PROD_KEY "RG@XY*28Q5QHS%Q5" +#define MSNP11_PROD_ID "PROD0113H11T8$X_" #define MSN_SB_NEW -24062002 diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index ffb21c47..3e02e328 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -292,25 +292,20 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) } else if( strcmp( cmd[0], "CHL" ) == 0 ) { - md5_state_t state; - md5_byte_t digest[16]; - int i; + char *resp; - if( num_parts != 3 ) + if( num_parts < 3 ) { imcb_error( ic, "Syntax error" ); imc_logout( ic, TRUE ); return( 0 ); } - md5_init( &state ); - md5_append( &state, (const md5_byte_t *) cmd[2], strlen( cmd[2] ) ); - md5_append( &state, (const md5_byte_t *) QRY_CODE, strlen( QRY_CODE ) ); - md5_finish( &state, digest ); - - g_snprintf( buf, sizeof( buf ), "QRY %d %s %d\r\n", ++md->trId, QRY_NAME, 32 ); - for( i = 0; i < 16; i ++ ) - g_snprintf( buf + strlen( buf ), 3, "%02x", digest[i] ); + resp = msn_p11_challenge( cmd[2] ); + g_snprintf( buf, sizeof( buf ), "QRY %d %s %zd\r\n%s", + ++md->trId, MSNP11_PROD_ID, + strlen( resp ), resp ); + g_free( resp ); return( msn_write( ic, buf, strlen( buf ) ) ); } @@ -581,6 +576,12 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) censore. Meh. */ md->handler->msglen = atoi( cmd[2] ); } + else if( strcmp( cmd[0], "UBX" ) == 0 ) + { + /* Status message. Parser coming soon. */ + if( num_parts >= 4 ) + md->handler->msglen = atoi( cmd[3] ); + } else if( isdigit( cmd[0][0] ) ) { int num = atoi( cmd[0] ); diff --git a/protocols/nogaim.c b/protocols/nogaim.c index 7943e026..10ffd843 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -325,14 +325,6 @@ void imc_logout( struct im_connection *ic, int allow_reconnect ) imcb_log( ic, "Signing off.." ); - b_event_remove( ic->keepalive ); - ic->keepalive = 0; - ic->acc->prpl->logout( ic ); - b_event_remove( ic->inpa ); - - g_free( ic->away ); - ic->away = NULL; - for( l = bee->users; l; ) { bee_user_t *bu = l->data; @@ -344,6 +336,14 @@ void imc_logout( struct im_connection *ic, int allow_reconnect ) l = next; } + b_event_remove( ic->keepalive ); + ic->keepalive = 0; + ic->acc->prpl->logout( ic ); + b_event_remove( ic->inpa ); + + g_free( ic->away ); + ic->away = NULL; + query_del_by_conn( (irc_t*) ic->bee->ui_data, ic ); for( a = bee->accounts; a; a = a->next ) -- cgit v1.2.3 From b46769d05371e501800a4658a0faf82c4ccdb0dd Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Thu, 12 Aug 2010 23:44:56 +0100 Subject: Some syntax checking fixups; don't make the same mistake of failing just if the MSN server is sending a little bit *more* info. And adding xt_insert_node() used in the ADL generation code. --- lib/xmltree.c | 20 ++++++++++++++++++++ lib/xmltree.h | 1 + protocols/msn/ns.c | 16 +++++----------- protocols/msn/sb.c | 12 ++++++------ 4 files changed, 32 insertions(+), 17 deletions(-) diff --git a/lib/xmltree.c b/lib/xmltree.c index b0a945ce..00b37ae6 100644 --- a/lib/xmltree.c +++ b/lib/xmltree.c @@ -549,6 +549,26 @@ void xt_add_child( struct xt_node *parent, struct xt_node *child ) } } +/* Same, but at the beginning. */ +void xt_insert_child( struct xt_node *parent, struct xt_node *child ) +{ + struct xt_node *node, *last; + + for( node = child; node; node = node->next ) + { + if( node->parent != NULL ) + { + /* ERROR CONDITION: They seem to have a parent already??? */ + } + + node->parent = parent; + last = node; + } + + last->next = parent->children; + parent->children = child; +} + void xt_add_attr( struct xt_node *node, const char *key, const char *value ) { int i; diff --git a/lib/xmltree.h b/lib/xmltree.h index 34e3be68..ddb3f02f 100644 --- a/lib/xmltree.h +++ b/lib/xmltree.h @@ -91,6 +91,7 @@ char *xt_find_attr( struct xt_node *node, const char *key ); struct xt_node *xt_new_node( char *name, const char *text, struct xt_node *children ); void xt_add_child( struct xt_node *parent, struct xt_node *child ); +void xt_insert_child( struct xt_node *parent, struct xt_node *child ); void xt_add_attr( struct xt_node *node, const char *key, const char *value ); int xt_remove_attr( struct xt_node *node, const char *key ); diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index 3e02e328..2d40b47b 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -227,13 +227,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) } else if( strcmp( cmd[2], "OK" ) == 0 ) { - if( num_parts == 7 ) - msn_ns_got_display_name( ic, cmd[4] ); - else - imcb_log( ic, "Warning: Friendly name in server response was corrupted" ); - imcb_log( ic, "Authenticated, getting buddy list" ); - msn_soap_memlist_request( ic ); } else @@ -245,7 +239,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) } else if( strcmp( cmd[0], "MSG" ) == 0 ) { - if( num_parts != 4 ) + if( num_parts < 4 ) { imcb_error( ic, "Syntax error" ); imc_logout( ic, TRUE ); @@ -347,7 +341,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) { const struct msn_away_state *st; - if( num_parts != 5 ) + if( num_parts < 5 ) { imcb_error( ic, "Syntax error" ); imc_logout( ic, TRUE ); @@ -376,7 +370,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) char *server; int session, port; - if( num_parts != 7 ) + if( num_parts < 7 ) { imcb_error( ic, "Syntax error" ); imc_logout( ic, TRUE ); @@ -420,7 +414,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) } else if( strcmp( cmd[0], "ADD" ) == 0 ) { - if( num_parts == 6 && strcmp( cmd[2], "RL" ) == 0 ) + if( num_parts >= 6 && strcmp( cmd[2], "RL" ) == 0 ) { GSList *l; @@ -484,7 +478,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) and since MSN servers can apparently screw up the formatting. */ else if( strcmp( cmd[0], "REA" ) == 0 ) { - if( num_parts != 5 ) + if( num_parts < 5 ) { imcb_error( ic, "Syntax error" ); imc_logout( ic, TRUE ); diff --git a/protocols/msn/sb.c b/protocols/msn/sb.c index 07e94072..b718d4e8 100644 --- a/protocols/msn/sb.c +++ b/protocols/msn/sb.c @@ -413,7 +413,7 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts ) } else if( strcmp( cmd[0], "USR" ) == 0 ) { - if( num_parts != 5 ) + if( num_parts < 5 ) { msn_sb_destroy( sb ); return( 0 ); @@ -439,7 +439,7 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts ) { int num, tot; - if( num_parts != 6 ) + if( num_parts < 6 ) { msn_sb_destroy( sb ); return( 0 ); @@ -476,7 +476,7 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts ) } else if( strcmp( cmd[0], "ANS" ) == 0 ) { - if( num_parts != 3 ) + if( num_parts < 3 ) { msn_sb_destroy( sb ); return( 0 ); @@ -495,7 +495,7 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts ) } else if( strcmp( cmd[0], "CAL" ) == 0 ) { - if( num_parts != 4 || !isdigit( cmd[3][0] ) ) + if( num_parts < 4 || !isdigit( cmd[3][0] ) ) { msn_sb_destroy( sb ); return( 0 ); @@ -505,7 +505,7 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts ) } else if( strcmp( cmd[0], "JOI" ) == 0 ) { - if( num_parts != 3 ) + if( num_parts < 3 ) { msn_sb_destroy( sb ); return( 0 ); @@ -566,7 +566,7 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts ) } else if( strcmp( cmd[0], "MSG" ) == 0 ) { - if( num_parts != 4 ) + if( num_parts < 4 ) { msn_sb_destroy( sb ); return( 0 ); -- cgit v1.2.3 From 91d6e9108bce93925a1bad60613d01c5382d003d Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Fri, 13 Aug 2010 10:12:31 +0100 Subject: Sending offline messages works now ... but Pidgin doesn't seem to receive them. :-/ --- protocols/msn/msn.c | 1 + protocols/msn/msn.h | 11 ++++++++--- protocols/msn/ns.c | 4 ++-- protocols/msn/soap.c | 15 +++++++++------ protocols/msn/soap.h | 13 +++++++++++-- 5 files changed, 31 insertions(+), 13 deletions(-) diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c index 4de2d822..ef70fe0c 100644 --- a/protocols/msn/msn.c +++ b/protocols/msn/msn.c @@ -105,6 +105,7 @@ static void msn_logout( struct im_connection *ic ) g_free( md->grouplist ); g_free( md->tokens[0] ); g_free( md->tokens[1] ); + g_free( md->tokens[2] ); g_free( md->lock_key ); g_tree_destroy( md->domaintree ); diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h index d788260c..8abe6875 100644 --- a/protocols/msn/msn.h +++ b/protocols/msn/msn.h @@ -48,8 +48,13 @@ #define MSNP11_PROD_ID "PROD01065C%ZFN6F" */ -#define MSNP11_PROD_KEY "RG@XY*28Q5QHS%Q5" -#define MSNP11_PROD_ID "PROD0113H11T8$X_" +#define MSNP11_PROD_KEY "ILTXC!4IXB5FB*PX" +//PK}_A_0N_K%O?A9S" +#define MSNP11_PROD_ID "PROD0119GSJUC$18" +//PROD0114ES4Z%Q5W" +#define MSNP_VER "MSNP15" +#define MSNP_BUILD "8.5.1288" +//"8.1.0178" #define MSN_SB_NEW -24062002 @@ -78,7 +83,7 @@ struct msn_data struct msn_handler_data *handler; int trId; - char *tokens[2]; + char *tokens[3]; char *lock_key; GSList *msgq, *grpq; diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index 2d40b47b..4ae8693d 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -73,7 +73,7 @@ gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ) md->handler->fd = md->fd; md->handler->rxq = g_new0( char, 1 ); - g_snprintf( s, sizeof( s ), "VER %d MSNP15 CVR0\r\n", ++md->trId ); + g_snprintf( s, sizeof( s ), "VER %d %s CVR0\r\n", ++md->trId, MSNP_VER ); if( msn_write( ic, s, strlen( s ) ) ) { ic->inpa = b_input_add( md->fd, B_EV_IO_READ, msn_ns_callback, ic ); @@ -113,7 +113,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( strcmp( cmd[0], "VER" ) == 0 ) { - if( cmd[2] && strncmp( cmd[2], "MSNP15", 5 ) != 0 ) + if( cmd[2] && strncmp( cmd[2], MSNP_VER, 5 ) != 0 ) { imcb_error( ic, "Unsupported protocol" ); imc_logout( ic, FALSE ); diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c index bb664861..0fb36bb4 100644 --- a/protocols/msn/soap.c +++ b/protocols/msn/soap.c @@ -177,10 +177,12 @@ static xt_status msn_soap_passport_sso_token( struct xt_node *node, gpointer dat p->text ) sd->secret = g_strdup( p->text ); - if( *id == '1' ) - md->tokens[0] = g_strdup( node->text ); - else if( *id == '2' ) - md->tokens[1] = g_strdup( node->text ); + *id -= '1'; + if( *id >= 0 && *id <= 2 ) + { + g_free( md->tokens[(int)*id] ); + md->tokens[(int)*id] = g_strdup( node->text ); + } return XT_HANDLED; } @@ -309,12 +311,13 @@ static int msn_soap_oim_build_request( struct msn_soap_req_data *soap_req ) struct msn_data *md = ic->proto_data; char *display_name_b64; - display_name_b64 = tobase64( ic->displayname ); + display_name_b64 = tobase64( set_getstr( &ic->acc->set, "display_name" ) ); soap_req->url = g_strdup( SOAP_OIM_SEND_URL ); soap_req->action = g_strdup( SOAP_OIM_SEND_ACTION ); soap_req->payload = g_markup_printf_escaped( SOAP_OIM_SEND_PAYLOAD, - ic->acc->user, display_name_b64, oim->to, "bla", //md->passport_token, + ic->acc->user, display_name_b64, MSNP_VER, MSNP_BUILD, + oim->to, md->tokens[2], MSNP11_PROD_ID, md->lock_key ? md->lock_key : "", oim->number, oim->number, oim->msg ); diff --git a/protocols/msn/soap.h b/protocols/msn/soap.h index 9eb1caef..f3231e91 100644 --- a/protocols/msn/soap.h +++ b/protocols/msn/soap.h @@ -110,6 +110,15 @@ "" \ "" \ "" \ + "" \ + "http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue" \ + "" \ + "" \ + "messengersecure.live.com" \ + "" \ + "" \ + "" \ + "" \ "" \ "" \ "" @@ -118,13 +127,13 @@ int msn_soap_passport_sso_request( struct im_connection *ic, const char *policy, #define SOAP_OIM_SEND_URL "https://ows.messenger.msn.com/OimWS/oim.asmx" -#define SOAP_OIM_SEND_ACTION "http://messenger.msn.com/ws/2004/09/oim/Store" +#define SOAP_OIM_SEND_ACTION "http://messenger.live.com/ws/2006/09/oim/Store2" #define SOAP_OIM_SEND_PAYLOAD \ "" \ "" \ "" \ - "" \ + "" \ "" \ "" \ "" \ -- cgit v1.2.3 From 50b8978f0662fc83aa2e3db1d40081c315c9e6cf Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Fri, 13 Aug 2010 10:12:54 +0100 Subject: OpenSSL fixes + debugging. --- lib/ssl_gnutls.c | 4 ++++ lib/ssl_openssl.c | 14 +++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/lib/ssl_gnutls.c b/lib/ssl_gnutls.c index 5a14b825..15c23dbb 100644 --- a/lib/ssl_gnutls.c +++ b/lib/ssl_gnutls.c @@ -188,6 +188,8 @@ int ssl_read( void *conn, char *buf, int len ) if( st == GNUTLS_E_AGAIN || st == GNUTLS_E_INTERRUPTED ) ssl_errno = SSL_AGAIN; + if( getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st ); + return st; } @@ -207,6 +209,8 @@ int ssl_write( void *conn, const char *buf, int len ) if( st == GNUTLS_E_AGAIN || st == GNUTLS_E_INTERRUPTED ) ssl_errno = SSL_AGAIN; + if( getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st ); + return st; } diff --git a/lib/ssl_openssl.c b/lib/ssl_openssl.c index 1c70eb0f..0feed4ca 100644 --- a/lib/ssl_openssl.c +++ b/lib/ssl_openssl.c @@ -115,7 +115,9 @@ static gboolean ssl_connected( gpointer data, gint source, b_input_condition con if( !initialized ) { initialized = TRUE; - SSLeay_add_ssl_algorithms(); + SSL_library_init(); + //SSLeay_add_ssl_algorithms(); + //OpenSSL_add_all_algorithms(); } meth = TLSv1_client_method(); @@ -204,6 +206,8 @@ int ssl_read( void *conn, char *buf, int len ) ssl_errno = SSL_AGAIN; } + if( getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st ); + return st; } @@ -219,6 +223,8 @@ int ssl_write( void *conn, const char *buf, int len ) st = SSL_write( ((struct scd*)conn)->ssl, buf, len ); + if( getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st ); + ssl_errno = SSL_OK; if( st <= 0 ) { @@ -274,12 +280,11 @@ b_input_condition ssl_getdirection( void *conn ) size_t ssl_des3_encrypt(const unsigned char *key, size_t key_len, const unsigned char *input, size_t input_len, const unsigned char *iv, unsigned char **res) { - OpenSSL_add_all_algorithms(); int output_length = 0; + EVP_CIPHER_CTX ctx; *res = g_new0(unsigned char, 72); - EVP_CIPHER_CTX ctx; /* Don't set key or IV because we will modify the parameters */ EVP_CIPHER_CTX_init(&ctx); EVP_CipherInit_ex(&ctx, EVP_des_ede3_cbc(), NULL, NULL, NULL, 1); @@ -289,9 +294,8 @@ size_t ssl_des3_encrypt(const unsigned char *key, size_t key_len, const unsigned EVP_CipherInit_ex(&ctx, NULL, NULL, key, iv, 1); EVP_CipherUpdate(&ctx, *res, &output_length, input, input_len); EVP_CipherFinal_ex(&ctx, *res, &output_length); - EVP_CIPHER_CTX_cleanup(&ctx); - EVP_cleanup(); + //EVP_cleanup(); return output_length; } -- cgit v1.2.3 From 4e4af1b0fe073fd2d43f4ea0d55f8deadbeb974d Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 14 Aug 2010 09:48:46 +0100 Subject: Remove some old Passport stuff, this is all in soap.[ch] now. --- protocols/msn/Makefile | 2 +- protocols/msn/msn.c | 2 +- protocols/msn/msn.h | 3 - protocols/msn/ns.c | 2 +- protocols/msn/passport.c | 172 ----------------------------------------------- protocols/msn/passport.h | 113 ------------------------------- protocols/msn/sb.c | 3 +- protocols/msn/soap.c | 60 ++++++++++------- protocols/msn/tables.c | 2 +- 9 files changed, 39 insertions(+), 320 deletions(-) delete mode 100644 protocols/msn/passport.c delete mode 100644 protocols/msn/passport.h diff --git a/protocols/msn/Makefile b/protocols/msn/Makefile index 28fe81c9..a14225d1 100644 --- a/protocols/msn/Makefile +++ b/protocols/msn/Makefile @@ -12,7 +12,7 @@ SRCDIR := $(SRCDIR)protocols/msn/ endif # [SH] Program variables -objects = msn.o msn_util.o ns.o passport.o sb.o soap.o tables.o +objects = msn.o msn_util.o ns.o sb.o soap.o tables.o LFLAGS += -r diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c index ef70fe0c..7b881c67 100644 --- a/protocols/msn/msn.c +++ b/protocols/msn/msn.c @@ -1,7 +1,7 @@ /********************************************************************\ * BitlBee -- An IRC to other IM-networks gateway * * * - * Copyright 2002-2004 Wilmer van der Gaast and others * + * Copyright 2002-2010 Wilmer van der Gaast and others * \********************************************************************/ /* MSN module - Main file; functions to be called from BitlBee */ diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h index 8abe6875..5c7949c9 100644 --- a/protocols/msn/msn.h +++ b/protocols/msn/msn.h @@ -232,7 +232,4 @@ int msn_sb_write_msg( struct im_connection *ic, struct msn_message *m ); void msn_sb_start_keepalives( struct msn_switchboard *sb, gboolean initial ); void msn_sb_stop_keepalives( struct msn_switchboard *sb ); -/* invitation.c */ -void msn_ftp_transfer_request( struct im_connection *ic, file_transfer_t *ft, char *who ); - #endif //_MSN_H diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index 4ae8693d..40f96b21 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -1,7 +1,7 @@ /********************************************************************\ * BitlBee -- An IRC to other IM-networks gateway * * * - * Copyright 2002-2004 Wilmer van der Gaast and others * + * Copyright 2002-2010 Wilmer van der Gaast and others * \********************************************************************/ /* MSN module - Notification server callbacks */ diff --git a/protocols/msn/passport.c b/protocols/msn/passport.c deleted file mode 100644 index 7c896db1..00000000 --- a/protocols/msn/passport.c +++ /dev/null @@ -1,172 +0,0 @@ -/** passport.c - * - * Functions to login to Microsoft Passport service for Messenger - * Copyright (C) 2004-2008 Wilmer van der Gaast - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation - * - * This program is distributed in the hope that is will be useful, - * bit WITHOU ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include "http_client.h" -#include "passport.h" -#include "msn.h" -#include "bitlbee.h" -#include "url.h" -#include "misc.h" -#include "xmltree.h" -#include -#include - -static int passport_get_token_real( struct msn_auth_data *mad ); -static void passport_get_token_ready( struct http_request *req ); - -int passport_get_token( gpointer func, gpointer data, char *username, char *password, char *cookie ) -{ - struct msn_auth_data *mad = g_new0( struct msn_auth_data, 1 ); - int i; - - mad->username = g_strdup( username ); - mad->password = g_strdup( password ); - mad->cookie = g_strdup( cookie ); - - mad->callback = func; - mad->data = data; - - mad->url = g_strdup( SOAP_AUTHENTICATION_URL ); - mad->ttl = 3; /* Max. # of redirects. */ - - /* HTTP-escape stuff and s/,/&/ */ - http_decode( mad->cookie ); - for( i = 0; mad->cookie[i]; i ++ ) - if( mad->cookie[i] == ',' ) - mad->cookie[i] = '&'; - - /* Microsoft doesn't allow password longer than 16 chars and silently - fails authentication if you give the "full version" of your passwd. */ - if( strlen( mad->password ) > MAX_PASSPORT_PWLEN ) - mad->password[MAX_PASSPORT_PWLEN] = 0; - - return passport_get_token_real( mad ); -} - -static int passport_get_token_real( struct msn_auth_data *mad ) -{ - char *post_payload, *post_request; - struct http_request *req; - url_t url; - - url_set( &url, mad->url ); - - post_payload = g_markup_printf_escaped( SOAP_AUTHENTICATION_PAYLOAD, - mad->username, - mad->password, - mad->cookie ); - - post_request = g_strdup_printf( SOAP_AUTHENTICATION_REQUEST, - url.file, url.host, - (int) strlen( post_payload ), - post_payload ); - - req = http_dorequest( url.host, url.port, 1, post_request, - passport_get_token_ready, mad ); - - g_free( post_request ); - g_free( post_payload ); - - return req != NULL; -} - -static xt_status passport_xt_extract_token( struct xt_node *node, gpointer data ); -static xt_status passport_xt_handle_fault( struct xt_node *node, gpointer data ); - -static const struct xt_handler_entry passport_xt_handlers[] = { - { "wsse:BinarySecurityToken", "wst:RequestedSecurityToken", passport_xt_extract_token }, - { "S:Fault", "S:Envelope", passport_xt_handle_fault }, - { NULL, NULL, NULL } -}; - -static void passport_get_token_ready( struct http_request *req ) -{ - struct msn_auth_data *mad = req->data; - struct xt_parser *parser; - - g_free( mad->url ); - g_free( mad->error ); - mad->url = mad->error = NULL; - - if( req->status_code == 200 ) - { - parser = xt_new( passport_xt_handlers, mad ); - xt_feed( parser, req->reply_body, req->body_size ); - xt_handle( parser, NULL, -1 ); - xt_free( parser ); - } - else - { - mad->error = g_strdup_printf( "HTTP error %d (%s)", req->status_code, - req->status_string ? req->status_string : "unknown" ); - } - - if( mad->error == NULL && mad->token == NULL ) - mad->error = g_strdup( "Could not parse Passport server response" ); - - if( mad->url && mad->token == NULL ) - { - passport_get_token_real( mad ); - } - else - { - mad->callback( mad ); - - g_free( mad->url ); - g_free( mad->username ); - g_free( mad->password ); - g_free( mad->cookie ); - g_free( mad->token ); - g_free( mad->error ); - g_free( mad ); - } -} - -static xt_status passport_xt_extract_token( struct xt_node *node, gpointer data ) -{ - struct msn_auth_data *mad = data; - char *s; - - if( ( s = xt_find_attr( node, "Id" ) ) && - ( strncmp( s, "Compact", 7 ) == 0 || - strncmp( s, "PPToken", 7 ) == 0 ) ) - mad->token = g_memdup( node->text, node->text_len + 1 ); - - return XT_HANDLED; -} - -static xt_status passport_xt_handle_fault( struct xt_node *node, gpointer data ) -{ - struct msn_auth_data *mad = data; - struct xt_node *code = xt_find_node( node->children, "faultcode" ); - struct xt_node *string = xt_find_node( node->children, "faultstring" ); - struct xt_node *redirect = xt_find_node( node->children, "psf:redirectUrl" ); - - if( redirect && redirect->text_len && mad->ttl-- > 0 ) - mad->url = g_memdup( redirect->text, redirect->text_len + 1 ); - - if( code == NULL || code->text_len == 0 ) - mad->error = g_strdup( "Unknown error" ); - else - mad->error = g_strdup_printf( "%s (%s)", code->text, string && string->text_len ? - string->text : "no description available" ); - - return XT_HANDLED; -} diff --git a/protocols/msn/passport.h b/protocols/msn/passport.h deleted file mode 100644 index 517d2e91..00000000 --- a/protocols/msn/passport.h +++ /dev/null @@ -1,113 +0,0 @@ -/* passport.h - * - * Functions to login to Microsoft Passport service for Messenger - * Copyright (C) 2004-2008 Wilmer van der Gaast - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation - * - * This program is distributed in the hope that is will be useful, - * bit WITHOU ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* Thanks to http://msnpiki.msnfanatic.com/index.php/MSNP13:SOAPTweener - for the specs! */ - -#ifndef __PASSPORT_H__ -#define __PASSPORT_H__ - -#include -#include -#include -#include -#ifndef _WIN32 -#include -#include -#include -#include -#endif -#include "nogaim.h" - -#define MAX_PASSPORT_PWLEN 16 - -struct msn_auth_data -{ - char *url; - int ttl; - - char *username; - char *password; - char *cookie; - - /* The end result, the only thing we'll really be interested in - once finished. */ - char *token; - char *error; /* Yeah, or that... */ - - void (*callback)( struct msn_auth_data *mad ); - gpointer data; -}; - -#define SOAP_AUTHENTICATION_URL "https://loginnet.passport.com/RST.srf" - -#define SOAP_AUTHENTICATION_REQUEST \ -"POST %s HTTP/1.0\r\n" \ -"Accept: text/*\r\n" \ -"User-Agent: BitlBee " BITLBEE_VERSION "\r\n" \ -"Host: %s\r\n" \ -"Content-Length: %d\r\n" \ -"Cache-Control: no-cache\r\n" \ -"\r\n" \ -"%s" - -#define SOAP_AUTHENTICATION_PAYLOAD \ -"" \ -"" \ - "
" \ - "" \ - "{7108E71A-9926-4FCB-BCC9-9A9D3F32E423}" \ - "4" \ - "1" \ - "" \ - "AQAAAAIAAABsYwQAAAAzMDg0" \ - "" \ - "" \ - "" \ - "%s" \ - "%s" \ - "" \ - "" \ - "
" \ - "" \ - "" \ - "" \ - "http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue" \ - "" \ - "" \ - "http://Passport.NET/tb" \ - "" \ - "" \ - "" \ - "" \ - "http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue" \ - "" \ - "" \ - "messenger.msn.com" \ - "" \ - "" \ - "" \ - "" \ - "" \ - "" \ -"
" - -int passport_get_token( gpointer func, gpointer data, char *username, char *password, char *cookie ); - -#endif /* __PASSPORT_H__ */ diff --git a/protocols/msn/sb.c b/protocols/msn/sb.c index b718d4e8..fdad2882 100644 --- a/protocols/msn/sb.c +++ b/protocols/msn/sb.c @@ -1,7 +1,7 @@ /********************************************************************\ * BitlBee -- An IRC to other IM-networks gateway * * * - * Copyright 2002-2005 Wilmer van der Gaast and others * + * Copyright 2002-2010 Wilmer van der Gaast and others * \********************************************************************/ /* MSN module - Switchboard server callbacks and utilities */ @@ -26,7 +26,6 @@ #include #include "nogaim.h" #include "msn.h" -#include "passport.h" #include "md5.h" #include "soap.h" #include "invitation.h" diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c index 0fb36bb4..621e213b 100644 --- a/protocols/msn/soap.c +++ b/protocols/msn/soap.c @@ -1,25 +1,30 @@ -/** soap.c - * - * SOAP-related functions. Some manager at Microsoft apparently thought - * MSNP wasn't XMLy enough so someone stepped up and changed that. This - * is the result. - * - * Copyright (C) 2010 Wilmer van der Gaast - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation - * - * This program is distributed in the hope that is will be useful, - * bit WITHOU ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2010 Wilmer van der Gaast and others * + \********************************************************************/ + +/* MSN module - All the SOAPy XML stuff. + Some manager at Microsoft apparently thought MSNP wasn't XMLy enough so + someone stepped up and changed that. This is the result. Kilobytes and + more kilobytes of XML vomit to transfer tiny bits of informaiton. */ + +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License with + the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, + Suite 330, Boston, MA 02111-1307 USA +*/ #include "http_client.h" #include "soap.h" @@ -33,6 +38,11 @@ #include #include +/* This file tries to make SOAP stuff pretty simple to do by letting you just + provide a function to build a request, a few functions to parse various + parts of the response, and a function to run when the full response was + received and parsed. See the various examples below. */ + typedef enum { MSN_SOAP_OK, @@ -40,10 +50,6 @@ typedef enum MSN_SOAP_ABORT, } msn_soap_result_t; -struct msn_soap_req_data; - -typedef int (*msn_soap_func) ( struct msn_soap_req_data * ); - struct msn_soap_req_data { void *data; @@ -57,6 +63,8 @@ struct msn_soap_req_data msn_soap_func build_request, handle_response, free_data; }; +typedef int (*msn_soap_func) ( struct msn_soap_req_data * ); + static int msn_soap_send_request( struct msn_soap_req_data *req ); static int msn_soap_start( struct im_connection *ic, diff --git a/protocols/msn/tables.c b/protocols/msn/tables.c index 42b12aa9..fd7eca41 100644 --- a/protocols/msn/tables.c +++ b/protocols/msn/tables.c @@ -1,7 +1,7 @@ /********************************************************************\ * BitlBee -- An IRC to other IM-networks gateway * * * - * Copyright 2002-2004 Wilmer van der Gaast and others * + * Copyright 2002-2010 Wilmer van der Gaast and others * \********************************************************************/ /* MSN module - Some tables with useful data */ -- cgit v1.2.3 From 73efe3a6ea04ca19f3a4088990eda60ad852a94f Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 14 Aug 2010 12:07:45 +0100 Subject: Allow Passport authentication with @msn.com accounts. --- protocols/msn/soap.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c index 621e213b..c23d190a 100644 --- a/protocols/msn/soap.c +++ b/protocols/msn/soap.c @@ -160,7 +160,11 @@ static int msn_soap_passport_sso_build_request( struct msn_soap_req_data *soap_r struct msn_soap_passport_sso_data *sd = soap_req->data; struct im_connection *ic = soap_req->ic; - soap_req->url = g_strdup( SOAP_PASSPORT_SSO_URL ); + if( g_str_has_suffix( ic->acc->user, "@msn.com" ) ) + soap_req->url = g_strdup( SOAP_PASSPORT_SSO_URL_MSN ); + else + soap_req->url = g_strdup( SOAP_PASSPORT_SSO_URL ); + soap_req->payload = g_markup_printf_escaped( SOAP_PASSPORT_SSO_PAYLOAD, ic->acc->user, ic->acc->pass, sd->policy ); -- cgit v1.2.3 From 12767e39dbafc36d54995727ff2c6043e8292f16 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 14 Aug 2010 12:30:40 +0100 Subject: Status/Away messages. --- protocols/msn/msn.c | 12 +++++++++++- protocols/msn/soap.c | 6 +++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c index 7b881c67..99db509c 100644 --- a/protocols/msn/msn.c +++ b/protocols/msn/msn.c @@ -38,6 +38,8 @@ static void msn_init( account_t *acc ) set_add( &acc->set, "local_display_name", "false", set_eval_bool, acc ); set_add( &acc->set, "mail_notifications", "false", set_eval_bool, acc ); set_add( &acc->set, "switchboard_keepalives", "false", set_eval_bool, acc ); + + acc->flags |= ACC_FLAG_AWAY_MESSAGE | ACC_FLAG_STATUS_MESSAGE; } static void msn_login( account_t *acc ) @@ -181,6 +183,7 @@ static GList *msn_away_states( struct im_connection *ic ) static void msn_set_away( struct im_connection *ic, char *state, char *message ) { char buf[1024]; + char *uux; struct msn_data *md = ic->proto_data; if( state == NULL ) @@ -189,7 +192,14 @@ static void msn_set_away( struct im_connection *ic, char *state, char *message ) md->away_state = msn_away_state_list + 1; g_snprintf( buf, sizeof( buf ), "CHG %d %s\r\n", ++md->trId, md->away_state->code ); - msn_write( ic, buf, strlen( buf ) ); + if( !msn_write( ic, buf, strlen( buf ) ) ) + return; + + uux = g_markup_printf_escaped( "%s" + "", message ? message : "" ); + g_snprintf( buf, sizeof( buf ), "UUX %d %zd\r\n%s", ++md->trId, strlen( uux ), uux ); + if( !msn_write( ic, buf, strlen( buf ) ) ) + return; } static void msn_set_my_name( struct im_connection *ic, char *info ) diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c index c23d190a..5eae3089 100644 --- a/protocols/msn/soap.c +++ b/protocols/msn/soap.c @@ -50,6 +50,9 @@ typedef enum MSN_SOAP_ABORT, } msn_soap_result_t; +struct msn_soap_req_data; +typedef int (*msn_soap_func) ( struct msn_soap_req_data * ); + struct msn_soap_req_data { void *data; @@ -63,8 +66,6 @@ struct msn_soap_req_data msn_soap_func build_request, handle_response, free_data; }; -typedef int (*msn_soap_func) ( struct msn_soap_req_data * ); - static int msn_soap_send_request( struct msn_soap_req_data *req ); static int msn_soap_start( struct im_connection *ic, @@ -526,7 +527,6 @@ static xt_status msn_soap_addressbook_group( struct xt_node *node, gpointer data struct xt_node *p; char *id = NULL, *name = NULL; struct msn_soap_req_data *soap_req = data; - struct im_connection *ic = soap_req->ic; if( ( p = node->parent ) && ( p = xt_find_node( p->children, "groupId" ) ) ) -- cgit v1.2.3 From d93c0eb9f3f5d2d2cd78f02422d0c0ed25743e3a Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 14 Aug 2010 13:20:59 +0100 Subject: Read incoming MSN status/away messages. --- lib/xmltree.c | 16 +++++++++++++++- lib/xmltree.h | 3 ++- protocols/bee.h | 1 + protocols/bee_user.c | 29 ++++++++++++++++++++++++++++- protocols/msn/ns.c | 20 ++++++++++++++++++++ protocols/msn/soap.h | 48 +++++++++++++++++++++++++++--------------------- 6 files changed, 93 insertions(+), 24 deletions(-) diff --git a/lib/xmltree.c b/lib/xmltree.c index 00b37ae6..f413b8f7 100644 --- a/lib/xmltree.c +++ b/lib/xmltree.c @@ -140,7 +140,7 @@ void xt_reset( struct xt_parser *xt ) /* Feed the parser, don't execute any handler. Returns -1 on errors, 0 on end-of-stream and 1 otherwise. */ -int xt_feed( struct xt_parser *xt, char *text, int text_len ) +int xt_feed( struct xt_parser *xt, const char *text, int text_len ) { if( !g_markup_parse_context_parse( xt->parser, text, text_len, &xt->gerr ) ) { @@ -259,6 +259,20 @@ void xt_cleanup( struct xt_parser *xt, struct xt_node *node, int depth ) } } +struct xt_node *xt_from_string( const char *in ) +{ + struct xt_parser *parser; + struct xt_node *ret; + + parser = xt_new( NULL, NULL ); + xt_feed( parser, in, strlen( in ) ); + ret = parser->root; + parser->root = NULL; + xt_free( parser ); + + return ret; +} + static void xt_to_string_real( struct xt_node *node, GString *str ) { char *buf; diff --git a/lib/xmltree.h b/lib/xmltree.h index ddb3f02f..c1697ff5 100644 --- a/lib/xmltree.h +++ b/lib/xmltree.h @@ -78,9 +78,10 @@ struct xt_parser struct xt_parser *xt_new( const struct xt_handler_entry *handlers, gpointer data ); void xt_reset( struct xt_parser *xt ); -int xt_feed( struct xt_parser *xt, char *text, int text_len ); +int xt_feed( struct xt_parser *xt, const char *text, int text_len ); int xt_handle( struct xt_parser *xt, struct xt_node *node, int depth ); void xt_cleanup( struct xt_parser *xt, struct xt_node *node, int depth ); +struct xt_node *xt_from_string( const char *in ); char *xt_to_string( struct xt_node *node ); void xt_print( struct xt_node *node ); struct xt_node *xt_dup( struct xt_node *node ); diff --git a/protocols/bee.h b/protocols/bee.h index 5792e988..6e3cf563 100644 --- a/protocols/bee.h +++ b/protocols/bee.h @@ -147,6 +147,7 @@ void bee_group_free( bee_t *bee ); * OPT_LOGGED_IN and OPT_AWAY. * - 'state' and 'message' can be NULL */ G_MODULE_EXPORT void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, const char *state, const char *message ); +G_MODULE_EXPORT void imcb_buddy_status_msg( struct im_connection *ic, const char *handle, const char *message ); G_MODULE_EXPORT void imcb_buddy_times( struct im_connection *ic, const char *handle, time_t login, time_t idle ); /* Call when a handle says something. 'flags' and 'sent_at may be just 0. */ G_MODULE_EXPORT void imcb_buddy_msg( struct im_connection *ic, const char *handle, char *msg, guint32 flags, time_t sent_at ); diff --git a/protocols/bee_user.c b/protocols/bee_user.c index 5acd5b83..86f87f86 100644 --- a/protocols/bee_user.c +++ b/protocols/bee_user.c @@ -186,8 +186,13 @@ void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, /* TODO(wilmer): OPT_AWAY, or just state == NULL ? */ bu->flags = flags; - bu->status = g_strdup( ( flags & OPT_AWAY ) && state == NULL ? "Away" : state ); bu->status_msg = g_strdup( message ); + if( state && *state ) + bu->status = g_strdup( state ); + else if( flags & OPT_AWAY ) + bu->status = g_strdup( "Away" ); + else + bu->status = NULL; if( bee->ui->user_status ) bee->ui->user_status( bee, bu, old ); @@ -197,6 +202,28 @@ void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, g_free( old ); } +/* Same, but only change the away/status message, not any away/online state info. */ +void imcb_buddy_status_msg( struct im_connection *ic, const char *handle, const char *message ) +{ + bee_t *bee = ic->bee; + bee_user_t *bu, *old; + + if( !( bu = bee_user_by_handle( bee, ic, handle ) ) ) + { + return; + } + + old = g_memdup( bu, sizeof( bee_user_t ) ); + + bu->status_msg = g_strdup( message ); + + if( bee->ui->user_status ) + bee->ui->user_status( bee, bu, old ); + + g_free( old->status_msg ); + g_free( old ); +} + void imcb_buddy_times( struct im_connection *ic, const char *handle, time_t login, time_t idle ) { bee_t *bee = ic->bee; diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index 40f96b21..0c067b8c 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -576,6 +576,13 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( num_parts >= 4 ) md->handler->msglen = atoi( cmd[3] ); } + else if( strcmp( cmd[0], "NOT" ) == 0 ) + { + /* Some kind of notification, not sure if it still exists + but we have to skip the payload or stuff breaks. */ + if( num_parts >= 3 ) + md->handler->msglen = atoi( cmd[2] ); + } else if( isdigit( cmd[0][0] ) ) { int num = atoi( cmd[0] ); @@ -685,6 +692,19 @@ static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int g_free( ct ); } } + else if( strcmp( cmd[0], "UBX" ) == 0 ) + { + struct xt_node *psm; + char *psm_text = NULL; + + psm = xt_from_string( msg ); + if( psm && strcmp( psm->name, "Data" ) == 0 && + ( psm = xt_find_node( psm->children, "PSM" ) ) ) + psm_text = psm->text; + + imcb_buddy_status_msg( ic, cmd[1], psm_text ); + xt_free_node( psm ); + } return( 1 ); } diff --git a/protocols/msn/soap.h b/protocols/msn/soap.h index f3231e91..14b0624b 100644 --- a/protocols/msn/soap.h +++ b/protocols/msn/soap.h @@ -1,24 +1,30 @@ -/* soap.h - * - * SOAP-related functions. Some manager at Microsoft apparently thought - * MSNP wasn't XMLy enough so someone stepped up and changed that. This - * is the result. - * - * Copyright (C) 2010 Wilmer van der Gaast - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation - * - * This program is distributed in the hope that is will be useful, - * bit WITHOU ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2010 Wilmer van der Gaast and others * + \********************************************************************/ + +/* MSN module - All the SOAPy XML stuff. + Some manager at Microsoft apparently thought MSNP wasn't XMLy enough so + someone stepped up and changed that. This is the result. Kilobytes and + more kilobytes of XML vomit to transfer tiny bits of informaiton. */ + +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License with + the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, + Suite 330, Boston, MA 02111-1307 USA +*/ /* Thanks to http://msnpiki.msnfanatic.com/ for lots of info on this! */ -- cgit v1.2.3 From 4452e69ab1f01793a37205db8227a2de2f211d3e Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 14 Aug 2010 14:06:11 +0100 Subject: Allow changing the display_name, now permanently! --- lib/xmltree.c | 14 ++++----- protocols/msn/msn.c | 37 ++++++++++++---------- protocols/msn/msn.h | 1 - protocols/msn/msn_util.c | 49 ++++------------------------- protocols/msn/ns.c | 80 ------------------------------------------------ protocols/msn/soap.c | 34 ++++++++++++++++++++ protocols/msn/soap.h | 33 ++++++++++++++++++++ protocols/nogaim.h | 2 ++ storage_xml.c | 10 ++++++ 9 files changed, 113 insertions(+), 147 deletions(-) diff --git a/lib/xmltree.c b/lib/xmltree.c index f413b8f7..5fd43014 100644 --- a/lib/xmltree.c +++ b/lib/xmltree.c @@ -173,20 +173,20 @@ int xt_handle( struct xt_parser *xt, struct xt_node *node, int depth ) if( node->flags & XT_COMPLETE && !( node->flags & XT_SEEN ) ) { - for( i = 0; xt->handlers[i].func; i ++ ) + if( xt->handlers ) for( i = 0; xt->handlers[i].func; i ++ ) { /* This one is fun! \o/ */ - /* If handler.name == NULL it means it should always match. */ + /* If handler.name == NULL it means it should always match. */ if( ( xt->handlers[i].name == NULL || - /* If it's not, compare. There should always be a name. */ + /* If it's not, compare. There should always be a name. */ g_strcasecmp( xt->handlers[i].name, node->name ) == 0 ) && - /* If handler.parent == NULL, it's a match. */ + /* If handler.parent == NULL, it's a match. */ ( xt->handlers[i].parent == NULL || - /* If there's a parent node, see if the name matches. */ + /* If there's a parent node, see if the name matches. */ ( node->parent ? g_strcasecmp( xt->handlers[i].parent, node->parent->name ) == 0 : - /* If there's no parent, the handler should mention as a parent. */ - g_strcasecmp( xt->handlers[i].parent, "" ) == 0 ) ) ) + /* If there's no parent, the handler should mention as a parent. */ + strcmp( xt->handlers[i].parent, "" ) == 0 ) ) ) { st = xt->handlers[i].func( node, xt->data ); diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c index 99db509c..ed0881d1 100644 --- a/protocols/msn/msn.c +++ b/protocols/msn/msn.c @@ -24,6 +24,7 @@ */ #include "nogaim.h" +#include "soap.h" #include "msn.h" int msn_chat_id; @@ -34,8 +35,11 @@ static char *set_eval_display_name( set_t *set, char *value ); static void msn_init( account_t *acc ) { - set_add( &acc->set, "display_name", NULL, set_eval_display_name, acc ); - set_add( &acc->set, "local_display_name", "false", set_eval_bool, acc ); + set_t *s; + + s = set_add( &acc->set, "display_name", NULL, set_eval_display_name, acc ); + s->flags |= ACC_SET_NOSAVE | ACC_SET_ONLINE_ONLY; + set_add( &acc->set, "mail_notifications", "false", set_eval_bool, acc ); set_add( &acc->set, "switchboard_keepalives", "false", set_eval_bool, acc ); @@ -202,11 +206,6 @@ static void msn_set_away( struct im_connection *ic, char *state, char *message ) return; } -static void msn_set_my_name( struct im_connection *ic, char *info ) -{ - msn_set_display_name( ic, info ); -} - static void msn_get_info(struct im_connection *ic, char *who) { /* Just make an URL and let the user fetch the info */ @@ -331,10 +330,9 @@ static char *set_eval_display_name( set_t *set, char *value ) { account_t *acc = set->data; struct im_connection *ic = acc->ic; - - /* Allow any name if we're offline. */ - if( ic == NULL ) - return value; + struct msn_data *md = ic->proto_data; + char buf[512]; + char *fn; if( strlen( value ) > 129 ) { @@ -342,10 +340,18 @@ static char *set_eval_display_name( set_t *set, char *value ) return NULL; } - /* Returning NULL would be better, because the server still has to - confirm the name change. However, it looks a bit confusing to the - user. */ - return msn_set_display_name( ic, value ) ? value : NULL; + msn_soap_addressbook_set_display_name( ic, value ); + + fn = g_malloc( strlen( value ) * 3 + 1 ); + strcpy( fn, value ); + http_encode( fn ); + g_snprintf( buf, sizeof( buf ), "PRP %d MFN %s\r\n", + ++md->trId, fn ); + g_free( fn ); + + /* Note: We don't actually know if the server accepted the new name, + and won't give proper feedback yet if it doesn't. */ + return msn_write( ic, buf, strlen( buf ) ) ? value : NULL; } static void msn_buddy_data_add( bee_user_t *bu ) @@ -374,7 +380,6 @@ void msn_initmodule() ret->away_states = msn_away_states; ret->set_away = msn_set_away; ret->get_info = msn_get_info; - ret->set_my_name = msn_set_my_name; ret->add_buddy = msn_add_buddy; ret->remove_buddy = msn_remove_buddy; ret->chat_msg = msn_chat_msg; diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h index 5c7949c9..1828cc8a 100644 --- a/protocols/msn/msn.h +++ b/protocols/msn/msn.h @@ -206,7 +206,6 @@ void msn_buddy_ask( struct im_connection *ic, char *handle, char *realname ); char *msn_findheader( char *text, char *header, int len ); char **msn_linesplit( char *line ); int msn_handler( struct msn_handler_data *h ); -char *msn_http_encode( const char *input ); void msn_msgq_purge( struct im_connection *ic, GSList **list ); gboolean msn_set_display_name( struct im_connection *ic, const char *rawname ); char *msn_p11_challenge( char *challenge ); diff --git a/protocols/msn/msn_util.c b/protocols/msn/msn_util.c index 3a19d92f..bd1bea42 100644 --- a/protocols/msn/msn_util.c +++ b/protocols/msn/msn_util.c @@ -60,7 +60,7 @@ int msn_logged_in( struct im_connection *ic ) int msn_buddy_list_add( struct im_connection *ic, const char *list, const char *who, const char *realname_, const char *group ) { struct msn_data *md = ic->proto_data; - char buf[1024], *realname, groupid[8]; + char buf[1024], realname[strlen(realname_)*3+1], groupid[8]; *groupid = '\0'; if( group ) @@ -93,9 +93,10 @@ int msn_buddy_list_add( struct im_connection *ic, const char *list, const char * if( l == NULL ) { - char *groupname = msn_http_encode( group ); + char groupname[strlen(group)+1]; + strcpy( groupname, group ); + http_encode( groupname ); g_snprintf( buf, sizeof( buf ), "ADG %d %s %d\r\n", ++md->trId, groupname, 0 ); - g_free( groupname ); return msn_write( ic, buf, strlen( buf ) ); } else @@ -108,9 +109,9 @@ int msn_buddy_list_add( struct im_connection *ic, const char *list, const char * } } - realname = msn_http_encode( realname_ ); + strcpy( realname, realname_ ); + http_encode( realname ); g_snprintf( buf, sizeof( buf ), "ADD %d %s %s %s%s\r\n", ++md->trId, list, who, realname, groupid ); - g_free( realname ); return msn_write( ic, buf, strlen( buf ) ); } @@ -379,32 +380,6 @@ int msn_handler( struct msn_handler_data *h ) return( 1 ); } -/* The difference between this function and the normal http_encode() function - is that this one escapes every 7-bit ASCII character because this is said - to avoid some lame server-side checks when setting a real-name. Also, - non-ASCII characters are not escaped because MSN servers don't seem to - appreciate that! */ -char *msn_http_encode( const char *input ) -{ - char *ret, *s; - int i; - - ret = s = g_new0( char, strlen( input ) * 3 + 1 ); - for( i = 0; input[i]; i ++ ) - if( input[i] & 128 ) - { - *s = input[i]; - s ++; - } - else - { - g_snprintf( s, 4, "%%%02X", input[i] ); - s += 3; - } - - return ret; -} - void msn_msgq_purge( struct im_connection *ic, GSList **list ) { struct msn_message *m; @@ -445,18 +420,6 @@ void msn_msgq_purge( struct im_connection *ic, GSList **list ) g_string_free( ret, TRUE ); } -gboolean msn_set_display_name( struct im_connection *ic, const char *rawname ) -{ - char *fn = msn_http_encode( rawname ); - struct msn_data *md = ic->proto_data; - char buf[1024]; - - g_snprintf( buf, sizeof( buf ), "REA %d %s %s\r\n", ++md->trId, ic->acc->user, fn ); - g_free( fn ); - - return msn_write( ic, buf, strlen( buf ) ) != 0; -} - /* Copied and heavily modified from http://tmsnc.sourceforge.net/chl.c */ char *msn_p11_challenge( char *challenge ) { diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index 0c067b8c..777a6ebd 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -34,7 +34,6 @@ static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition c static int msn_ns_command( gpointer data, char **cmd, int num_parts ); static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts ); -static gboolean msn_ns_got_display_name( struct im_connection *ic, char *name ); static void msn_ns_send_adl( struct im_connection *ic ); gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ) @@ -473,40 +472,6 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) imc_logout( ic, allow_reconnect ); return( 0 ); } -#if 0 - /* Discard this one completely for now since I don't care about the ack - and since MSN servers can apparently screw up the formatting. */ - else if( strcmp( cmd[0], "REA" ) == 0 ) - { - if( num_parts < 5 ) - { - imcb_error( ic, "Syntax error" ); - imc_logout( ic, TRUE ); - return( 0 ); - } - - if( g_strcasecmp( cmd[3], ic->acc->user ) == 0 ) - { - set_t *s; - - http_decode( cmd[4] ); - strncpy( ic->displayname, cmd[4], sizeof( ic->displayname ) ); - ic->displayname[sizeof(ic->displayname)-1] = 0; - - if( ( s = set_find( &ic->acc->set, "display_name" ) ) ) - { - g_free( s->value ); - s->value = g_strdup( cmd[4] ); - } - } - else - { - /* This is not supposed to happen, but let's handle it anyway... */ - http_decode( cmd[4] ); - imcb_rename_buddy( ic, cmd[3], cmd[4] ); - } - } -#endif else if( strcmp( cmd[0], "IPG" ) == 0 ) { imcb_error( ic, "Received IPG command, we don't handle them yet." ); @@ -800,48 +765,3 @@ static void msn_ns_send_adl( struct im_connection *ic ) g_free( adls ); xt_free_node( adl ); } - -static gboolean msn_ns_got_display_name( struct im_connection *ic, char *name ) -{ - set_t *s; - - if( ( s = set_find( &ic->acc->set, "display_name" ) ) == NULL ) - return FALSE; /* Shouldn't happen.. */ - - http_decode( name ); - - if( s->value && strcmp( s->value, name ) == 0 ) - { - return TRUE; - /* The names match, nothing to worry about. */ - } - else if( s->value != NULL && - ( strcmp( name, ic->acc->user ) == 0 || - set_getbool( &ic->acc->set, "local_display_name" ) ) ) - { - /* The server thinks our display name is our e-mail address - which is probably wrong, or the user *wants* us to do this: - Always use the locally set display_name. */ - return msn_set_display_name( ic, s->value ); - } - else - { - if( s->value && *s->value ) - imcb_log( ic, "BitlBee thinks your display name is `%s' but " - "the MSN server says it's `%s'. Using the MSN " - "server's name. Set local_display_name to true " - "to use the local name.", s->value, name ); - - if( g_utf8_validate( name, -1, NULL ) ) - { - g_free( s->value ); - s->value = g_strdup( name ); - } - else - { - imcb_log( ic, "Warning: Friendly name in server response was corrupted" ); - } - - return TRUE; - } -} diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c index 5eae3089..cd54858f 100644 --- a/protocols/msn/soap.c +++ b/protocols/msn/soap.c @@ -608,3 +608,37 @@ int msn_soap_addressbook_request( struct im_connection *ic ) msn_soap_addressbook_handle_response, msn_soap_addressbook_free_data ); } + +/* Variant: Change our display name. */ +static int msn_soap_ab_namechange_build_request( struct msn_soap_req_data *soap_req ) +{ + struct msn_data *md = soap_req->ic->proto_data; + + soap_req->url = g_strdup( SOAP_ADDRESSBOOK_URL ); + soap_req->action = g_strdup( SOAP_AB_NAMECHANGE_ACTION ); + soap_req->payload = g_markup_printf_escaped( SOAP_AB_NAMECHANGE_PAYLOAD, + md->tokens[1], (char *) soap_req->data ); + + return 1; +} + +static int msn_soap_ab_namechange_handle_response( struct msn_soap_req_data *soap_req ) +{ + /* TODO: Ack the change? Not sure what the NAKs look like.. */ + return MSN_SOAP_OK; +} + +static int msn_soap_ab_namechange_free_data( struct msn_soap_req_data *soap_req ) +{ + g_free( soap_req->data ); + return 0; +} + +int msn_soap_addressbook_set_display_name( struct im_connection *ic, const char *new ) +{ + return msn_soap_start( ic, g_strdup( new ), + msn_soap_ab_namechange_build_request, + NULL, + msn_soap_ab_namechange_handle_response, + msn_soap_ab_namechange_free_data ); +} diff --git a/protocols/msn/soap.h b/protocols/msn/soap.h index 14b0624b..5673583a 100644 --- a/protocols/msn/soap.h +++ b/protocols/msn/soap.h @@ -219,7 +219,40 @@ int msn_soap_memlist_request( struct im_connection *ic ); "
" \ "" +#define SOAP_AB_NAMECHANGE_ACTION "http://www.msn.com/webservices/AddressBook/ABContactUpdate" + +#define SOAP_AB_NAMECHANGE_PAYLOAD \ +"" \ +"" \ + "" \ + "" \ + "CFE80F9D-180F-4399-82AB-413F33A1FA11" \ + "false" \ + "Initial" \ + "" \ + "" \ + "false" \ + "%s" \ + "" \ + "" \ + "" \ + "" \ + "00000000-0000-0000-0000-000000000000" \ + "" \ + "" \ + "" \ + "Me" \ + "%s" \ + "" \ + "DisplayName" \ + "" \ + "" \ + "" \ + "" \ +"" + int msn_soap_addressbook_request( struct im_connection *ic ); +int msn_soap_addressbook_set_display_name( struct im_connection *ic, const char *new ); #endif /* __SOAP_H__ */ diff --git a/protocols/nogaim.h b/protocols/nogaim.h index be67bb24..90254508 100644 --- a/protocols/nogaim.h +++ b/protocols/nogaim.h @@ -193,6 +193,8 @@ struct prpl { /* Request profile info. Free-formatted stuff, the IM module gives back this info via imcb_log(). Implementing these are optional. */ void (* get_info) (struct im_connection *, char *who); + /* set_my_name is *DEPRECATED*, not used by the UI anymore. Use the + display_name setting instead. */ void (* set_my_name) (struct im_connection *, char *name); void (* set_name) (struct im_connection *, char *who, char *name); diff --git a/storage_xml.c b/storage_xml.c index 1d6757ae..5035e214 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -319,6 +319,16 @@ static void xml_text( GMarkupParseContext *ctx, const gchar *text_orig, gsize te } else if( g_strcasecmp( g_markup_parse_context_get_element( ctx ), "setting" ) == 0 && xd->current_setting ) { + if( xd->current_account ) + { + set_t *s = set_find( xd->current_set_head, xd->current_setting ); + if( s && ( s->flags & ACC_SET_ONLINE_ONLY ) ) + { + g_free( xd->current_setting ); + xd->current_setting = NULL; + return; + } + } set_setstr( xd->current_set_head, xd->current_setting, (char*) text ); g_free( xd->current_setting ); xd->current_setting = NULL; -- cgit v1.2.3 From 584867592546f43f857645e02169d135f0df25e8 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 14 Aug 2010 14:32:46 +0100 Subject: The contact's full name is in a different field now in NLN messages. --- protocols/msn/ns.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index 777a6ebd..a1b88ae1 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -347,8 +347,8 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) return( 0 ); } - http_decode( cmd[3] ); - imcb_rename_buddy( ic, cmd[2], cmd[3] ); + http_decode( cmd[4] ); + imcb_rename_buddy( ic, cmd[2], cmd[4] ); st = msn_away_state_by_code( cmd[1] ); if( !st ) -- cgit v1.2.3 From e5854a80111e337be01cf1e506073a231fac1c3d Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 14 Aug 2010 15:50:10 +0100 Subject: Show incoming auth. requests (although responding to them currently causes a disconnect). --- protocols/msn/msn.h | 2 +- protocols/msn/msn_util.c | 19 ++++++--- protocols/msn/ns.c | 109 ++++++++++++++++++++++++++++------------------- protocols/msn/soap.c | 8 ++++ 4 files changed, 85 insertions(+), 53 deletions(-) diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h index 1828cc8a..d9609189 100644 --- a/protocols/msn/msn.h +++ b/protocols/msn/msn.h @@ -202,7 +202,7 @@ int msn_write( struct im_connection *ic, char *s, int len ); int msn_logged_in( struct im_connection *ic ); int msn_buddy_list_add( struct im_connection *ic, const char *list, const char *who, const char *realname_, const char *group ); int msn_buddy_list_remove( struct im_connection *ic, char *list, const char *who, const char *group ); -void msn_buddy_ask( struct im_connection *ic, char *handle, char *realname ); +void msn_buddy_ask( bee_user_t *bu ); char *msn_findheader( char *text, char *header, int len ); char **msn_linesplit( char *line ); int msn_handler( struct msn_handler_data *h ); diff --git a/protocols/msn/msn_util.c b/protocols/msn/msn_util.c index bd1bea42..6a5afd93 100644 --- a/protocols/msn/msn_util.c +++ b/protocols/msn/msn_util.c @@ -171,19 +171,24 @@ static void msn_buddy_ask_no( void *data ) g_free( bla ); } -void msn_buddy_ask( struct im_connection *ic, char *handle, char *realname ) +void msn_buddy_ask( bee_user_t *bu ) { - struct msn_buddy_ask_data *bla = g_new0( struct msn_buddy_ask_data, 1 ); + struct msn_buddy_ask_data *bla; + struct msn_buddy_data *bd = bu->data; char buf[1024]; - bla->ic = ic; - bla->handle = g_strdup( handle ); - bla->realname = g_strdup( realname ); + if( ( bd->flags & 30 ) != 8 && ( bd->flags & 30 ) != 16 ) + return; + + bla = g_new0( struct msn_buddy_ask_data, 1 ); + bla->ic = bu->ic; + bla->handle = g_strdup( bu->handle ); + bla->realname = g_strdup( bu->fullname ); g_snprintf( buf, sizeof( buf ), "The user %s (%s) wants to add you to his/her buddy list.", - handle, realname ); - imcb_ask( ic, buf, bla, msn_buddy_ask_yes, msn_buddy_ask_no ); + bu->handle, bu->fullname ); + imcb_ask( bu->ic, buf, bla, msn_buddy_ask_yes, msn_buddy_ask_no ); } char *msn_findheader( char *text, char *header, int len ) diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index a1b88ae1..7518dc25 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -278,6 +278,10 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) msn_write( ic, buf, strlen( buf ) ); } + else if( num_parts >= 3 ) + { + md->handler->msglen = atoi( cmd[2] ); + } } else if( strcmp( cmd[0], "PRP" ) == 0 ) { @@ -411,46 +415,6 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) sb->who = g_strdup( cmd[5] ); } } - else if( strcmp( cmd[0], "ADD" ) == 0 ) - { - if( num_parts >= 6 && strcmp( cmd[2], "RL" ) == 0 ) - { - GSList *l; - - http_decode( cmd[5] ); - - if( strchr( cmd[4], '@' ) == NULL ) - { - imcb_error( ic, "Syntax error" ); - imc_logout( ic, TRUE ); - return 0; - } - - /* We got added by someone. If we don't have this - person in permit/deny yet, inform the user. */ - for( l = ic->permit; l; l = l->next ) - if( g_strcasecmp( l->data, cmd[4] ) == 0 ) - return 1; - - for( l = ic->deny; l; l = l->next ) - if( g_strcasecmp( l->data, cmd[4] ) == 0 ) - return 1; - - msn_buddy_ask( ic, cmd[4], cmd[5] ); - } - else if( num_parts >= 6 && strcmp( cmd[2], "FL" ) == 0 ) - { - const char *group = NULL; - int num; - - if( cmd[6] != NULL && sscanf( cmd[6], "%d", &num ) == 1 && num < md->groupcount ) - group = md->grouplist[num]; - - http_decode( cmd[5] ); - imcb_add_buddy( ic, cmd[4], group ); - imcb_rename_buddy( ic, cmd[4], cmd[5] ); - } - } else if( strcmp( cmd[0], "OUT" ) == 0 ) { int allow_reconnect = TRUE; @@ -485,6 +449,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) return( 0 ); } } +#if 0 else if( strcmp( cmd[0], "ADG" ) == 0 ) { char *group = g_strdup( cmd[3] ); @@ -529,6 +494,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) } } } +#endif else if( strcmp( cmd[0], "GCF" ) == 0 ) { /* Coming up is cmd[2] bytes of stuff we're supposed to @@ -537,16 +503,16 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) } else if( strcmp( cmd[0], "UBX" ) == 0 ) { - /* Status message. Parser coming soon. */ + /* Status message. */ if( num_parts >= 4 ) md->handler->msglen = atoi( cmd[3] ); } else if( strcmp( cmd[0], "NOT" ) == 0 ) { - /* Some kind of notification, not sure if it still exists - but we have to skip the payload or stuff breaks. */ - if( num_parts >= 3 ) - md->handler->msglen = atoi( cmd[2] ); + /* Some kind of notification, poorly documented but + apparently used to announce address book changes. */ + if( num_parts >= 2 ) + md->handler->msglen = atoi( cmd[1] ); } else if( isdigit( cmd[0][0] ) ) { @@ -670,6 +636,56 @@ static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int imcb_buddy_status_msg( ic, cmd[1], psm_text ); xt_free_node( psm ); } + else if( strcmp( cmd[0], "ADL" ) == 0 ) + { + struct xt_node *adl, *d, *c; + + if( !( adl = xt_from_string( msg ) ) ) + return 1; + + for( d = adl->children; d; d = d->next ) + { + char *dn; + if( strcmp( d->name, "d" ) != 0 || + ( dn = xt_find_attr( d, "n" ) ) == NULL ) + continue; + for( c = d->children; c; c = c->next ) + { + bee_user_t *bu; + struct msn_buddy_data *bd; + char *cn, *handle, *f, *l; + int flags; + + if( strcmp( c->name, "c" ) != 0 || + ( l = xt_find_attr( c, "l" ) ) == NULL || + ( cn = xt_find_attr( c, "n" ) ) == NULL ) + continue; + + handle = g_strdup_printf( "%s@%s", cn, dn ); + if( !( ( bu = bee_user_by_handle( ic->bee, ic, handle ) ) || + ( bu = bee_user_new( ic->bee, ic, handle, 0 ) ) ) ) + { + g_free( handle ); + continue; + } + g_free( handle ); + bd = bu->data; + + if( ( f = xt_find_attr( c, "f" ) ) ) + { + http_decode( f ); + imcb_rename_buddy( ic, bu->handle, f ); + } + + flags = atoi( l ) & 15; + if( bd->flags != flags ) + { + bd->flags = flags; + msn_buddy_ask( bu ); + } + } + } + } return( 1 ); } @@ -717,6 +733,9 @@ static gboolean msn_ns_send_adl_1( gpointer key, gpointer value, gpointer data ) char *domain; char l[4]; + if( ( bd->flags & 7 ) == 0 ) + return FALSE; + strcpy( handle, bu->handle ); if( ( domain = strchr( handle, '@' ) ) == NULL ) /* WTF */ return FALSE; diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c index cd54858f..8cc241b8 100644 --- a/protocols/msn/soap.c +++ b/protocols/msn/soap.c @@ -476,9 +476,17 @@ static xt_status msn_soap_memlist_member( struct xt_node *node, gpointer data ) else if( strcmp( role, "Block" ) == 0 ) bd->flags |= MSN_BUDDY_BL; else if( strcmp( role, "Reverse" ) == 0 ) + { bd->flags |= MSN_BUDDY_RL; + msn_buddy_ask( bu ); + } else if( strcmp( role, "Pending" ) == 0 ) + { bd->flags |= MSN_BUDDY_PL; + msn_buddy_ask( bu ); + } + + printf( "%s %d\n", handle, bd->flags ); return XT_HANDLED; } -- cgit v1.2.3 From 193dc742d357bb604fff8921417c74ddf9e8729c Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 14 Aug 2010 17:16:52 +0100 Subject: Responses to add requests work now. --- protocols/msn/msn.c | 14 ++++----- protocols/msn/msn.h | 4 +-- protocols/msn/msn_util.c | 74 ++++++++++++++++++++++++++++++++++++------- protocols/msn/ns.c | 7 +++-- protocols/msn/soap.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++ protocols/msn/soap.h | 41 ++++++++++++++++++++++++ 6 files changed, 198 insertions(+), 23 deletions(-) diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c index ed0881d1..679ac65e 100644 --- a/protocols/msn/msn.c +++ b/protocols/msn/msn.c @@ -216,14 +216,14 @@ static void msn_add_buddy( struct im_connection *ic, char *who, char *group ) { struct bee_user *bu = bee_user_by_handle( ic->bee, ic, who ); - msn_buddy_list_add( ic, "FL", who, who, group ); + msn_buddy_list_add( ic, MSN_BUDDY_FL, who, who, group ); if( bu && bu->group ) - msn_buddy_list_remove( ic, "FL", who, bu->group->name ); + msn_buddy_list_remove( ic, MSN_BUDDY_FL, who, bu->group->name ); } static void msn_remove_buddy( struct im_connection *ic, char *who, char *group ) { - msn_buddy_list_remove( ic, "FL", who, NULL ); + msn_buddy_list_remove( ic, MSN_BUDDY_FL, who, NULL ); } static void msn_chat_msg( struct groupchat *c, char *message, int flags ) @@ -288,19 +288,19 @@ static void msn_keepalive( struct im_connection *ic ) static void msn_add_permit( struct im_connection *ic, char *who ) { - msn_buddy_list_add( ic, "AL", who, who, NULL ); + msn_buddy_list_add( ic, MSN_BUDDY_AL, who, who, NULL ); } static void msn_rem_permit( struct im_connection *ic, char *who ) { - msn_buddy_list_remove( ic, "AL", who, NULL ); + msn_buddy_list_remove( ic, MSN_BUDDY_AL, who, NULL ); } static void msn_add_deny( struct im_connection *ic, char *who ) { struct msn_switchboard *sb; - msn_buddy_list_add( ic, "BL", who, who, NULL ); + msn_buddy_list_add( ic, MSN_BUDDY_BL, who, who, NULL ); /* If there's still a conversation with this person, close it. */ if( ( sb = msn_sb_by_handle( ic, who ) ) ) @@ -311,7 +311,7 @@ static void msn_add_deny( struct im_connection *ic, char *who ) static void msn_rem_deny( struct im_connection *ic, char *who ) { - msn_buddy_list_remove( ic, "BL", who, NULL ); + msn_buddy_list_remove( ic, MSN_BUDDY_BL, who, NULL ); } static int msn_send_typing( struct im_connection *ic, char *who, int typing ) diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h index d9609189..862d1ef7 100644 --- a/protocols/msn/msn.h +++ b/protocols/msn/msn.h @@ -200,8 +200,8 @@ void msn_auth_got_contact_list( struct im_connection *ic ); /* msn_util.c */ int msn_write( struct im_connection *ic, char *s, int len ); int msn_logged_in( struct im_connection *ic ); -int msn_buddy_list_add( struct im_connection *ic, const char *list, const char *who, const char *realname_, const char *group ); -int msn_buddy_list_remove( struct im_connection *ic, char *list, const char *who, const char *group ); +int msn_buddy_list_add( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *realname_, const char *group ); +int msn_buddy_list_remove( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group ); void msn_buddy_ask( bee_user_t *bu ); char *msn_findheader( char *text, char *header, int len ); char **msn_linesplit( char *line ); diff --git a/protocols/msn/msn_util.c b/protocols/msn/msn_util.c index 6a5afd93..54bfad7f 100644 --- a/protocols/msn/msn_util.c +++ b/protocols/msn/msn_util.c @@ -26,6 +26,7 @@ #include "nogaim.h" #include "msn.h" #include "md5.h" +#include "soap.h" #include int msn_write( struct im_connection *ic, char *s, int len ) @@ -57,12 +58,31 @@ int msn_logged_in( struct im_connection *ic ) return( 0 ); } -int msn_buddy_list_add( struct im_connection *ic, const char *list, const char *who, const char *realname_, const char *group ) +static char *adlrml_entry( const char *handle_, msn_buddy_flags_t list ) +{ + char *domain, handle[strlen(handle_)+1]; + + strcpy( handle, handle_ ); + if( ( domain = strchr( handle, '@' ) ) ) + *(domain + ++) = '\0'; + else + return NULL; + + return g_markup_printf_escaped( "", + domain, handle, list ); +} + +int msn_buddy_list_add( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *realname_, const char *group ) { struct msn_data *md = ic->proto_data; - char buf[1024], realname[strlen(realname_)*3+1], groupid[8]; + char buf[1024], groupid[8]; + bee_user_t *bu; + struct msn_buddy_data *bd; + char *adl; *groupid = '\0'; +#if 0 if( group ) { int i; @@ -108,20 +128,36 @@ int msn_buddy_list_add( struct im_connection *ic, const char *list, const char * } } } +#endif + + if( !( bu = bee_user_by_handle( ic->bee, ic, who ) ) || + !( bd = bu->data ) || bd->flags & list ) + return 1; - strcpy( realname, realname_ ); - http_encode( realname ); - g_snprintf( buf, sizeof( buf ), "ADD %d %s %s %s%s\r\n", ++md->trId, list, who, realname, groupid ); + bd->flags |= list; - return msn_write( ic, buf, strlen( buf ) ); + msn_soap_memlist_edit( ic, who, TRUE, list ); + + if( ( adl = adlrml_entry( who, list ) ) ) + { + g_snprintf( buf, sizeof( buf ), "ADL %d %zd\r\n%s", + ++md->trId, strlen( adl ), adl ); + g_free( adl ); + + return msn_write( ic, buf, strlen( buf ) ); + } } -int msn_buddy_list_remove( struct im_connection *ic, char *list, const char *who, const char *group ) +int msn_buddy_list_remove( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group ) { struct msn_data *md = ic->proto_data; char buf[1024], groupid[8]; + bee_user_t *bu; + struct msn_buddy_data *bd; + char *adl; *groupid = '\0'; +#if 0 if( group ) { int i; @@ -132,10 +168,24 @@ int msn_buddy_list_remove( struct im_connection *ic, char *list, const char *who break; } } +#endif + + if( !( bu = bee_user_by_handle( ic->bee, ic, who ) ) || + !( bd = bu->data ) || !( bd->flags & list ) ) + return 1; + + bd->flags &= ~list; - g_snprintf( buf, sizeof( buf ), "REM %d %s %s%s\r\n", ++md->trId, list, who, groupid ); - if( msn_write( ic, buf, strlen( buf ) ) ) - return( 1 ); + msn_soap_memlist_edit( ic, who, FALSE, list ); + + if( ( adl = adlrml_entry( who, list ) ) ) + { + g_snprintf( buf, sizeof( buf ), "RML %d %zd\r\n%s", + ++md->trId, strlen( adl ), adl ); + g_free( adl ); + + return msn_write( ic, buf, strlen( buf ) ); + } return( 0 ); } @@ -151,7 +201,7 @@ static void msn_buddy_ask_yes( void *data ) { struct msn_buddy_ask_data *bla = data; - msn_buddy_list_add( bla->ic, "AL", bla->handle, bla->realname, NULL ); + msn_buddy_list_add( bla->ic, MSN_BUDDY_AL, bla->handle, bla->realname, NULL ); imcb_ask_add( bla->ic, bla->handle, NULL ); @@ -164,7 +214,7 @@ static void msn_buddy_ask_no( void *data ) { struct msn_buddy_ask_data *bla = data; - msn_buddy_list_add( bla->ic, "BL", bla->handle, bla->realname, NULL ); + msn_buddy_list_add( bla->ic, MSN_BUDDY_BL, bla->handle, bla->realname, NULL ); g_free( bla->handle ); g_free( bla->realname ); diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index 7518dc25..23b8f3b1 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -263,10 +263,13 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( num_parts >= 3 && strcmp( cmd[2], "OK" ) == 0 ) { char buf[1024]; - char *fn_raw = set_getstr( &ic->acc->set, "display_name" ); + char *fn_raw; char *fn; - if( fn_raw == NULL ) + if( ic->flags & OPT_LOGGED_IN ) + return 1; + + if( ( fn_raw = set_getstr( &ic->acc->set, "display_name" ) ) == NULL ) fn_raw = ic->acc->user; fn = g_malloc( strlen( fn_raw ) * 3 + 1 ); strcpy( fn, fn_raw ); diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c index 8cc241b8..93bb37a6 100644 --- a/protocols/msn/soap.c +++ b/protocols/msn/soap.c @@ -516,6 +516,87 @@ int msn_soap_memlist_request( struct im_connection *ic ) msn_soap_memlist_free_data ); } +/* Variant: Adding/Removing people */ +struct msn_soap_memlist_edit_data +{ + char *handle; + gboolean add; + msn_buddy_flags_t list; +}; + +static int msn_soap_memlist_edit_build_request( struct msn_soap_req_data *soap_req ) +{ + struct msn_data *md = soap_req->ic->proto_data; + struct msn_soap_memlist_edit_data *med = soap_req->data; + char *add, *scenario, *list; + + soap_req->url = g_strdup( SOAP_MEMLIST_URL ); + if( med->add ) + { + soap_req->action = g_strdup( SOAP_MEMLIST_ADD_ACTION ); + add = "Add"; + } + else + { + soap_req->action = g_strdup( SOAP_MEMLIST_DEL_ACTION ); + add = "Delete"; + } + switch( med->list ) + { + case MSN_BUDDY_AL: + scenario = "BlockUnblock"; + list = "Allow"; + break; + case MSN_BUDDY_BL: + scenario = "BlockUnblock"; + list = "Block"; + break; + case MSN_BUDDY_RL: + scenario = "Timer"; + list = "Reverse"; + break; + case MSN_BUDDY_PL: + default: + scenario = "Timer"; + list = "Pending"; + break; + } + soap_req->payload = g_markup_printf_escaped( SOAP_MEMLIST_EDIT_PAYLOAD, + scenario, md->tokens[1], add, list, med->handle, add ); + + return 1; +} + +static int msn_soap_memlist_edit_handle_response( struct msn_soap_req_data *soap_req ) +{ + return MSN_SOAP_OK; +} + +static int msn_soap_memlist_edit_free_data( struct msn_soap_req_data *soap_req ) +{ + struct msn_soap_memlist_edit_data *med = soap_req->data; + + g_free( med->handle ); + g_free( med ); + + return 0; +} + +int msn_soap_memlist_edit( struct im_connection *ic, const char *handle, gboolean add, int list ) +{ + struct msn_soap_memlist_edit_data *med; + + med = g_new0( struct msn_soap_memlist_edit_data, 1 ); + med->handle = g_strdup( handle ); + med->add = add; + med->list = list; + + return msn_soap_start( ic, med, msn_soap_memlist_edit_build_request, + NULL, + msn_soap_memlist_edit_handle_response, + msn_soap_memlist_edit_free_data ); +} + /* addressbook: Fetching the membership list (NOT address book) */ diff --git a/protocols/msn/soap.h b/protocols/msn/soap.h index 5673583a..9ef68df9 100644 --- a/protocols/msn/soap.h +++ b/protocols/msn/soap.h @@ -189,7 +189,48 @@ int msn_soap_oim_send_queue( struct im_connection *ic, GSList **msgq ); "
" \ "" +#define SOAP_MEMLIST_ADD_ACTION "http://www.msn.com/webservices/AddressBook/AddMember" +#define SOAP_MEMLIST_DEL_ACTION "http://www.msn.com/webservices/AddressBook/DeleteMember" + +#define SOAP_MEMLIST_EDIT_PAYLOAD \ +"" \ +"" \ + "" \ + "" \ + "CFE80F9D-180F-4399-82AB-413F33A1FA11" \ + "false" \ + "%s" \ + "" \ + "" \ + "false" \ + "%s" \ + "" \ + "" \ + "" \ + "<%sMember xmlns=\"http://www.msn.com/webservices/AddressBook\">" \ + "" \ + "0" \ + "Messenger" \ + "" \ + "" \ + "" \ + "" \ + "%s" \ + "" \ + "" \ + "Passport" \ + "Accepted" \ + "%s" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ +"" + int msn_soap_memlist_request( struct im_connection *ic ); +int msn_soap_memlist_edit( struct im_connection *ic, const char *handle, gboolean add, int list ); #define SOAP_ADDRESSBOOK_URL "http://contacts.msn.com/abservice/abservice.asmx" -- cgit v1.2.3 From 6ddb2236943384d45cacd08e02cb4ef9ed03bba3 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 14 Aug 2010 20:57:13 +0100 Subject: Separate boilerplate and body of abservice SOAP requests since the former's the same all the time (and I have to add some more request types). --- protocols/msn/msn_util.c | 4 ++- protocols/msn/soap.c | 28 +++++++++++++++---- protocols/msn/soap.h | 71 +++++++++--------------------------------------- 3 files changed, 39 insertions(+), 64 deletions(-) diff --git a/protocols/msn/msn_util.c b/protocols/msn/msn_util.c index 54bfad7f..b7fdda28 100644 --- a/protocols/msn/msn_util.c +++ b/protocols/msn/msn_util.c @@ -146,6 +146,8 @@ int msn_buddy_list_add( struct im_connection *ic, msn_buddy_flags_t list, const return msn_write( ic, buf, strlen( buf ) ); } + + return 1; } int msn_buddy_list_remove( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group ) @@ -187,7 +189,7 @@ int msn_buddy_list_remove( struct im_connection *ic, msn_buddy_flags_t list, con return msn_write( ic, buf, strlen( buf ) ); } - return( 0 ); + return 1; } struct msn_buddy_ask_data diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c index 93bb37a6..130df840 100644 --- a/protocols/msn/soap.c +++ b/protocols/msn/soap.c @@ -146,6 +146,24 @@ static void msn_soap_handle_response( struct http_request *http_req ) } } +static char *msn_soap_abservice_build( const char *body_fmt, const char *scenario, const char *ticket, ... ) +{ + va_list params; + char *ret, *format, *body; + + format = g_markup_printf_escaped( SOAP_ABSERVICE_PAYLOAD, scenario, ticket ); + + va_start( params, ticket ); + body = g_strdup_vprintf( body_fmt, params ); + va_end( params ); + + ret = g_strdup_printf( format, body ); + g_free( body ); + g_free( format ); + + return ret; +} + /* passport_sso: Authentication MSNP15+ */ @@ -444,7 +462,7 @@ static int msn_soap_memlist_build_request( struct msn_soap_req_data *soap_req ) soap_req->url = g_strdup( SOAP_MEMLIST_URL ); soap_req->action = g_strdup( SOAP_MEMLIST_ACTION ); - soap_req->payload = g_markup_printf_escaped( SOAP_MEMLIST_PAYLOAD, md->tokens[1] ); + soap_req->payload = msn_soap_abservice_build( SOAP_MEMLIST_PAYLOAD, "Initial", md->tokens[1] ); return 1; } @@ -561,7 +579,7 @@ static int msn_soap_memlist_edit_build_request( struct msn_soap_req_data *soap_r list = "Pending"; break; } - soap_req->payload = g_markup_printf_escaped( SOAP_MEMLIST_EDIT_PAYLOAD, + soap_req->payload = msn_soap_abservice_build( SOAP_MEMLIST_EDIT_PAYLOAD, scenario, md->tokens[1], add, list, med->handle, add ); return 1; @@ -606,7 +624,7 @@ static int msn_soap_addressbook_build_request( struct msn_soap_req_data *soap_re soap_req->url = g_strdup( SOAP_ADDRESSBOOK_URL ); soap_req->action = g_strdup( SOAP_ADDRESSBOOK_ACTION ); - soap_req->payload = g_markup_printf_escaped( SOAP_ADDRESSBOOK_PAYLOAD, md->tokens[1] ); + soap_req->payload = msn_soap_abservice_build( SOAP_ADDRESSBOOK_PAYLOAD, "Initial", md->tokens[1] ); return 1; } @@ -705,8 +723,8 @@ static int msn_soap_ab_namechange_build_request( struct msn_soap_req_data *soap_ soap_req->url = g_strdup( SOAP_ADDRESSBOOK_URL ); soap_req->action = g_strdup( SOAP_AB_NAMECHANGE_ACTION ); - soap_req->payload = g_markup_printf_escaped( SOAP_AB_NAMECHANGE_PAYLOAD, - md->tokens[1], (char *) soap_req->data ); + soap_req->payload = msn_soap_abservice_build( SOAP_AB_NAMECHANGE_PAYLOAD, + "Initial", md->tokens[1], (char *) soap_req->data ); return 1; } diff --git a/protocols/msn/soap.h b/protocols/msn/soap.h index 9ef68df9..8ce893df 100644 --- a/protocols/msn/soap.h +++ b/protocols/msn/soap.h @@ -166,17 +166,14 @@ int msn_soap_oim_send( struct im_connection *ic, const char *to, const char *msg int msn_soap_oim_send_queue( struct im_connection *ic, GSList **msgq ); -#define SOAP_MEMLIST_URL "http://contacts.msn.com/abservice/SharingService.asmx" -#define SOAP_MEMLIST_ACTION "http://www.msn.com/webservices/AddressBook/FindMembership" - -#define SOAP_MEMLIST_PAYLOAD \ +#define SOAP_ABSERVICE_PAYLOAD \ "" \ "" \ "" \ "" \ "CFE80F9D-180F-4399-82AB-413F33A1FA11" \ "false" \ - "Initial" \ + "%s" \ "" \ "" \ "false" \ @@ -184,29 +181,21 @@ int msn_soap_oim_send_queue( struct im_connection *ic, GSList **msgq ); "" \ "" \ "" \ - "MessengerInvitationSocialNetworkSpaceProfile" \ - "" \ + "%%s" \ "" \ "" +#define SOAP_MEMLIST_URL "http://contacts.msn.com/abservice/SharingService.asmx" +#define SOAP_MEMLIST_ACTION "http://www.msn.com/webservices/AddressBook/FindMembership" + +#define SOAP_MEMLIST_PAYLOAD \ + "MessengerInvitationSocialNetworkSpaceProfile" \ + "" + #define SOAP_MEMLIST_ADD_ACTION "http://www.msn.com/webservices/AddressBook/AddMember" #define SOAP_MEMLIST_DEL_ACTION "http://www.msn.com/webservices/AddressBook/DeleteMember" #define SOAP_MEMLIST_EDIT_PAYLOAD \ -"" \ -"" \ - "" \ - "" \ - "CFE80F9D-180F-4399-82AB-413F33A1FA11" \ - "false" \ - "%s" \ - "" \ - "" \ - "false" \ - "%s" \ - "" \ - "" \ - "" \ "<%sMember xmlns=\"http://www.msn.com/webservices/AddressBook\">" \ "" \ "0" \ @@ -225,9 +214,7 @@ int msn_soap_oim_send_queue( struct im_connection *ic, GSList **msgq ); "" \ "" \ "" \ - "" \ - "" \ -"" + "" int msn_soap_memlist_request( struct im_connection *ic ); int msn_soap_memlist_edit( struct im_connection *ic, const char *handle, gboolean add, int list ); @@ -237,46 +224,16 @@ int msn_soap_memlist_edit( struct im_connection *ic, const char *handle, gboolea #define SOAP_ADDRESSBOOK_ACTION "http://www.msn.com/webservices/AddressBook/ABFindAll" #define SOAP_ADDRESSBOOK_PAYLOAD \ -"" \ -"" \ - "" \ - "" \ - "CFE80F9D-180F-4399-82AB-413F33A1FA11" \ - "false" \ - "Initial" \ - "" \ - "" \ - "false" \ - "%s" \ - "" \ - "" \ - "" \ "" \ "00000000-0000-0000-0000-000000000000" \ "Full" \ "false" \ "0001-01-01T00:00:00.0000000-08:00" \ - "" \ - "" \ -"" + "" #define SOAP_AB_NAMECHANGE_ACTION "http://www.msn.com/webservices/AddressBook/ABContactUpdate" #define SOAP_AB_NAMECHANGE_PAYLOAD \ -"" \ -"" \ - "" \ - "" \ - "CFE80F9D-180F-4399-82AB-413F33A1FA11" \ - "false" \ - "Initial" \ - "" \ - "" \ - "false" \ - "%s" \ - "" \ - "" \ - "" \ "" \ "00000000-0000-0000-0000-000000000000" \ "" \ @@ -288,9 +245,7 @@ int msn_soap_memlist_edit( struct im_connection *ic, const char *handle, gboolea "DisplayName" \ "" \ "" \ - "" \ - "" \ -"" + "" int msn_soap_addressbook_request( struct im_connection *ic ); int msn_soap_addressbook_set_display_name( struct im_connection *ic, const char *new ); -- cgit v1.2.3 From 4fc95c57361193c5338d9916fd37cc8a939067cd Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 14 Aug 2010 22:33:33 +0100 Subject: Add/Remove support. --- protocols/msn/msn_util.c | 15 ++++++--- protocols/msn/soap.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++ protocols/msn/soap.h | 37 ++++++++++++++++++++- protocols/msn/tables.c | 2 ++ 4 files changed, 135 insertions(+), 5 deletions(-) diff --git a/protocols/msn/msn_util.c b/protocols/msn/msn_util.c index b7fdda28..84d68b8c 100644 --- a/protocols/msn/msn_util.c +++ b/protocols/msn/msn_util.c @@ -73,7 +73,7 @@ static char *adlrml_entry( const char *handle_, msn_buddy_flags_t list ) domain, handle, list ); } -int msn_buddy_list_add( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *realname_, const char *group ) +int msn_buddy_list_add( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *realname, const char *group ) { struct msn_data *md = ic->proto_data; char buf[1024], groupid[8]; @@ -130,13 +130,17 @@ int msn_buddy_list_add( struct im_connection *ic, msn_buddy_flags_t list, const } #endif - if( !( bu = bee_user_by_handle( ic->bee, ic, who ) ) || + if( !( ( bu = bee_user_by_handle( ic->bee, ic, who ) ) || + ( bu = bee_user_new( ic->bee, ic, who, 0 ) ) ) || !( bd = bu->data ) || bd->flags & list ) return 1; bd->flags |= list; - msn_soap_memlist_edit( ic, who, TRUE, list ); + if( list == MSN_BUDDY_FL ) + msn_soap_ab_contact_add( ic, bu ); + else + msn_soap_memlist_edit( ic, who, TRUE, list ); if( ( adl = adlrml_entry( who, list ) ) ) { @@ -178,7 +182,10 @@ int msn_buddy_list_remove( struct im_connection *ic, msn_buddy_flags_t list, con bd->flags &= ~list; - msn_soap_memlist_edit( ic, who, FALSE, list ); + if( list == MSN_BUDDY_FL ) + msn_soap_ab_contact_del( ic, bu ); + else + msn_soap_memlist_edit( ic, who, FALSE, list ); if( ( adl = adlrml_entry( who, list ) ) ) { diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c index 130df840..13ef7e37 100644 --- a/protocols/msn/soap.c +++ b/protocols/msn/soap.c @@ -749,3 +749,89 @@ int msn_soap_addressbook_set_display_name( struct im_connection *ic, const char msn_soap_ab_namechange_handle_response, msn_soap_ab_namechange_free_data ); } + +/* Add a contact. */ +static int msn_soap_ab_contact_add_build_request( struct msn_soap_req_data *soap_req ) +{ + struct msn_data *md = soap_req->ic->proto_data; + bee_user_t *bu = soap_req->data; + + soap_req->url = g_strdup( SOAP_ADDRESSBOOK_URL ); + soap_req->action = g_strdup( SOAP_AB_CONTACT_ADD_ACTION ); + soap_req->payload = msn_soap_abservice_build( SOAP_AB_CONTACT_ADD_PAYLOAD, + "ContactSave", md->tokens[1], bu->handle, bu->fullname ? bu->fullname : bu->handle ); + + return 1; +} + +static xt_status msn_soap_ab_contact_add_cid( struct xt_node *node, gpointer data ) +{ + struct msn_soap_req_data *soap_req = data; + bee_user_t *bu = soap_req->data; + struct msn_buddy_data *bd = bu->data; + + g_free( bd->cid ); + bd->cid = g_strdup( node->text ); + + return XT_HANDLED; +} + +static const struct xt_handler_entry msn_soap_ab_contact_add_parser[] = { + { "guid", "ABContactAddResult", msn_soap_ab_contact_add_cid }, + { NULL, NULL, NULL } +}; + +static int msn_soap_ab_contact_add_handle_response( struct msn_soap_req_data *soap_req ) +{ + /* TODO: Ack the change? Not sure what the NAKs look like.. */ + return MSN_SOAP_OK; +} + +static int msn_soap_ab_contact_add_free_data( struct msn_soap_req_data *soap_req ) +{ + return 0; +} + +int msn_soap_ab_contact_add( struct im_connection *ic, bee_user_t *bu ) +{ + return msn_soap_start( ic, bu, + msn_soap_ab_contact_add_build_request, + msn_soap_ab_contact_add_parser, + msn_soap_ab_contact_add_handle_response, + msn_soap_ab_contact_add_free_data ); +} + +/* Remove a contact. */ +static int msn_soap_ab_contact_del_build_request( struct msn_soap_req_data *soap_req ) +{ + struct msn_data *md = soap_req->ic->proto_data; + bee_user_t *bu = soap_req->data; + struct msn_buddy_data *bd = bu->data; + + soap_req->url = g_strdup( SOAP_ADDRESSBOOK_URL ); + soap_req->action = g_strdup( SOAP_AB_CONTACT_DEL_ACTION ); + soap_req->payload = msn_soap_abservice_build( SOAP_AB_CONTACT_DEL_PAYLOAD, + "Timer", md->tokens[1], bd->cid ); + + return 1; +} + +static int msn_soap_ab_contact_del_handle_response( struct msn_soap_req_data *soap_req ) +{ + /* TODO: Ack the change? Not sure what the NAKs look like.. */ + return MSN_SOAP_OK; +} + +static int msn_soap_ab_contact_del_free_data( struct msn_soap_req_data *soap_req ) +{ + return 0; +} + +int msn_soap_ab_contact_del( struct im_connection *ic, bee_user_t *bu ) +{ + return msn_soap_start( ic, bu, + msn_soap_ab_contact_del_build_request, + NULL, + msn_soap_ab_contact_del_handle_response, + msn_soap_ab_contact_del_free_data ); +} diff --git a/protocols/msn/soap.h b/protocols/msn/soap.h index 8ce893df..19a5c6ae 100644 --- a/protocols/msn/soap.h +++ b/protocols/msn/soap.h @@ -247,8 +247,43 @@ int msn_soap_memlist_edit( struct im_connection *ic, const char *handle, gboolea "" \ "" +#define SOAP_AB_CONTACT_ADD_ACTION "http://www.msn.com/webservices/AddressBook/ABContactAdd" + +#define SOAP_AB_CONTACT_ADD_PAYLOAD \ + "" \ + "00000000-0000-0000-0000-000000000000" \ + "" \ + "" \ + "" \ + "LivePending" \ + "%s" \ + "true" \ + "" \ + "%s" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "true" \ + "" \ + "" + +#define SOAP_AB_CONTACT_DEL_ACTION "http://www.msn.com/webservices/AddressBook/ABContactDelete" + +#define SOAP_AB_CONTACT_DEL_PAYLOAD \ + "" \ + "00000000-0000-0000-0000-000000000000" \ + "" \ + "" \ + "%s" \ + "" \ + "" \ + "" + int msn_soap_addressbook_request( struct im_connection *ic ); int msn_soap_addressbook_set_display_name( struct im_connection *ic, const char *new ); - +int msn_soap_ab_contact_add( struct im_connection *ic, bee_user_t *bu ); +int msn_soap_ab_contact_del( struct im_connection *ic, bee_user_t *bu ); #endif /* __SOAP_H__ */ diff --git a/protocols/msn/tables.c b/protocols/msn/tables.c index fd7eca41..191abe43 100644 --- a/protocols/msn/tables.c +++ b/protocols/msn/tables.c @@ -82,6 +82,8 @@ const struct msn_status_code msn_status_code_list[] = { 229, "Group name too long", 0 }, { 230, "Cannot remove that group", 0 }, { 231, "Invalid group", 0 }, + { 240, "ADL/RML command with corrupted payload", STATUS_FATAL }, + { 241, "ADL/RML command with invalid modification", STATUS_FATAL }, { 280, "Switchboard failed", STATUS_SB_FATAL }, { 281, "Transfer to switchboard failed", 0 }, -- cgit v1.2.3 From d912fe4783cc9f5c2e7204f810df420359d5bee8 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 15 Aug 2010 00:00:53 +0100 Subject: Add xt_find_path() to simplify digging through multi-level XML trees. --- lib/xmltree.c | 40 ++++++++++++++++++++++++++++++++++++++++ lib/xmltree.h | 1 + 2 files changed, 41 insertions(+) diff --git a/lib/xmltree.c b/lib/xmltree.c index 5fd43014..20d69455 100644 --- a/lib/xmltree.c +++ b/lib/xmltree.c @@ -478,6 +478,46 @@ struct xt_node *xt_find_node( struct xt_node *node, const char *name ) return node; } +/* More advanced than the one above, understands something like + ../foo/bar to find a subnode bar of a node foo which is a child + of node's parent. Pass the node directly, not its list of children. */ +struct xt_node *xt_find_path( struct xt_node *node, const char *name ) +{ + while( name && *name && node ) + { + char *colon, *slash; + int n; + + if( ( slash = strchr( name, '/' ) ) ) + n = slash - name; + else + n = strlen( name ); + + if( strncmp( name, "..", n ) == 0 ) + { + node = node->parent; + } + else + { + node = node->children; + + while( node ) + { + if( g_strncasecmp( node->name, name, n ) == 0 || + ( ( colon = strchr( node->name, ':' ) ) && + g_strncasecmp( colon + 1, name, n ) == 0 ) ) + break; + + node = node->next; + } + } + + name = slash ? slash + 1 : NULL; + } + + return node; +} + char *xt_find_attr( struct xt_node *node, const char *key ) { int i; diff --git a/lib/xmltree.h b/lib/xmltree.h index c1697ff5..5a0dbc8e 100644 --- a/lib/xmltree.h +++ b/lib/xmltree.h @@ -88,6 +88,7 @@ struct xt_node *xt_dup( struct xt_node *node ); void xt_free_node( struct xt_node *node ); void xt_free( struct xt_parser *xt ); struct xt_node *xt_find_node( struct xt_node *node, const char *name ); +struct xt_node *xt_find_path( struct xt_node *node, const char *name ); char *xt_find_attr( struct xt_node *node, const char *key ); struct xt_node *xt_new_node( char *name, const char *text, struct xt_node *children ); -- cgit v1.2.3 From d97f51b59a3ac6d9557ebd1e42a45928fe064b4b Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 15 Aug 2010 00:23:23 +0100 Subject: Fix issues with logging in with huge SSO tickets (hilariously, the 1024- byte buffer was just one byte too short, resulting in a \r-terminated login line and the server waiting for the \n). Also using xt_find_path(). --- protocols/msn/msn_util.c | 3 +-- protocols/msn/ns.c | 2 +- protocols/msn/soap.c | 16 +++++++--------- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/protocols/msn/msn_util.c b/protocols/msn/msn_util.c index 84d68b8c..069e68b8 100644 --- a/protocols/msn/msn_util.c +++ b/protocols/msn/msn_util.c @@ -64,8 +64,7 @@ static char *adlrml_entry( const char *handle_, msn_buddy_flags_t list ) strcpy( handle, handle_ ); if( ( domain = strchr( handle, '@' ) ) ) - *(domain - ++) = '\0'; + *(domain++) = '\0'; else return NULL; diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index 23b8f3b1..5bf07c3e 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -704,7 +704,7 @@ void msn_auth_got_passport_token( struct im_connection *ic, char *token ) md = ic->proto_data; { - char buf[1024]; + char buf[1536]; g_snprintf( buf, sizeof( buf ), "USR %d SSO S %s %s\r\n", ++md->trId, md->tokens[0], token ); msn_write( ic, buf, strlen( buf ) ); diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c index 13ef7e37..5d641542 100644 --- a/protocols/msn/soap.c +++ b/protocols/msn/soap.c @@ -202,9 +202,7 @@ static xt_status msn_soap_passport_sso_token( struct xt_node *node, gpointer dat return XT_HANDLED; id += strlen( id ) - 1; if( *id == '1' && - ( p = node->parent ) && ( p = p->parent ) && - ( p = xt_find_node( p->children, "wst:RequestedProofToken" ) ) && - ( p = xt_find_node( p->children, "wst:BinarySecret" ) ) && + ( p = xt_find_path( node, "../../wst:RequestedProofToken/wst:BinarySecret" ) ) && p->text ) sd->secret = g_strdup( p->text ); @@ -476,8 +474,7 @@ static xt_status msn_soap_memlist_member( struct xt_node *node, gpointer data ) struct msn_soap_req_data *soap_req = data; struct im_connection *ic = soap_req->ic; - if( ( p = node->parent ) && ( p = p->parent ) && - ( p = xt_find_node( p->children, "MemberRole" ) ) ) + if( ( p = xt_find_path( node, "../../MemberRole" ) ) ) role = p->text; if( ( p = xt_find_node( node->children, "PassportName" ) ) ) @@ -635,8 +632,7 @@ static xt_status msn_soap_addressbook_group( struct xt_node *node, gpointer data char *id = NULL, *name = NULL; struct msn_soap_req_data *soap_req = data; - if( ( p = node->parent ) && - ( p = xt_find_node( p->children, "groupId" ) ) ) + if( ( p = xt_find_path( node, "../groupId" ) ) ) id = p->text; if( ( p = xt_find_node( node->children, "name" ) ) ) @@ -656,8 +652,7 @@ static xt_status msn_soap_addressbook_contact( struct xt_node *node, gpointer da struct msn_soap_req_data *soap_req = data; struct im_connection *ic = soap_req->ic; - if( ( p = node->parent ) && - ( p = xt_find_node( p->children, "contactId" ) ) ) + if( ( p = xt_find_path( node, "../contactId" ) ) ) id = p->text; if( ( p = xt_find_node( node->children, "contactType" ) ) ) type = p->text; @@ -675,6 +670,9 @@ static xt_status msn_soap_addressbook_contact( struct xt_node *node, gpointer da return XT_HANDLED; } + if( handle == NULL ) + return XT_HANDLED; + if( !( bu = bee_user_by_handle( ic->bee, ic, handle ) ) && !( bu = bee_user_new( ic->bee, ic, handle, 0 ) ) ) return XT_HANDLED; -- cgit v1.2.3 From ff27648aee17e649cdd1e47f503271e4fccbff43 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 15 Aug 2010 01:05:49 +0100 Subject: Read group info. --- protocols/msn/msn.c | 12 +++++++++--- protocols/msn/msn.h | 13 +++++++++---- protocols/msn/msn_util.c | 32 ++++++++++++++++++++++++++++++++ protocols/msn/soap.c | 18 +++++++++++++++++- 4 files changed, 67 insertions(+), 8 deletions(-) diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c index 679ac65e..00c01dc3 100644 --- a/protocols/msn/msn.c +++ b/protocols/msn/msn.c @@ -106,14 +106,20 @@ static void msn_logout( struct im_connection *ic ) msn_msgq_purge( ic, &md->msgq ); - while( md->groupcount > 0 ) - g_free( md->grouplist[--md->groupcount] ); - g_free( md->grouplist ); g_free( md->tokens[0] ); g_free( md->tokens[1] ); g_free( md->tokens[2] ); g_free( md->lock_key ); + while( md->groups ) + { + struct msn_group *mg = md->groups->data; + g_free( mg->id ); + g_free( mg->name ); + g_free( mg ); + md->groups = g_slist_remove( md->groups, mg ); + } + g_tree_destroy( md->domaintree ); md->domaintree = NULL; diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h index 862d1ef7..c7529803 100644 --- a/protocols/msn/msn.h +++ b/protocols/msn/msn.h @@ -90,12 +90,9 @@ struct msn_data GSList *switchboards; int sb_failures; time_t first_sb_failure; - GSList *filetransfers; const struct msn_away_state *away_state; - int buddycount; - int groupcount; - char **grouplist; + GSList *groups; GTree *domaintree; }; @@ -174,6 +171,12 @@ struct msn_buddy_data msn_buddy_flags_t flags; }; +struct msn_group +{ + char *name; + char *id; +}; + /* Bitfield values for msn_status_code.flags */ #define STATUS_FATAL 1 #define STATUS_SB_FATAL 2 @@ -210,6 +213,8 @@ void msn_msgq_purge( struct im_connection *ic, GSList **list ); gboolean msn_set_display_name( struct im_connection *ic, const char *rawname ); char *msn_p11_challenge( char *challenge ); gint msn_domaintree_cmp( gconstpointer a_, gconstpointer b_ ); +struct msn_group *msn_group_by_name( struct im_connection *ic, const char *name ); +struct msn_group *msn_group_by_id( struct im_connection *ic, const char *id ); /* tables.c */ const struct msn_away_state *msn_away_state_by_number( int number ); diff --git a/protocols/msn/msn_util.c b/protocols/msn/msn_util.c index 069e68b8..cf8ab4db 100644 --- a/protocols/msn/msn_util.c +++ b/protocols/msn/msn_util.c @@ -565,3 +565,35 @@ gint msn_domaintree_cmp( gconstpointer a_, gconstpointer b_ ) return ret; } + +struct msn_group *msn_group_by_name( struct im_connection *ic, const char *name ) +{ + struct msn_data *md = ic->proto_data; + GSList *l; + + for( l = md->groups; l; l = l->next ) + { + struct msn_group *mg = l->data; + + if( g_strcasecmp( mg->name, name ) == 0 ) + return mg; + } + + return NULL; +} + +struct msn_group *msn_group_by_id( struct im_connection *ic, const char *id ) +{ + struct msn_data *md = ic->proto_data; + GSList *l; + + for( l = md->groups; l; l = l->next ) + { + struct msn_group *mg = l->data; + + if( g_strcasecmp( mg->id, id ) == 0 ) + return mg; + } + + return NULL; +} diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c index 5d641542..b8762ce1 100644 --- a/protocols/msn/soap.c +++ b/protocols/msn/soap.c @@ -631,6 +631,7 @@ static xt_status msn_soap_addressbook_group( struct xt_node *node, gpointer data struct xt_node *p; char *id = NULL, *name = NULL; struct msn_soap_req_data *soap_req = data; + struct msn_data *md = soap_req->ic->proto_data; if( ( p = xt_find_path( node, "../groupId" ) ) ) id = p->text; @@ -638,6 +639,14 @@ static xt_status msn_soap_addressbook_group( struct xt_node *node, gpointer data if( ( p = xt_find_node( node->children, "name" ) ) ) name = p->text; + if( id && name ) + { + struct msn_group *mg = g_new0( struct msn_group, 1 ); + mg->id = g_strdup( id ); + mg->name = g_strdup( name ); + md->groups = g_slist_prepend( md->groups, mg ); + } + printf( "%s %s\n", id, name ); return XT_HANDLED; @@ -648,9 +657,11 @@ static xt_status msn_soap_addressbook_contact( struct xt_node *node, gpointer da bee_user_t *bu; struct msn_buddy_data *bd; struct xt_node *p; - char *id = NULL, *type = NULL, *handle = NULL, *display_name = NULL; + char *id = NULL, *type = NULL, *handle = NULL, + *display_name = NULL, *group_id = NULL; struct msn_soap_req_data *soap_req = data; struct im_connection *ic = soap_req->ic; + struct msn_group *group; if( ( p = xt_find_path( node, "../contactId" ) ) ) id = p->text; @@ -660,6 +671,8 @@ static xt_status msn_soap_addressbook_contact( struct xt_node *node, gpointer da handle = p->text; if( ( p = xt_find_node( node->children, "displayName" ) ) ) display_name = p->text; + if( ( p = xt_find_path( node, "groupIds/guid" ) ) ) + group_id = p->text; if( type && g_strcasecmp( type, "me" ) == 0 ) { @@ -684,6 +697,9 @@ static xt_status msn_soap_addressbook_contact( struct xt_node *node, gpointer da imcb_rename_buddy( ic, handle, display_name ); + if( group_id && ( group = msn_group_by_id( ic, group_id ) ) ) + imcb_add_buddy( ic, handle, group->name ); + printf( "%s %s %s %s\n", id, type, handle, display_name ); return XT_HANDLED; -- cgit v1.2.3 From 5a7af1ba940521a65b3611e5f96ffa9306497e45 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 15 Aug 2010 14:02:52 +0100 Subject: The ADL command doesn't support >150 contacts. Split it up. --- protocols/msn/msn.h | 6 ++++ protocols/msn/ns.c | 88 ++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 66 insertions(+), 28 deletions(-) diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h index c7529803..f6666178 100644 --- a/protocols/msn/msn.h +++ b/protocols/msn/msn.h @@ -93,7 +93,12 @@ struct msn_data const struct msn_away_state *away_state; GSList *groups; + + /* Mostly used for sending the ADL command; since MSNP13 the client + is responsible for downloading the contact list and then sending + it to the MSNP server. */ GTree *domaintree; + int adl_todo; }; struct msn_switchboard @@ -163,6 +168,7 @@ typedef enum MSN_BUDDY_BL = 4, MSN_BUDDY_RL = 8, MSN_BUDDY_PL = 16, + MSN_BUDDY_ADL_SYNCED = 256, } msn_buddy_flags_t; struct msn_buddy_data diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index 5bf07c3e..a599b0ba 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -34,6 +34,7 @@ static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition c static int msn_ns_command( gpointer data, char **cmd, int num_parts ); static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts ); +static void msn_ns_send_adl_start( struct im_connection *ic ); static void msn_ns_send_adl( struct im_connection *ic ); gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ) @@ -256,30 +257,32 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) } else if( strcmp( cmd[0], "BLP" ) == 0 ) { - msn_ns_send_adl( ic ); + msn_ns_send_adl_start( ic ); } else if( strcmp( cmd[0], "ADL" ) == 0 ) { if( num_parts >= 3 && strcmp( cmd[2], "OK" ) == 0 ) { - char buf[1024]; - char *fn_raw; - char *fn; + msn_ns_send_adl( ic ); - if( ic->flags & OPT_LOGGED_IN ) - return 1; - - if( ( fn_raw = set_getstr( &ic->acc->set, "display_name" ) ) == NULL ) - fn_raw = ic->acc->user; - fn = g_malloc( strlen( fn_raw ) * 3 + 1 ); - strcpy( fn, fn_raw ); - http_encode( fn ); - - g_snprintf( buf, sizeof( buf ), "PRP %d MFN %s\r\n", - ++md->trId, fn ); - g_free( fn ); - - msn_write( ic, buf, strlen( buf ) ); + if( md->adl_todo < 0 && !( ic->flags & OPT_LOGGED_IN ) ) + { + char buf[1024]; + char *fn_raw; + char *fn; + + if( ( fn_raw = set_getstr( &ic->acc->set, "display_name" ) ) == NULL ) + fn_raw = ic->acc->user; + fn = g_malloc( strlen( fn_raw ) * 3 + 1 ); + strcpy( fn, fn_raw ); + http_encode( fn ); + + g_snprintf( buf, sizeof( buf ), "PRP %d MFN %s\r\n", + ++md->trId, fn ); + g_free( fn ); + + msn_write( ic, buf, strlen( buf ) ); + } } else if( num_parts >= 3 ) { @@ -732,11 +735,12 @@ static gboolean msn_ns_send_adl_1( gpointer key, gpointer value, gpointer data ) struct xt_node *adl = data, *d, *c; struct bee_user *bu = value; struct msn_buddy_data *bd = bu->data; + struct msn_data *md = bu->ic->proto_data; char handle[strlen(bu->handle)]; char *domain; char l[4]; - if( ( bd->flags & 7 ) == 0 ) + if( ( bd->flags & 7 ) == 0 || ( bd->flags & MSN_BUDDY_ADL_SYNCED ) ) return FALSE; strcpy( handle, bu->handle ); @@ -760,24 +764,27 @@ static gboolean msn_ns_send_adl_1( gpointer key, gpointer value, gpointer data ) xt_add_attr( c, "t", "1" ); /* 1 means normal, 4 means mobile? */ xt_insert_child( d, c ); - return FALSE; + /* Do this in batches of 100. */ + bd->flags |= MSN_BUDDY_ADL_SYNCED; + return (--md->adl_todo % 140) == 0; } static void msn_ns_send_adl( struct im_connection *ic ) { struct xt_node *adl; - struct msn_data *md; + struct msn_data *md = ic->proto_data; char *adls, buf[64]; - /* Dead connection? */ - if( g_slist_find( msn_connections, ic ) == NULL ) - return; - - md = ic->proto_data; - adl = xt_new_node( "ml", NULL, NULL ); xt_add_attr( adl, "l", "1" ); g_tree_foreach( md->domaintree, msn_ns_send_adl_1, adl ); + if( adl->children == NULL ) + { + /* This tells the caller that we're done now. */ + md->adl_todo = -1; + xt_free_node( adl ); + return; + } adls = xt_to_string( adl ); g_snprintf( buf, sizeof( buf ), "ADL %d %zd\r\n", ++md->trId, strlen( adls ) ); @@ -785,5 +792,30 @@ static void msn_ns_send_adl( struct im_connection *ic ) msn_write( ic, adls, strlen( adls ) ); g_free( adls ); - xt_free_node( adl ); +} + +static void msn_ns_send_adl_start( struct im_connection *ic ) +{ + struct msn_data *md; + GSList *l; + + /* Dead connection? */ + if( g_slist_find( msn_connections, ic ) == NULL ) + return; + + md = ic->proto_data; + md->adl_todo = 0; + for( l = ic->bee->users; l; l = l->next ) + { + bee_user_t *bu = l->data; + struct msn_buddy_data *bd = bu->data; + + if( bu->ic != ic || ( bd->flags & 7 ) == 0 ) + continue; + + bd->flags &= ~MSN_BUDDY_ADL_SYNCED; + md->adl_todo++; + } + + msn_ns_send_adl( ic ); } -- cgit v1.2.3 From 660cb00687dbe0abd37e705a2923d1cf8bf6f45c Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 15 Aug 2010 14:23:03 +0100 Subject: Parse authentication errors. --- protocols/msn/msn.h | 2 +- protocols/msn/ns.c | 8 +++++++- protocols/msn/soap.c | 27 ++++++++++++++++++++++++++- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h index f6666178..ae4ea42b 100644 --- a/protocols/msn/msn.h +++ b/protocols/msn/msn.h @@ -203,7 +203,7 @@ extern GSList *msn_switchboards; /* ns.c */ gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ); -void msn_auth_got_passport_token( struct im_connection *ic, char *token ); +void msn_auth_got_passport_token( struct im_connection *ic, const char *token, const char *error ); void msn_auth_got_contact_list( struct im_connection *ic ); /* msn_util.c */ diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index a599b0ba..2449c8d5 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -696,7 +696,7 @@ static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int return( 1 ); } -void msn_auth_got_passport_token( struct im_connection *ic, char *token ) +void msn_auth_got_passport_token( struct im_connection *ic, const char *token, const char *error ) { struct msn_data *md; @@ -706,12 +706,18 @@ void msn_auth_got_passport_token( struct im_connection *ic, char *token ) md = ic->proto_data; + if( token ) { char buf[1536]; g_snprintf( buf, sizeof( buf ), "USR %d SSO S %s %s\r\n", ++md->trId, md->tokens[0], token ); msn_write( ic, buf, strlen( buf ) ); } + else + { + imcb_error( ic, "Error during Passport authentication: %s", error ); + imc_logout( ic, TRUE ); + } } void msn_auth_got_contact_list( struct im_connection *ic ) diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c index b8762ce1..fe716d9d 100644 --- a/protocols/msn/soap.c +++ b/protocols/msn/soap.c @@ -172,6 +172,7 @@ struct msn_soap_passport_sso_data char *policy; char *nonce; char *secret; + char *error; }; static int msn_soap_passport_sso_build_request( struct msn_soap_req_data *soap_req ) @@ -216,8 +217,25 @@ static xt_status msn_soap_passport_sso_token( struct xt_node *node, gpointer dat return XT_HANDLED; } +static xt_status msn_soap_passport_failure( struct xt_node *node, gpointer data ) +{ + struct msn_soap_req_data *soap_req = data; + struct msn_soap_passport_sso_data *sd = soap_req->data; + struct xt_node *code = xt_find_node( node->children, "faultcode" ); + struct xt_node *string = xt_find_node( node->children, "faultstring" ); + + if( code == NULL || code->text_len == 0 ) + sd->error = g_strdup( "Unknown error" ); + else + sd->error = g_strdup_printf( "%s (%s)", code->text, string && string->text_len ? + string->text : "no description available" ); + + return XT_HANDLED; +} + static const struct xt_handler_entry msn_soap_passport_sso_parser[] = { { "wsse:BinarySecurityToken", "wst:RequestedSecurityToken", msn_soap_passport_sso_token }, + { "S:Fault", "S:Envelope", msn_soap_passport_failure }, { NULL, NULL, NULL } }; @@ -269,6 +287,12 @@ static int msn_soap_passport_sso_handle_response( struct msn_soap_req_data *soap GUINT32_TO_LE( 20 ), GUINT32_TO_LE( 72 ), }; + + if( sd->secret == NULL ) + { + msn_auth_got_passport_token( ic, NULL, sd->error ); + return MSN_SOAP_OK; + } key1_len = base64_decode( sd->secret, (unsigned char**) &key1 ); @@ -286,7 +310,7 @@ static int msn_soap_passport_sso_handle_response( struct msn_soap_req_data *soap memcpy( blurb.cipherbytes, des3res, 72 ); blurb64 = base64_encode( (unsigned char*) &blurb, sizeof( blurb ) ); - msn_auth_got_passport_token( ic, blurb64 ); + msn_auth_got_passport_token( ic, blurb64, NULL ); g_free( padnonce ); g_free( blurb64 ); @@ -305,6 +329,7 @@ static int msn_soap_passport_sso_free_data( struct msn_soap_req_data *soap_req ) g_free( sd->policy ); g_free( sd->nonce ); g_free( sd->secret ); + g_free( sd->error ); return MSN_SOAP_OK; } -- cgit v1.2.3 From 9679fd8f3141abb0cabe7b036cf96c3de40ee22a Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 15 Aug 2010 15:27:44 +0100 Subject: Removing soap.h dependency in Makefile. I'll have to fix the internal dependencies for real some day soon, but this one-off hack is breaking out-of-tree builds. --- protocols/msn/Makefile | 2 -- 1 file changed, 2 deletions(-) diff --git a/protocols/msn/Makefile b/protocols/msn/Makefile index a14225d1..8ff61c60 100644 --- a/protocols/msn/Makefile +++ b/protocols/msn/Makefile @@ -41,5 +41,3 @@ $(objects): %.o: $(SRCDIR)%.c msn_mod.o: $(objects) @echo '*' Linking msn_mod.o @$(LD) $(LFLAGS) $(objects) -o msn_mod.o - -soap.o: soap.h soap.c -- cgit v1.2.3 From 9b01339168bc79d08c4e371552cc44648bd8878d Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 15 Aug 2010 18:19:06 +0100 Subject: Check the flag in address book entries, ignore the ones that have it set to false, or this code will add all non-Messenger contacts to the contact list (oops). --- protocols/msn/soap.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c index fe716d9d..91f93afd 100644 --- a/protocols/msn/soap.c +++ b/protocols/msn/soap.c @@ -682,7 +682,7 @@ static xt_status msn_soap_addressbook_contact( struct xt_node *node, gpointer da bee_user_t *bu; struct msn_buddy_data *bd; struct xt_node *p; - char *id = NULL, *type = NULL, *handle = NULL, + char *id = NULL, *type = NULL, *handle = NULL, *is_msgr = "false", *display_name = NULL, *group_id = NULL; struct msn_soap_req_data *soap_req = data; struct im_connection *ic = soap_req->ic; @@ -696,6 +696,8 @@ static xt_status msn_soap_addressbook_contact( struct xt_node *node, gpointer da handle = p->text; if( ( p = xt_find_node( node->children, "displayName" ) ) ) display_name = p->text; + if( ( p = xt_find_node( node->children, "isMessengerUser" ) ) ) + is_msgr = p->text; if( ( p = xt_find_path( node, "groupIds/guid" ) ) ) group_id = p->text; @@ -708,7 +710,7 @@ static xt_status msn_soap_addressbook_contact( struct xt_node *node, gpointer da return XT_HANDLED; } - if( handle == NULL ) + if( !bool2int( is_msgr ) || handle == NULL ) return XT_HANDLED; if( !( bu = bee_user_by_handle( ic->bee, ic, handle ) ) && -- cgit v1.2.3 From e0e15468835d5ae5bce54a28bd7a5b7aea66a1e2 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 15 Aug 2010 19:46:10 +0100 Subject: Making display name code a bit saner. Apparently PoS MSN is still suffering from display_name amnesia a little bit though at least with Hotmail accounts. --- protocols/msn/msn.c | 15 +-------------- protocols/msn/msn.h | 2 +- protocols/msn/msn_util.c | 16 ++++++++++++++++ protocols/msn/ns.c | 20 ++++++-------------- protocols/msn/soap.c | 7 ++++++- 5 files changed, 30 insertions(+), 30 deletions(-) diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c index 00c01dc3..873a51ad 100644 --- a/protocols/msn/msn.c +++ b/protocols/msn/msn.c @@ -336,9 +336,6 @@ static char *set_eval_display_name( set_t *set, char *value ) { account_t *acc = set->data; struct im_connection *ic = acc->ic; - struct msn_data *md = ic->proto_data; - char buf[512]; - char *fn; if( strlen( value ) > 129 ) { @@ -347,17 +344,7 @@ static char *set_eval_display_name( set_t *set, char *value ) } msn_soap_addressbook_set_display_name( ic, value ); - - fn = g_malloc( strlen( value ) * 3 + 1 ); - strcpy( fn, value ); - http_encode( fn ); - g_snprintf( buf, sizeof( buf ), "PRP %d MFN %s\r\n", - ++md->trId, fn ); - g_free( fn ); - - /* Note: We don't actually know if the server accepted the new name, - and won't give proper feedback yet if it doesn't. */ - return msn_write( ic, buf, strlen( buf ) ) ? value : NULL; + return msn_ns_set_display_name( ic, value ) ? value : NULL; } static void msn_buddy_data_add( bee_user_t *bu ) diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h index ae4ea42b..3ea8c503 100644 --- a/protocols/msn/msn.h +++ b/protocols/msn/msn.h @@ -216,11 +216,11 @@ char *msn_findheader( char *text, char *header, int len ); char **msn_linesplit( char *line ); int msn_handler( struct msn_handler_data *h ); void msn_msgq_purge( struct im_connection *ic, GSList **list ); -gboolean msn_set_display_name( struct im_connection *ic, const char *rawname ); char *msn_p11_challenge( char *challenge ); gint msn_domaintree_cmp( gconstpointer a_, gconstpointer b_ ); struct msn_group *msn_group_by_name( struct im_connection *ic, const char *name ); struct msn_group *msn_group_by_id( struct im_connection *ic, const char *id ); +int msn_ns_set_display_name( struct im_connection *ic, const char *value ); /* tables.c */ const struct msn_away_state *msn_away_state_by_number( int number ); diff --git a/protocols/msn/msn_util.c b/protocols/msn/msn_util.c index cf8ab4db..78f81a41 100644 --- a/protocols/msn/msn_util.c +++ b/protocols/msn/msn_util.c @@ -597,3 +597,19 @@ struct msn_group *msn_group_by_id( struct im_connection *ic, const char *id ) return NULL; } + +int msn_ns_set_display_name( struct im_connection *ic, const char *value ) +{ + struct msn_data *md = ic->proto_data; + char fn[strlen(value)*3+1]; + char buf[512]; + + strcpy( fn, value ); + http_encode( fn ); + g_snprintf( buf, sizeof( buf ), "PRP %d MFN %s\r\n", + ++md->trId, fn ); + + /* Note: We don't actually know if the server accepted the new name, + and won't give proper feedback yet if it doesn't. */ + return msn_write( ic, buf, strlen( buf ) ); +} diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index 2449c8d5..c9b01ef2 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -258,6 +258,9 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) else if( strcmp( cmd[0], "BLP" ) == 0 ) { msn_ns_send_adl_start( ic ); + + if( md->adl_todo < 0 && !( ic->flags & OPT_LOGGED_IN ) ) + return msn_ns_set_display_name( ic, set_getstr( &ic->acc->set, "display_name" ) ); } else if( strcmp( cmd[0], "ADL" ) == 0 ) { @@ -267,21 +270,10 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( md->adl_todo < 0 && !( ic->flags & OPT_LOGGED_IN ) ) { - char buf[1024]; - char *fn_raw; - char *fn; - - if( ( fn_raw = set_getstr( &ic->acc->set, "display_name" ) ) == NULL ) - fn_raw = ic->acc->user; - fn = g_malloc( strlen( fn_raw ) * 3 + 1 ); - strcpy( fn, fn_raw ); - http_encode( fn ); - - g_snprintf( buf, sizeof( buf ), "PRP %d MFN %s\r\n", - ++md->trId, fn ); - g_free( fn ); + msn_ns_send_adl( ic ); - msn_write( ic, buf, strlen( buf ) ); + if( md->adl_todo < 0 && !( ic->flags & OPT_LOGGED_IN ) ) + return msn_ns_set_display_name( ic, set_getstr( &ic->acc->set, "display_name" ) ); } } else if( num_parts >= 3 ) diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c index 91f93afd..b717343f 100644 --- a/protocols/msn/soap.c +++ b/protocols/msn/soap.c @@ -686,6 +686,7 @@ static xt_status msn_soap_addressbook_contact( struct xt_node *node, gpointer da *display_name = NULL, *group_id = NULL; struct msn_soap_req_data *soap_req = data; struct im_connection *ic = soap_req->ic; + struct msn_data *md = soap_req->ic->proto_data; struct msn_group *group; if( ( p = xt_find_path( node, "../contactId" ) ) ) @@ -703,6 +704,10 @@ static xt_status msn_soap_addressbook_contact( struct xt_node *node, gpointer da if( type && g_strcasecmp( type, "me" ) == 0 ) { +#if 0 + g_free( md->myid ); + md->myid = g_strdup( id ); +#endif set_t *set = set_find( &ic->acc->set, "display_name" ); g_free( set->value ); set->value = g_strdup( display_name ); @@ -765,7 +770,7 @@ static int msn_soap_ab_namechange_build_request( struct msn_soap_req_data *soap_ soap_req->url = g_strdup( SOAP_ADDRESSBOOK_URL ); soap_req->action = g_strdup( SOAP_AB_NAMECHANGE_ACTION ); soap_req->payload = msn_soap_abservice_build( SOAP_AB_NAMECHANGE_PAYLOAD, - "Initial", md->tokens[1], (char *) soap_req->data ); + "Timer", md->tokens[1], (char *) soap_req->data ); return 1; } -- cgit v1.2.3 From 80175a1558f297d5505ed4e91a261781ec9c65a2 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 18 Aug 2010 20:21:44 +0100 Subject: Fetch the user's profile to see if there's a display name set there. If there is, the one in the address book should be ignored. No support for changing the profile yet though. --- protocols/msn/msn.c | 11 +++++--- protocols/msn/msn.h | 14 +++++++--- protocols/msn/ns.c | 29 ++++++++++++-------- protocols/msn/soap.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++----- protocols/msn/soap.h | 57 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 163 insertions(+), 24 deletions(-) diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c index 873a51ad..4b79cc26 100644 --- a/protocols/msn/msn.c +++ b/protocols/msn/msn.c @@ -82,6 +82,7 @@ static void msn_logout( struct im_connection *ic ) { struct msn_data *md = ic->proto_data; GSList *l; + int i; if( md ) { @@ -106,9 +107,8 @@ static void msn_logout( struct im_connection *ic ) msn_msgq_purge( ic, &md->msgq ); - g_free( md->tokens[0] ); - g_free( md->tokens[1] ); - g_free( md->tokens[2] ); + for( i = 0; i < sizeof( md->tokens ) / sizeof( md->tokens[0] ); i ++ ) + g_free( md->tokens[i] ); g_free( md->lock_key ); while( md->groups ) @@ -336,6 +336,7 @@ static char *set_eval_display_name( set_t *set, char *value ) { account_t *acc = set->data; struct im_connection *ic = acc->ic; + struct msn_data *md = ic->proto_data; if( strlen( value ) > 129 ) { @@ -343,6 +344,10 @@ static char *set_eval_display_name( set_t *set, char *value ) return NULL; } + if( md->flags & MSN_GOT_PROFILE_DN ) + imcb_log( ic, "Warning: Persistent name changes for this account have to be done " + "in the profile. BitlBee doesn't currently support this." ); + msn_soap_addressbook_set_display_name( ic, value ); return msn_ns_set_display_name( ic, value ) ? value : NULL; } diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h index 3ea8c503..7cb3241c 100644 --- a/protocols/msn/msn.h +++ b/protocols/msn/msn.h @@ -49,12 +49,9 @@ */ #define MSNP11_PROD_KEY "ILTXC!4IXB5FB*PX" -//PK}_A_0N_K%O?A9S" #define MSNP11_PROD_ID "PROD0119GSJUC$18" -//PROD0114ES4Z%Q5W" #define MSNP_VER "MSNP15" #define MSNP_BUILD "8.5.1288" -//"8.1.0178" #define MSN_SB_NEW -24062002 @@ -75,15 +72,23 @@ #define PROFILE_URL "http://members.msn.com/" +typedef enum +{ + MSN_GOT_PROFILE = 1, + MSN_GOT_PROFILE_DN = 2, + MSN_DONE_ADL = 4, +} msn_flags_t; + struct msn_data { struct im_connection *ic; int fd; struct msn_handler_data *handler; + msn_flags_t flags; int trId; - char *tokens[3]; + char *tokens[4]; char *lock_key; GSList *msgq, *grpq; @@ -205,6 +210,7 @@ extern GSList *msn_switchboards; gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ); void msn_auth_got_passport_token( struct im_connection *ic, const char *token, const char *error ); void msn_auth_got_contact_list( struct im_connection *ic ); +int msn_ns_finish_login( struct im_connection *ic ); /* msn_util.c */ int msn_write( struct im_connection *ic, char *s, int len ); diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index c9b01ef2..4b779a58 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -258,23 +258,14 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) else if( strcmp( cmd[0], "BLP" ) == 0 ) { msn_ns_send_adl_start( ic ); - - if( md->adl_todo < 0 && !( ic->flags & OPT_LOGGED_IN ) ) - return msn_ns_set_display_name( ic, set_getstr( &ic->acc->set, "display_name" ) ); + return msn_ns_finish_login( ic ); } else if( strcmp( cmd[0], "ADL" ) == 0 ) { if( num_parts >= 3 && strcmp( cmd[2], "OK" ) == 0 ) { msn_ns_send_adl( ic ); - - if( md->adl_todo < 0 && !( ic->flags & OPT_LOGGED_IN ) ) - { - msn_ns_send_adl( ic ); - - if( md->adl_todo < 0 && !( ic->flags & OPT_LOGGED_IN ) ) - return msn_ns_set_display_name( ic, set_getstr( &ic->acc->set, "display_name" ) ); - } + return msn_ns_finish_login( ic ); } else if( num_parts >= 3 ) { @@ -817,3 +808,19 @@ static void msn_ns_send_adl_start( struct im_connection *ic ) msn_ns_send_adl( ic ); } + +int msn_ns_finish_login( struct im_connection *ic ) +{ + struct msn_data *md = ic->proto_data; + + if( ic->flags & OPT_LOGGED_IN ) + return 1; + + if( md->adl_todo < 0 ) + md->flags |= MSN_DONE_ADL; + + if( ( md->flags & MSN_DONE_ADL ) && ( md->flags & MSN_GOT_PROFILE ) ) + return msn_ns_set_display_name( ic, set_getstr( &ic->acc->set, "display_name" ) ); + else + return 1; +} diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c index b717343f..410ff37c 100644 --- a/protocols/msn/soap.c +++ b/protocols/msn/soap.c @@ -208,7 +208,7 @@ static xt_status msn_soap_passport_sso_token( struct xt_node *node, gpointer dat sd->secret = g_strdup( p->text ); *id -= '1'; - if( *id >= 0 && *id <= 2 ) + if( *id >= 0 && *id < sizeof( md->tokens ) / sizeof( md->tokens[0] ) ) { g_free( md->tokens[(int)*id] ); md->tokens[(int)*id] = g_strdup( node->text ); @@ -686,7 +686,6 @@ static xt_status msn_soap_addressbook_contact( struct xt_node *node, gpointer da *display_name = NULL, *group_id = NULL; struct msn_soap_req_data *soap_req = data; struct im_connection *ic = soap_req->ic; - struct msn_data *md = soap_req->ic->proto_data; struct msn_group *group; if( ( p = xt_find_path( node, "../contactId" ) ) ) @@ -704,14 +703,15 @@ static xt_status msn_soap_addressbook_contact( struct xt_node *node, gpointer da if( type && g_strcasecmp( type, "me" ) == 0 ) { -#if 0 - g_free( md->myid ); - md->myid = g_strdup( id ); -#endif set_t *set = set_find( &ic->acc->set, "display_name" ); g_free( set->value ); set->value = g_strdup( display_name ); + /* Try to fetch the profile; if the user has one, that's where + we can find the persistent display_name. */ + if( ( p = xt_find_node( node->children, "CID" ) ) && p->text ) + msn_soap_profile_get( ic, p->text ); + return XT_HANDLED; } @@ -881,3 +881,67 @@ int msn_soap_ab_contact_del( struct im_connection *ic, bee_user_t *bu ) msn_soap_ab_contact_del_handle_response, msn_soap_ab_contact_del_free_data ); } + + + +/* Storage stuff: Fetch profile. */ +static int msn_soap_profile_get_build_request( struct msn_soap_req_data *soap_req ) +{ + struct msn_data *md = soap_req->ic->proto_data; + + soap_req->url = g_strdup( SOAP_STORAGE_URL ); + soap_req->action = g_strdup( SOAP_PROFILE_GET_ACTION ); + soap_req->payload = g_markup_printf_escaped( SOAP_PROFILE_GET_PAYLOAD, + md->tokens[3], (char*) soap_req->data ); + + return 1; +} + +static xt_status msn_soap_profile_get_result( struct xt_node *node, gpointer data ) +{ + struct msn_soap_req_data *soap_req = data; + struct im_connection *ic = soap_req->ic; + struct msn_data *md = soap_req->ic->proto_data; + struct xt_node *dn; + + if( ( dn = xt_find_node( node->children, "DisplayName" ) ) && dn->text ) + { + set_t *set = set_find( &ic->acc->set, "display_name" ); + g_free( set->value ); + set->value = g_strdup( dn->text ); + + md->flags |= MSN_GOT_PROFILE_DN; + } + + return XT_HANDLED; +} + +static const struct xt_handler_entry msn_soap_profile_get_parser[] = { + { "ExpressionProfile", "GetProfileResult", msn_soap_profile_get_result }, + { NULL, NULL, NULL } +}; + +static int msn_soap_profile_get_handle_response( struct msn_soap_req_data *soap_req ) +{ + struct msn_data *md = soap_req->ic->proto_data; + + md->flags |= MSN_GOT_PROFILE; + msn_ns_finish_login( soap_req->ic ); + + return MSN_SOAP_OK; +} + +static int msn_soap_profile_get_free_data( struct msn_soap_req_data *soap_req ) +{ + g_free( soap_req->data ); + return 0; +} + +int msn_soap_profile_get( struct im_connection *ic, const char *cid ) +{ + return msn_soap_start( ic, g_strdup( cid ), + msn_soap_profile_get_build_request, + msn_soap_profile_get_parser, + msn_soap_profile_get_handle_response, + msn_soap_profile_get_free_data ); +} diff --git a/protocols/msn/soap.h b/protocols/msn/soap.h index 19a5c6ae..9fba5366 100644 --- a/protocols/msn/soap.h +++ b/protocols/msn/soap.h @@ -125,6 +125,15 @@ "" \ "" \ "" \ + "" \ + "http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue" \ + "" \ + "" \ + "storage.msn.com" \ + "" \ + "" \ + "" \ + "" \ "" \ "" \ "" @@ -286,4 +295,52 @@ int msn_soap_addressbook_set_display_name( struct im_connection *ic, const char int msn_soap_ab_contact_add( struct im_connection *ic, bee_user_t *bu ); int msn_soap_ab_contact_del( struct im_connection *ic, bee_user_t *bu ); + +#define SOAP_STORAGE_URL "https://storage.msn.com/storageservice/SchematizedStore.asmx" +#define SOAP_PROFILE_GET_ACTION "http://www.msn.com/webservices/storage/w10/GetProfile" + +#define SOAP_PROFILE_GET_PAYLOAD \ +"" \ +"" \ + "" \ + "" \ + "Messenger Client 9.0" \ + "Initial" \ + "" \ + "" \ + "0" \ + "%s" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "%s" \ + "MyCidStuff" \ + "" \ + "MyProfile" \ + "" \ + "" \ + "true" \ + "true" \ + "" \ + "true" \ + "true" \ + "true" \ + "true" \ + "true" \ + "true" \ + "true" \ + "true" \ + "true" \ + "" \ + "" \ + "" \ + "" \ +"" + +int msn_soap_profile_get( struct im_connection *ic, const char *cid ); + + #endif /* __SOAP_H__ */ -- cgit v1.2.3 From f2520b5ad5a82d9bf08a550fb0e49913f57d4685 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Fri, 20 Aug 2010 09:22:28 +0100 Subject: In debugging mode, dump all SOAP requests + responses with some indentation for easier debugging. --- lib/xmltree.c | 4 ++-- protocols/msn/soap.c | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/lib/xmltree.c b/lib/xmltree.c index 20d69455..3ec7e673 100644 --- a/lib/xmltree.c +++ b/lib/xmltree.c @@ -330,7 +330,7 @@ void xt_print( struct xt_node *node ) /* Indentation */ for( c = node; c->parent; c = c->parent ) - printf( "\t" ); + printf( " " ); /* Start the tag */ printf( "<%s", node->name ); @@ -368,7 +368,7 @@ void xt_print( struct xt_node *node ) if( node->children ) for( c = node; c->parent; c = c->parent ) - printf( "\t" ); + printf( " " ); /* Non-empty tag is now finished. */ printf( "\n", node->name ); diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c index 410ff37c..6665eef1 100644 --- a/protocols/msn/soap.c +++ b/protocols/msn/soap.c @@ -67,6 +67,7 @@ struct msn_soap_req_data }; static int msn_soap_send_request( struct msn_soap_req_data *req ); +static void msn_soap_debug_print( const char *headers, const char *payload ); static int msn_soap_start( struct im_connection *ic, void *data, @@ -106,6 +107,8 @@ static int msn_soap_send_request( struct msn_soap_req_data *soap_req ) soap_action ? soap_action : "", strlen( soap_req->payload ), soap_req->payload ); + msn_soap_debug_print( http_req, soap_req->payload ); + soap_req->http_req = http_dorequest( url.host, url.port, url.proto == PROTO_HTTPS, http_req, msn_soap_handle_response, soap_req ); @@ -130,6 +133,8 @@ static void msn_soap_handle_response( struct http_request *http_req ) xt_free( parser ); } + msn_soap_debug_print( http_req->reply_headers, http_req->reply_body ); + st = soap_req->handle_response( soap_req ); g_free( soap_req->url ); @@ -164,6 +169,28 @@ static char *msn_soap_abservice_build( const char *body_fmt, const char *scenari return ret; } +static void msn_soap_debug_print( const char *headers, const char *payload ) +{ + char *s; + + if( !getenv( "BITLBEE_DEBUG" ) ) + return; + + if( ( s = strstr( headers, "\r\n\r\n" ) ) ) + write( 1, s, s - headers + 4 ); + else + write( 1, headers, strlen( headers ) ); + +#ifdef DEBUG + { + struct xt_node *xt = xt_from_string( payload ); + if( xt ) + xt_print( xt ); + xt_free_node( xt ); + } +#endif +} + /* passport_sso: Authentication MSNP15+ */ -- cgit v1.2.3 From 801b90b3e76f6eed7027f46a7d11e3d3fe0e04e9 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Fri, 20 Aug 2010 20:30:12 +0100 Subject: Check if a connection is down before handling its SOAP responses. --- protocols/msn/soap.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c index 6665eef1..e67da2a1 100644 --- a/protocols/msn/soap.c +++ b/protocols/msn/soap.c @@ -123,6 +123,16 @@ static void msn_soap_handle_response( struct http_request *http_req ) struct msn_soap_req_data *soap_req = http_req->data; int st; + if( g_slist_find( msn_connections, soap_req->ic ) == NULL ) + { + soap_req->free_data( soap_req ); + g_free( soap_req->url ); + g_free( soap_req->action ); + g_free( soap_req->payload ); + g_free( soap_req ); + return; + } + if( http_req->body_size > 0 ) { struct xt_parser *parser; -- cgit v1.2.3 From a366cca62d3a55db4f12a94584f7e7f8fa00db02 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 21 Aug 2010 00:04:12 +0100 Subject: Now including a nice and compact 3DES implementation done by Christophe Devine. OpenSSL exports nice cipher functions, but GnuTLS only just started doing this in 2.10 or so (not even in Debian Sid yet). So instead of adding a whole library for encrypting 72 bytes of data, let's have a built-in 3DES implementation for a while.. --- configure | 6 + lib/Makefile | 2 +- lib/des.c | 646 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/des.h | 51 +++++ 4 files changed, 704 insertions(+), 1 deletion(-) create mode 100644 lib/des.c create mode 100644 lib/des.h diff --git a/configure b/configure index 9b77604c..b0035438 100755 --- a/configure +++ b/configure @@ -422,6 +422,12 @@ if [ "$ret" = "0" ]; then exit 1 fi; +if [ "$msn" = "1" -a "$ssl" != "openssl" ]; then + # Needed for MSN only. OpenSSL exports nice cipher functions already, + # others don't, so use our own 3des code. + echo 'DES=des.o' >> Makefile.settings +fi + echo 'SSL_CLIENT=ssl_'$ssl'.o' >> Makefile.settings if detect_resolv_dynamic || detect_resolv_static; then diff --git a/lib/Makefile b/lib/Makefile index bebe3ba6..7e19fb76 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -12,7 +12,7 @@ SRCDIR := $(SRCDIR)lib/ endif # [SH] Program variables -objects = arc.o base64.o $(EVENT_HANDLER) ftutil.o http_client.o ini.o md5.o misc.o oauth.o proxy.o sha1.o $(SSL_CLIENT) url.o xmltree.o +objects = arc.o base64.o $(DES) $(EVENT_HANDLER) ftutil.o http_client.o ini.o md5.o misc.o oauth.o proxy.o sha1.o $(SSL_CLIENT) url.o xmltree.o LFLAGS += -r diff --git a/lib/des.c b/lib/des.c new file mode 100644 index 00000000..3b9cc8d5 --- /dev/null +++ b/lib/des.c @@ -0,0 +1,646 @@ +/* + * FIPS-46-3 compliant 3DES implementation + * + * Copyright (C) 2001-2003 Christophe Devine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Modified for BitlBee: Added a function compatible with the existing + * function in ssl_openssl.c, fairly specialised for MSN auth (since that's + * all this is used for at least for now). + * + * Added some consts to the tables at the top, and disabled some 64-bit + * and 128-bit key code that I don't need. + * + * *Many* thanks to Christophe for this compact and easy to import code. + */ + +#include +#include +#include "des.h" + +/* the eight DES S-boxes */ + +static const uint32_t SB1[64] = +{ + 0x01010400, 0x00000000, 0x00010000, 0x01010404, + 0x01010004, 0x00010404, 0x00000004, 0x00010000, + 0x00000400, 0x01010400, 0x01010404, 0x00000400, + 0x01000404, 0x01010004, 0x01000000, 0x00000004, + 0x00000404, 0x01000400, 0x01000400, 0x00010400, + 0x00010400, 0x01010000, 0x01010000, 0x01000404, + 0x00010004, 0x01000004, 0x01000004, 0x00010004, + 0x00000000, 0x00000404, 0x00010404, 0x01000000, + 0x00010000, 0x01010404, 0x00000004, 0x01010000, + 0x01010400, 0x01000000, 0x01000000, 0x00000400, + 0x01010004, 0x00010000, 0x00010400, 0x01000004, + 0x00000400, 0x00000004, 0x01000404, 0x00010404, + 0x01010404, 0x00010004, 0x01010000, 0x01000404, + 0x01000004, 0x00000404, 0x00010404, 0x01010400, + 0x00000404, 0x01000400, 0x01000400, 0x00000000, + 0x00010004, 0x00010400, 0x00000000, 0x01010004 +}; + +static const uint32_t SB2[64] = +{ + 0x80108020, 0x80008000, 0x00008000, 0x00108020, + 0x00100000, 0x00000020, 0x80100020, 0x80008020, + 0x80000020, 0x80108020, 0x80108000, 0x80000000, + 0x80008000, 0x00100000, 0x00000020, 0x80100020, + 0x00108000, 0x00100020, 0x80008020, 0x00000000, + 0x80000000, 0x00008000, 0x00108020, 0x80100000, + 0x00100020, 0x80000020, 0x00000000, 0x00108000, + 0x00008020, 0x80108000, 0x80100000, 0x00008020, + 0x00000000, 0x00108020, 0x80100020, 0x00100000, + 0x80008020, 0x80100000, 0x80108000, 0x00008000, + 0x80100000, 0x80008000, 0x00000020, 0x80108020, + 0x00108020, 0x00000020, 0x00008000, 0x80000000, + 0x00008020, 0x80108000, 0x00100000, 0x80000020, + 0x00100020, 0x80008020, 0x80000020, 0x00100020, + 0x00108000, 0x00000000, 0x80008000, 0x00008020, + 0x80000000, 0x80100020, 0x80108020, 0x00108000 +}; + +static const uint32_t SB3[64] = +{ + 0x00000208, 0x08020200, 0x00000000, 0x08020008, + 0x08000200, 0x00000000, 0x00020208, 0x08000200, + 0x00020008, 0x08000008, 0x08000008, 0x00020000, + 0x08020208, 0x00020008, 0x08020000, 0x00000208, + 0x08000000, 0x00000008, 0x08020200, 0x00000200, + 0x00020200, 0x08020000, 0x08020008, 0x00020208, + 0x08000208, 0x00020200, 0x00020000, 0x08000208, + 0x00000008, 0x08020208, 0x00000200, 0x08000000, + 0x08020200, 0x08000000, 0x00020008, 0x00000208, + 0x00020000, 0x08020200, 0x08000200, 0x00000000, + 0x00000200, 0x00020008, 0x08020208, 0x08000200, + 0x08000008, 0x00000200, 0x00000000, 0x08020008, + 0x08000208, 0x00020000, 0x08000000, 0x08020208, + 0x00000008, 0x00020208, 0x00020200, 0x08000008, + 0x08020000, 0x08000208, 0x00000208, 0x08020000, + 0x00020208, 0x00000008, 0x08020008, 0x00020200 +}; + +static const uint32_t SB4[64] = +{ + 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802080, 0x00800081, 0x00800001, 0x00002001, + 0x00000000, 0x00802000, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00800080, 0x00800001, + 0x00000001, 0x00002000, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002001, 0x00002080, + 0x00800081, 0x00000001, 0x00002080, 0x00800080, + 0x00002000, 0x00802080, 0x00802081, 0x00000081, + 0x00800080, 0x00800001, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00000000, 0x00802000, + 0x00002080, 0x00800080, 0x00800081, 0x00000001, + 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802081, 0x00000081, 0x00000001, 0x00002000, + 0x00800001, 0x00002001, 0x00802080, 0x00800081, + 0x00002001, 0x00002080, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002000, 0x00802080 +}; + +static const uint32_t SB5[64] = +{ + 0x00000100, 0x02080100, 0x02080000, 0x42000100, + 0x00080000, 0x00000100, 0x40000000, 0x02080000, + 0x40080100, 0x00080000, 0x02000100, 0x40080100, + 0x42000100, 0x42080000, 0x00080100, 0x40000000, + 0x02000000, 0x40080000, 0x40080000, 0x00000000, + 0x40000100, 0x42080100, 0x42080100, 0x02000100, + 0x42080000, 0x40000100, 0x00000000, 0x42000000, + 0x02080100, 0x02000000, 0x42000000, 0x00080100, + 0x00080000, 0x42000100, 0x00000100, 0x02000000, + 0x40000000, 0x02080000, 0x42000100, 0x40080100, + 0x02000100, 0x40000000, 0x42080000, 0x02080100, + 0x40080100, 0x00000100, 0x02000000, 0x42080000, + 0x42080100, 0x00080100, 0x42000000, 0x42080100, + 0x02080000, 0x00000000, 0x40080000, 0x42000000, + 0x00080100, 0x02000100, 0x40000100, 0x00080000, + 0x00000000, 0x40080000, 0x02080100, 0x40000100 +}; + +static const uint32_t SB6[64] = +{ + 0x20000010, 0x20400000, 0x00004000, 0x20404010, + 0x20400000, 0x00000010, 0x20404010, 0x00400000, + 0x20004000, 0x00404010, 0x00400000, 0x20000010, + 0x00400010, 0x20004000, 0x20000000, 0x00004010, + 0x00000000, 0x00400010, 0x20004010, 0x00004000, + 0x00404000, 0x20004010, 0x00000010, 0x20400010, + 0x20400010, 0x00000000, 0x00404010, 0x20404000, + 0x00004010, 0x00404000, 0x20404000, 0x20000000, + 0x20004000, 0x00000010, 0x20400010, 0x00404000, + 0x20404010, 0x00400000, 0x00004010, 0x20000010, + 0x00400000, 0x20004000, 0x20000000, 0x00004010, + 0x20000010, 0x20404010, 0x00404000, 0x20400000, + 0x00404010, 0x20404000, 0x00000000, 0x20400010, + 0x00000010, 0x00004000, 0x20400000, 0x00404010, + 0x00004000, 0x00400010, 0x20004010, 0x00000000, + 0x20404000, 0x20000000, 0x00400010, 0x20004010 +}; + +static const uint32_t SB7[64] = +{ + 0x00200000, 0x04200002, 0x04000802, 0x00000000, + 0x00000800, 0x04000802, 0x00200802, 0x04200800, + 0x04200802, 0x00200000, 0x00000000, 0x04000002, + 0x00000002, 0x04000000, 0x04200002, 0x00000802, + 0x04000800, 0x00200802, 0x00200002, 0x04000800, + 0x04000002, 0x04200000, 0x04200800, 0x00200002, + 0x04200000, 0x00000800, 0x00000802, 0x04200802, + 0x00200800, 0x00000002, 0x04000000, 0x00200800, + 0x04000000, 0x00200800, 0x00200000, 0x04000802, + 0x04000802, 0x04200002, 0x04200002, 0x00000002, + 0x00200002, 0x04000000, 0x04000800, 0x00200000, + 0x04200800, 0x00000802, 0x00200802, 0x04200800, + 0x00000802, 0x04000002, 0x04200802, 0x04200000, + 0x00200800, 0x00000000, 0x00000002, 0x04200802, + 0x00000000, 0x00200802, 0x04200000, 0x00000800, + 0x04000002, 0x04000800, 0x00000800, 0x00200002 +}; + +static const uint32_t SB8[64] = +{ + 0x10001040, 0x00001000, 0x00040000, 0x10041040, + 0x10000000, 0x10001040, 0x00000040, 0x10000000, + 0x00040040, 0x10040000, 0x10041040, 0x00041000, + 0x10041000, 0x00041040, 0x00001000, 0x00000040, + 0x10040000, 0x10000040, 0x10001000, 0x00001040, + 0x00041000, 0x00040040, 0x10040040, 0x10041000, + 0x00001040, 0x00000000, 0x00000000, 0x10040040, + 0x10000040, 0x10001000, 0x00041040, 0x00040000, + 0x00041040, 0x00040000, 0x10041000, 0x00001000, + 0x00000040, 0x10040040, 0x00001000, 0x00041040, + 0x10001000, 0x00000040, 0x10000040, 0x10040000, + 0x10040040, 0x10000000, 0x00040000, 0x10001040, + 0x00000000, 0x10041040, 0x00040040, 0x10000040, + 0x10040000, 0x10001000, 0x10001040, 0x00000000, + 0x10041040, 0x00041000, 0x00041000, 0x00001040, + 0x00001040, 0x00040040, 0x10000000, 0x10041000 +}; + +/* PC1: left and right halves bit-swap */ + +static const uint32_t LHs[16] = +{ + 0x00000000, 0x00000001, 0x00000100, 0x00000101, + 0x00010000, 0x00010001, 0x00010100, 0x00010101, + 0x01000000, 0x01000001, 0x01000100, 0x01000101, + 0x01010000, 0x01010001, 0x01010100, 0x01010101 +}; + +static const uint32_t RHs[16] = +{ + 0x00000000, 0x01000000, 0x00010000, 0x01010000, + 0x00000100, 0x01000100, 0x00010100, 0x01010100, + 0x00000001, 0x01000001, 0x00010001, 0x01010001, + 0x00000101, 0x01000101, 0x00010101, 0x01010101, +}; + +/* platform-independant 32-bit integer manipulation macros */ + +#define GET_UINT32(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} + +#define PUT_UINT32(n,b,i) \ +{ \ + (b)[(i) ] = (uint8_t) ( (n) >> 24 ); \ + (b)[(i) + 1] = (uint8_t) ( (n) >> 16 ); \ + (b)[(i) + 2] = (uint8_t) ( (n) >> 8 ); \ + (b)[(i) + 3] = (uint8_t) ( (n) ); \ +} + +/* Initial Permutation macro */ + +#define DES_IP(X,Y) \ +{ \ + T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \ + T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \ + T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \ + T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \ + Y = ((Y << 1) | (Y >> 31)) & 0xFFFFFFFF; \ + T = (X ^ Y) & 0xAAAAAAAA; Y ^= T; X ^= T; \ + X = ((X << 1) | (X >> 31)) & 0xFFFFFFFF; \ +} + +/* Final Permutation macro */ + +#define DES_FP(X,Y) \ +{ \ + X = ((X << 31) | (X >> 1)) & 0xFFFFFFFF; \ + T = (X ^ Y) & 0xAAAAAAAA; X ^= T; Y ^= T; \ + Y = ((Y << 31) | (Y >> 1)) & 0xFFFFFFFF; \ + T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \ + T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \ + T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \ + T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \ +} + +/* DES round macro */ + +#define DES_ROUND(X,Y) \ +{ \ + T = *SK++ ^ X; \ + Y ^= SB8[ (T ) & 0x3F ] ^ \ + SB6[ (T >> 8) & 0x3F ] ^ \ + SB4[ (T >> 16) & 0x3F ] ^ \ + SB2[ (T >> 24) & 0x3F ]; \ + \ + T = *SK++ ^ ((X << 28) | (X >> 4)); \ + Y ^= SB7[ (T ) & 0x3F ] ^ \ + SB5[ (T >> 8) & 0x3F ] ^ \ + SB3[ (T >> 16) & 0x3F ] ^ \ + SB1[ (T >> 24) & 0x3F ]; \ +} + +/* DES key schedule */ + +int des_main_ks( uint32_t SK[32], const uint8_t key[8] ) +{ + int i; + uint32_t X, Y, T; + + GET_UINT32( X, key, 0 ); + GET_UINT32( Y, key, 4 ); + + /* Permuted Choice 1 */ + + T = ((Y >> 4) ^ X) & 0x0F0F0F0F; X ^= T; Y ^= (T << 4); + T = ((Y ) ^ X) & 0x10101010; X ^= T; Y ^= (T ); + + X = (LHs[ (X ) & 0xF] << 3) | (LHs[ (X >> 8) & 0xF ] << 2) + | (LHs[ (X >> 16) & 0xF] << 1) | (LHs[ (X >> 24) & 0xF ] ) + | (LHs[ (X >> 5) & 0xF] << 7) | (LHs[ (X >> 13) & 0xF ] << 6) + | (LHs[ (X >> 21) & 0xF] << 5) | (LHs[ (X >> 29) & 0xF ] << 4); + + Y = (RHs[ (Y >> 1) & 0xF] << 3) | (RHs[ (Y >> 9) & 0xF ] << 2) + | (RHs[ (Y >> 17) & 0xF] << 1) | (RHs[ (Y >> 25) & 0xF ] ) + | (RHs[ (Y >> 4) & 0xF] << 7) | (RHs[ (Y >> 12) & 0xF ] << 6) + | (RHs[ (Y >> 20) & 0xF] << 5) | (RHs[ (Y >> 28) & 0xF ] << 4); + + X &= 0x0FFFFFFF; + Y &= 0x0FFFFFFF; + + /* calculate subkeys */ + + for( i = 0; i < 16; i++ ) + { + if( i < 2 || i == 8 || i == 15 ) + { + X = ((X << 1) | (X >> 27)) & 0x0FFFFFFF; + Y = ((Y << 1) | (Y >> 27)) & 0x0FFFFFFF; + } + else + { + X = ((X << 2) | (X >> 26)) & 0x0FFFFFFF; + Y = ((Y << 2) | (Y >> 26)) & 0x0FFFFFFF; + } + + *SK++ = ((X << 4) & 0x24000000) | ((X << 28) & 0x10000000) + | ((X << 14) & 0x08000000) | ((X << 18) & 0x02080000) + | ((X << 6) & 0x01000000) | ((X << 9) & 0x00200000) + | ((X >> 1) & 0x00100000) | ((X << 10) & 0x00040000) + | ((X << 2) & 0x00020000) | ((X >> 10) & 0x00010000) + | ((Y >> 13) & 0x00002000) | ((Y >> 4) & 0x00001000) + | ((Y << 6) & 0x00000800) | ((Y >> 1) & 0x00000400) + | ((Y >> 14) & 0x00000200) | ((Y ) & 0x00000100) + | ((Y >> 5) & 0x00000020) | ((Y >> 10) & 0x00000010) + | ((Y >> 3) & 0x00000008) | ((Y >> 18) & 0x00000004) + | ((Y >> 26) & 0x00000002) | ((Y >> 24) & 0x00000001); + + *SK++ = ((X << 15) & 0x20000000) | ((X << 17) & 0x10000000) + | ((X << 10) & 0x08000000) | ((X << 22) & 0x04000000) + | ((X >> 2) & 0x02000000) | ((X << 1) & 0x01000000) + | ((X << 16) & 0x00200000) | ((X << 11) & 0x00100000) + | ((X << 3) & 0x00080000) | ((X >> 6) & 0x00040000) + | ((X << 15) & 0x00020000) | ((X >> 4) & 0x00010000) + | ((Y >> 2) & 0x00002000) | ((Y << 8) & 0x00001000) + | ((Y >> 14) & 0x00000808) | ((Y >> 9) & 0x00000400) + | ((Y ) & 0x00000200) | ((Y << 7) & 0x00000100) + | ((Y >> 7) & 0x00000020) | ((Y >> 3) & 0x00000011) + | ((Y << 2) & 0x00000004) | ((Y >> 21) & 0x00000002); + } + + return( 0 ); +} + +#if TEST +int des_set_key( des_context *ctx, uint8_t key[8] ) +{ + int i; + + /* setup encryption subkeys */ + + des_main_ks( ctx->esk, key ); + + /* setup decryption subkeys */ + + for( i = 0; i < 32; i += 2 ) + { + ctx->dsk[i ] = ctx->esk[30 - i]; + ctx->dsk[i + 1] = ctx->esk[31 - i]; + } + + return( 0 ); +} + +/* DES 64-bit block encryption/decryption */ + +void des_crypt( uint32_t SK[32], uint8_t input[8], uint8_t output[8] ) +{ + uint32_t X, Y, T; + + GET_UINT32( X, input, 0 ); + GET_UINT32( Y, input, 4 ); + + DES_IP( X, Y ); + + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + + DES_FP( Y, X ); + + PUT_UINT32( Y, output, 0 ); + PUT_UINT32( X, output, 4 ); +} + +void des_encrypt( des_context *ctx, uint8_t input[8], uint8_t output[8] ) +{ + des_crypt( ctx->esk, input, output ); +} + +void des_decrypt( des_context *ctx, uint8_t input[8], uint8_t output[8] ) +{ + des_crypt( ctx->dsk, input, output ); +} + +/* Triple-DES key schedule */ + +int des3_set_2keys( des3_context *ctx, const uint8_t key1[8], const uint8_t key2[8] ) +{ + int i; + + des_main_ks( ctx->esk , key1 ); + des_main_ks( ctx->dsk + 32, key2 ); + + for( i = 0; i < 32; i += 2 ) + { + ctx->dsk[i ] = ctx->esk[30 - i]; + ctx->dsk[i + 1] = ctx->esk[31 - i]; + + ctx->esk[i + 32] = ctx->dsk[62 - i]; + ctx->esk[i + 33] = ctx->dsk[63 - i]; + + ctx->esk[i + 64] = ctx->esk[ i]; + ctx->esk[i + 65] = ctx->esk[ 1 + i]; + + ctx->dsk[i + 64] = ctx->dsk[ i]; + ctx->dsk[i + 65] = ctx->dsk[ 1 + i]; + } + + return( 0 ); +} +#endif + +int des3_set_3keys( des3_context *ctx, const uint8_t key1[8], const uint8_t key2[8], + const uint8_t key3[8] ) +{ + int i; + + des_main_ks( ctx->esk , key1 ); + des_main_ks( ctx->dsk + 32, key2 ); + des_main_ks( ctx->esk + 64, key3 ); + + for( i = 0; i < 32; i += 2 ) + { + ctx->dsk[i ] = ctx->esk[94 - i]; + ctx->dsk[i + 1] = ctx->esk[95 - i]; + + ctx->esk[i + 32] = ctx->dsk[62 - i]; + ctx->esk[i + 33] = ctx->dsk[63 - i]; + + ctx->dsk[i + 64] = ctx->esk[30 - i]; + ctx->dsk[i + 65] = ctx->esk[31 - i]; + } + + return( 0 ); +} + +/* Triple-DES 64-bit block encryption/decryption */ + +void des3_crypt( uint32_t SK[96], uint8_t input[8], uint8_t output[8] ) +{ + uint32_t X, Y, T; + + GET_UINT32( X, input, 0 ); + GET_UINT32( Y, input, 4 ); + + DES_IP( X, Y ); + + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + + DES_ROUND( X, Y ); DES_ROUND( Y, X ); + DES_ROUND( X, Y ); DES_ROUND( Y, X ); + DES_ROUND( X, Y ); DES_ROUND( Y, X ); + DES_ROUND( X, Y ); DES_ROUND( Y, X ); + DES_ROUND( X, Y ); DES_ROUND( Y, X ); + DES_ROUND( X, Y ); DES_ROUND( Y, X ); + DES_ROUND( X, Y ); DES_ROUND( Y, X ); + DES_ROUND( X, Y ); DES_ROUND( Y, X ); + + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + + DES_FP( Y, X ); + + PUT_UINT32( Y, output, 0 ); + PUT_UINT32( X, output, 4 ); +} + +void des3_encrypt( des3_context *ctx, uint8_t input[8], uint8_t output[8] ) +{ + des3_crypt( ctx->esk, input, output ); +} + +void des3_decrypt( des3_context *ctx, uint8_t input[8], uint8_t output[8] ) +{ + des3_crypt( ctx->dsk, input, output ); +} + +size_t ssl_des3_encrypt( const unsigned char *key, size_t key_len, const unsigned char *input, + size_t input_len, const unsigned char *iv, unsigned char **res ) +{ + des3_context ctx3; + size_t off; + uint8_t buf[8]; + + /* Keep it simple, for as long as this is just used for MSN auth anyway. */ + if( key_len != 24 || ( input_len % 8 ) != 0 ) + return 0; + + *res = g_malloc( input_len ); + des3_set_3keys( &ctx3, key, key + 8, key + 16 ); + + /* This loop does CBC 3DES. */ + memcpy( buf, iv, 8 ); + for( off = 0; off < input_len; off += 8 ) + { + int i; + + for( i = 0; i < 8; i ++ ) + buf[i] ^= input[off+i]; + des3_encrypt( &ctx3, buf, buf ); + memcpy( *res + off, buf, 8 ); + } + + return input_len; +} + +#ifdef TEST + +#include +#include + +/* + * Triple-DES Monte Carlo Test: ECB mode + * source: NIST - tripledes-vectors.zip + */ + +static const unsigned char DES3_keys[3][8] = +{ + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }, + { 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01 }, + { 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23 } +}; + +static const unsigned char DES3_init[8] = +{ + 0x4E, 0x6F, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74 +}; + +static const unsigned char DES3_enc_test[3][8] = +{ + { 0x6A, 0x2A, 0x19, 0xF4, 0x1E, 0xCA, 0x85, 0x4B }, + { 0x03, 0xE6, 0x9F, 0x5B, 0xFA, 0x58, 0xEB, 0x42 }, + { 0xDD, 0x17, 0xE8, 0xB8, 0xB4, 0x37, 0xD2, 0x32 } +}; + +static const unsigned char DES3_dec_test[3][8] = +{ + { 0xCD, 0xD6, 0x4F, 0x2F, 0x94, 0x27, 0xC1, 0x5D }, + { 0x69, 0x96, 0xC8, 0xFA, 0x47, 0xA2, 0xAB, 0xEB }, + { 0x83, 0x25, 0x39, 0x76, 0x44, 0x09, 0x1A, 0x0A } +}; + +int main( void ) +{ + int m, n, i; + des_context ctx; + des3_context ctx3; + unsigned char buf[8]; + + for( m = 0; m < 2; m++ ) + { + printf( "\n Triple-DES Monte Carlo Test (ECB mode) - " ); + + if( m == 0 ) printf( "encryption\n\n" ); + if( m == 1 ) printf( "decryption\n\n" ); + + for( n = 0; n < 3; n++ ) + { + printf( " Test %d, key size = %3d bits: ", + n + 1, 64 + n * 64 ); + + fflush( stdout ); + + memcpy( buf, DES3_init, 8 ); + + switch( n ) + { + case 0: + des_set_key( &ctx, DES3_keys[0] ); + break; + + case 1: + des3_set_2keys( &ctx3, DES3_keys[0], + DES3_keys[1] ); + break; + + case 2: + des3_set_3keys( &ctx3, DES3_keys[0], + DES3_keys[1], + DES3_keys[2] ); + break; + } + + for( i = 0; i < 10000; i++ ) + { + if( n == 0 ) + { + if( m == 0 ) des_encrypt( &ctx, buf, buf ); + if( m == 1 ) des_decrypt( &ctx, buf, buf ); + } + else + { + if( m == 0 ) des3_encrypt( &ctx3, buf, buf ); + if( m == 1 ) des3_decrypt( &ctx3, buf, buf ); + } + } + + if( ( m == 0 && memcmp( buf, DES3_enc_test[n], 8 ) ) || + ( m == 1 && memcmp( buf, DES3_dec_test[n], 8 ) ) ) + { + printf( "failed!\n" ); + return( 1 ); + } + + printf( "passed.\n" ); + } + } + + printf( "\n" ); + + return( 0 ); +} + +#endif diff --git a/lib/des.h b/lib/des.h new file mode 100644 index 00000000..92fbfd22 --- /dev/null +++ b/lib/des.h @@ -0,0 +1,51 @@ +/* + * FIPS-46-3 compliant 3DES implementation + * + * Copyright (C) 2001-2003 Christophe Devine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _DES_H +#define _DES_H + +#include + +typedef struct +{ + uint32_t esk[32]; /* DES encryption subkeys */ + uint32_t dsk[32]; /* DES decryption subkeys */ +} +des_context; + +typedef struct +{ + uint32_t esk[96]; /* Triple-DES encryption subkeys */ + uint32_t dsk[96]; /* Triple-DES decryption subkeys */ +} +des3_context; + +int des_set_key( des_context *ctx, uint8_t key[8] ); +void des_encrypt( des_context *ctx, uint8_t input[8], uint8_t output[8] ); +void des_decrypt( des_context *ctx, uint8_t input[8], uint8_t output[8] ); + +int des3_set_2keys( des3_context *ctx, const uint8_t key1[8], const uint8_t key2[8] ); +int des3_set_3keys( des3_context *ctx, const uint8_t key1[8], const uint8_t key2[8], + const uint8_t key3[8] ); + +void des3_encrypt( des3_context *ctx, uint8_t input[8], uint8_t output[8] ); +void des3_decrypt( des3_context *ctx, uint8_t input[8], uint8_t output[8] ); + +#endif /* des.h */ -- cgit v1.2.3 From 327af51a28fe292cfc4a68caa086a13175a69719 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 21 Aug 2010 18:27:32 +0100 Subject: Some general cleanup, plus fixing a bug in the memberlist parsing code: the lists can come in in any order, so parse it *completely* before showing auth requests. --- doc/CHANGES | 9 +++++++-- lib/ssl_gnutls.c | 4 ++-- lib/ssl_openssl.c | 4 ++-- lib/xmltree.c | 12 ++++++++++-- protocols/msn/soap.c | 19 ++++++++++++------- 5 files changed, 33 insertions(+), 15 deletions(-) diff --git a/doc/CHANGES b/doc/CHANGES index d313c5d3..cfd524dc 100644 --- a/doc/CHANGES +++ b/doc/CHANGES @@ -3,7 +3,7 @@ found in the bzr commit logs, for example you can try: http://bugs.bitlbee.org/bitlbee/timeline?daysback=90&changeset=on -Version 1.3dev: +Version ... - For the first time since 2007, a dev snapshot. Like then, this is pretty stable already (running on testing.bitlbee.org for weeks by now), but not all planned features for the next major release are ready yet, and there @@ -51,6 +51,11 @@ Version 1.3dev: * Switching to libpurple should be pretty transparent. See "help purple" for a list of supported protocols (works only in libpurple-enabled binaries). +- Rewritten MSN module, implementing MSNP15 instead of the old MSNP8: + * MSNP8 support from MSN was getting pretty unreliable. There were issues + with remembering display names and adding contacts/auth requests. + * Support for sending offline messages. + * Support for setting and reading status messages. - Support for file transfers, in and out. /DCC SEND a file to a contact and it becomes a file transfer, and incoming file transfers become /DCC SENDs to you. Note that this is mostly useful when combined with libpurple, as @@ -58,7 +63,7 @@ Version 1.3dev: - Updated Yahoo! module to be in sync again with libyahoo2. This mostly fixes issues with authorization requests. -Finished 6 Aug 2010 +Finished ... Version 1.2.8: - Now always using the AIM-style authentication method for OSCAR connections, diff --git a/lib/ssl_gnutls.c b/lib/ssl_gnutls.c index 15c23dbb..4fc7c33f 100644 --- a/lib/ssl_gnutls.c +++ b/lib/ssl_gnutls.c @@ -188,7 +188,7 @@ int ssl_read( void *conn, char *buf, int len ) if( st == GNUTLS_E_AGAIN || st == GNUTLS_E_INTERRUPTED ) ssl_errno = SSL_AGAIN; - if( getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st ); + if( 0 && getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st ); return st; } @@ -209,7 +209,7 @@ int ssl_write( void *conn, const char *buf, int len ) if( st == GNUTLS_E_AGAIN || st == GNUTLS_E_INTERRUPTED ) ssl_errno = SSL_AGAIN; - if( getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st ); + if( 0 && getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st ); return st; } diff --git a/lib/ssl_openssl.c b/lib/ssl_openssl.c index 0feed4ca..e0143791 100644 --- a/lib/ssl_openssl.c +++ b/lib/ssl_openssl.c @@ -206,7 +206,7 @@ int ssl_read( void *conn, char *buf, int len ) ssl_errno = SSL_AGAIN; } - if( getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st ); + if( 0 && getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st ); return st; } @@ -223,7 +223,7 @@ int ssl_write( void *conn, const char *buf, int len ) st = SSL_write( ((struct scd*)conn)->ssl, buf, len ); - if( getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st ); + if( 0 && getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st ); ssl_errno = SSL_OK; if( st <= 0 ) diff --git a/lib/xmltree.c b/lib/xmltree.c index 3ec7e673..bee9007f 100644 --- a/lib/xmltree.c +++ b/lib/xmltree.c @@ -337,7 +337,11 @@ void xt_print( struct xt_node *node ) /* Print the attributes */ for( i = 0; node->attr[i].key; i ++ ) - printf( " %s=\"%s\"", node->attr[i].key, g_markup_escape_text( node->attr[i].value, -1 ) ); + { + char *v = g_markup_escape_text( node->attr[i].value, -1 ); + printf( " %s=\"%s\"", node->attr[i].key, v ); + g_free( v ); + } /* /> in case there's really *nothing* inside this tag, otherwise just >. */ @@ -357,7 +361,11 @@ void xt_print( struct xt_node *node ) { for( i = 0; node->text[i] && isspace( node->text[i] ); i ++ ); if( node->text[i] ) - printf( "%s", g_markup_escape_text( node->text, -1 ) ); + { + char *v = g_markup_escape_text( node->text, -1 ); + printf( "%s", v ); + g_free( v ); + } } if( node->children ) diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c index e67da2a1..8d276108 100644 --- a/protocols/msn/soap.c +++ b/protocols/msn/soap.c @@ -553,17 +553,11 @@ static xt_status msn_soap_memlist_member( struct xt_node *node, gpointer data ) else if( strcmp( role, "Block" ) == 0 ) bd->flags |= MSN_BUDDY_BL; else if( strcmp( role, "Reverse" ) == 0 ) - { bd->flags |= MSN_BUDDY_RL; - msn_buddy_ask( bu ); - } else if( strcmp( role, "Pending" ) == 0 ) - { bd->flags |= MSN_BUDDY_PL; - msn_buddy_ask( bu ); - } - printf( "%s %d\n", handle, bd->flags ); + printf( "%p %s %d\n", bu, handle, bd->flags ); return XT_HANDLED; } @@ -782,7 +776,18 @@ static const struct xt_handler_entry msn_soap_addressbook_parser[] = { static int msn_soap_addressbook_handle_response( struct msn_soap_req_data *soap_req ) { + GSList *l; + + for( l = soap_req->ic->bee->users; l; l = l->next ) + { + struct bee_user *bu = l->data; + + if( bu->ic == soap_req->ic ) + msn_buddy_ask( bu ); + } + msn_auth_got_contact_list( soap_req->ic ); + return MSN_SOAP_OK; } -- cgit v1.2.3 From fd424c891db6da587cce3da8ac98ab7dfa986fb3 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 22 Aug 2010 00:08:33 +0100 Subject: Also pick up MSN Messenger mobile info. --- protocols/msn/ns.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index 4b779a58..bd13c3a6 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -332,8 +332,9 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) else if( strcmp( cmd[0], "NLN" ) == 0 ) { const struct msn_away_state *st; + int cap; - if( num_parts < 5 ) + if( num_parts < 6 ) { imcb_error( ic, "Syntax error" ); imc_logout( ic, TRUE ); @@ -341,6 +342,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) } http_decode( cmd[4] ); + cap = atoi( cmd[5] ); imcb_rename_buddy( ic, cmd[2], cmd[4] ); st = msn_away_state_by_code( cmd[1] ); @@ -351,7 +353,8 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) } imcb_buddy_status( ic, cmd[2], OPT_LOGGED_IN | - ( st != msn_away_state_list ? OPT_AWAY : 0 ), + ( st != msn_away_state_list ? OPT_AWAY : 0 ) | + ( cap & 1 ? OPT_MOBILE : 0 ), st->name, NULL ); msn_sb_stop_keepalives( msn_sb_by_handle( ic, cmd[2] ) ); -- cgit v1.2.3 From 9b1d2d6fa7edb911e3dbcd8785aaa797ebb20d0a Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 22 Aug 2010 11:42:27 +0100 Subject: Ignore empty status messages, and msnmsgrp2p invitations. --- protocols/bee_user.c | 2 +- protocols/msn/sb.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/protocols/bee_user.c b/protocols/bee_user.c index 71b15d29..1f9b1b47 100644 --- a/protocols/bee_user.c +++ b/protocols/bee_user.c @@ -222,7 +222,7 @@ void imcb_buddy_status_msg( struct im_connection *ic, const char *handle, const old = g_memdup( bu, sizeof( bee_user_t ) ); - bu->status_msg = g_strdup( message ); + bu->status_msg = message && *message ? g_strdup( message ) : NULL; if( bee->ui->user_status ) bee->ui->user_status( bee, bu, old ); diff --git a/protocols/msn/sb.c b/protocols/msn/sb.c index fdad2882..75417fae 100644 --- a/protocols/msn/sb.c +++ b/protocols/msn/sb.c @@ -751,8 +751,8 @@ static int msn_sb_message( gpointer data, char *msg, int msglen, char **cmd, int #endif else if( g_strncasecmp( ct, "application/x-msnmsgrp2p", 24 ) == 0 ) { - imcb_error( sb->ic, "Cannot receive file from %s: BitlBee does not " - "support msnmsgrp2p yet.", sb->who ); + /* Not currently implemented. Don't warn about it since + this seems to be used for avatars now. */ g_free( ct ); } else if( g_strncasecmp( ct, "text/x-msmsgscontrol", 20 ) == 0 ) -- cgit v1.2.3 From 00374acf3061c2c6c34fd2eda42e452211f7c4f9 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 28 Aug 2010 14:22:50 +0200 Subject: Don't treat error 241 as fatal since it isn't - or at least not always. --- protocols/msn/tables.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocols/msn/tables.c b/protocols/msn/tables.c index 191abe43..273d291e 100644 --- a/protocols/msn/tables.c +++ b/protocols/msn/tables.c @@ -83,7 +83,7 @@ const struct msn_status_code msn_status_code_list[] = { 230, "Cannot remove that group", 0 }, { 231, "Invalid group", 0 }, { 240, "ADL/RML command with corrupted payload", STATUS_FATAL }, - { 241, "ADL/RML command with invalid modification", STATUS_FATAL }, + { 241, "ADL/RML command with invalid modification", 0 }, { 280, "Switchboard failed", STATUS_SB_FATAL }, { 281, "Transfer to switchboard failed", 0 }, -- cgit v1.2.3 From 02bb9db2edd535036e030e004a58ed1459c15bb8 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 29 Aug 2010 11:39:27 +0200 Subject: Handle payloads attached to errors (assume any number in cmd[2] would be a payload length, which seems like a fair assumption). This should solve problems with logging in with dodgy contact/membership lists. --- protocols/msn/ns.c | 4 ++++ protocols/nogaim.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index bd13c3a6..fa445aa7 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -518,6 +518,10 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) imc_logout( ic, TRUE ); return( 0 ); } + + /* Oh yes, errors can have payloads too now. Discard them for now. */ + if( num_parts >= 3 ) + md->handler->msglen = atoi( cmd[2] ); } else { diff --git a/protocols/nogaim.c b/protocols/nogaim.c index 10ffd843..aa3ad5bb 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -251,7 +251,7 @@ void imcb_error( struct im_connection *ic, char *format, ... ) if( ic->flags & OPT_LOGGED_IN ) serv_got_crap( ic, "Error: %s", text ); else - serv_got_crap( ic, "Couldn't log in: %s", text ); + serv_got_crap( ic, "Login error: %s", text ); g_free( text ); } -- cgit v1.2.3 From 64768d4ec0c3ad473573c3f3c34871e0081b4e59 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Thu, 2 Sep 2010 10:15:44 +0100 Subject: Replace msn*write functions with saner versions that accept format strings. Also preparing for additional temporary NS connections (auth token renewal). --- protocols/msn/msn.c | 14 ++++----- protocols/msn/msn.h | 4 +-- protocols/msn/msn_util.c | 43 ++++++--------------------- protocols/msn/ns.c | 75 +++++++++++++++++++++++++++++------------------- protocols/msn/sb.c | 57 ++++++++++++++++-------------------- 5 files changed, 87 insertions(+), 106 deletions(-) diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c index 4b79cc26..f37b802e 100644 --- a/protocols/msn/msn.c +++ b/protocols/msn/msn.c @@ -153,8 +153,7 @@ static int msn_buddy_msg( struct im_connection *ic, char *who, char *message, in #ifdef DEBUG if( strcmp( who, "raw" ) == 0 ) { - msn_write( ic, message, strlen( message ) ); - msn_write( ic, "\r\n", 2 ); + msn_ns_write( ic, -1, "%s\r\n", message ); } else #endif @@ -192,7 +191,6 @@ static GList *msn_away_states( struct im_connection *ic ) static void msn_set_away( struct im_connection *ic, char *state, char *message ) { - char buf[1024]; char *uux; struct msn_data *md = ic->proto_data; @@ -201,15 +199,13 @@ static void msn_set_away( struct im_connection *ic, char *state, char *message ) else if( ( md->away_state = msn_away_state_by_name( state ) ) == NULL ) md->away_state = msn_away_state_list + 1; - g_snprintf( buf, sizeof( buf ), "CHG %d %s\r\n", ++md->trId, md->away_state->code ); - if( !msn_write( ic, buf, strlen( buf ) ) ) + if( !msn_ns_write( ic, -1, "CHG %d %s\r\n", ++md->trId, md->away_state->code ) ) return; uux = g_markup_printf_escaped( "%s" "", message ? message : "" ); - g_snprintf( buf, sizeof( buf ), "UUX %d %zd\r\n%s", ++md->trId, strlen( uux ), uux ); - if( !msn_write( ic, buf, strlen( buf ) ) ) - return; + msn_ns_write( ic, -1, "UUX %d %zd\r\n%s", ++md->trId, strlen( uux ), uux ); + g_free( uux ); } static void msn_get_info(struct im_connection *ic, char *who) @@ -289,7 +285,7 @@ static struct groupchat *msn_chat_with( struct im_connection *ic, char *who ) static void msn_keepalive( struct im_connection *ic ) { - msn_write( ic, "PNG\r\n", strlen( "PNG\r\n" ) ); + msn_ns_write( ic, -1, "PNG\r\n" ); } static void msn_add_permit( struct im_connection *ic, char *who ) diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h index 7cb3241c..dae115ef 100644 --- a/protocols/msn/msn.h +++ b/protocols/msn/msn.h @@ -207,13 +207,13 @@ extern GSList *msn_connections; extern GSList *msn_switchboards; /* ns.c */ +int msn_ns_write( struct im_connection *ic, int fd, const char *fmt, ... ); gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ); void msn_auth_got_passport_token( struct im_connection *ic, const char *token, const char *error ); void msn_auth_got_contact_list( struct im_connection *ic ); int msn_ns_finish_login( struct im_connection *ic ); /* msn_util.c */ -int msn_write( struct im_connection *ic, char *s, int len ); int msn_logged_in( struct im_connection *ic ); int msn_buddy_list_add( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *realname_, const char *group ); int msn_buddy_list_remove( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group ); @@ -235,7 +235,7 @@ const struct msn_away_state *msn_away_state_by_name( char *name ); const struct msn_status_code *msn_status_by_number( int number ); /* sb.c */ -int msn_sb_write( struct msn_switchboard *sb, char *s, int len ); +int msn_sb_write( struct msn_switchboard *sb, const char *fmt, ... ); struct msn_switchboard *msn_sb_create( struct im_connection *ic, char *host, int port, char *key, int session ); struct msn_switchboard *msn_sb_by_handle( struct im_connection *ic, char *handle ); struct msn_switchboard *msn_sb_by_chat( struct groupchat *c ); diff --git a/protocols/msn/msn_util.c b/protocols/msn/msn_util.c index 78f81a41..6a16ba17 100644 --- a/protocols/msn/msn_util.c +++ b/protocols/msn/msn_util.c @@ -29,28 +29,6 @@ #include "soap.h" #include -int msn_write( struct im_connection *ic, char *s, int len ) -{ - struct msn_data *md = ic->proto_data; - int st; - - if( getenv( "BITLBEE_DEBUG" ) ) - { - write( 2, "->NS:", 5 ); - write( 2, s, len ); - } - - st = write( md->fd, s, len ); - if( st != len ) - { - imcb_error( ic, "Short write() to main server" ); - imc_logout( ic, TRUE ); - return 0; - } - - return 1; -} - int msn_logged_in( struct im_connection *ic ) { imcb_connected( ic ); @@ -75,7 +53,7 @@ static char *adlrml_entry( const char *handle_, msn_buddy_flags_t list ) int msn_buddy_list_add( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *realname, const char *group ) { struct msn_data *md = ic->proto_data; - char buf[1024], groupid[8]; + char groupid[8]; bee_user_t *bu; struct msn_buddy_data *bd; char *adl; @@ -143,11 +121,11 @@ int msn_buddy_list_add( struct im_connection *ic, msn_buddy_flags_t list, const if( ( adl = adlrml_entry( who, list ) ) ) { - g_snprintf( buf, sizeof( buf ), "ADL %d %zd\r\n%s", - ++md->trId, strlen( adl ), adl ); + int st = msn_ns_write( ic, -1, "ADL %d %zd\r\n%s", + ++md->trId, strlen( adl ), adl ); g_free( adl ); - return msn_write( ic, buf, strlen( buf ) ); + return st; } return 1; @@ -156,7 +134,7 @@ int msn_buddy_list_add( struct im_connection *ic, msn_buddy_flags_t list, const int msn_buddy_list_remove( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group ) { struct msn_data *md = ic->proto_data; - char buf[1024], groupid[8]; + char groupid[8]; bee_user_t *bu; struct msn_buddy_data *bd; char *adl; @@ -188,11 +166,11 @@ int msn_buddy_list_remove( struct im_connection *ic, msn_buddy_flags_t list, con if( ( adl = adlrml_entry( who, list ) ) ) { - g_snprintf( buf, sizeof( buf ), "RML %d %zd\r\n%s", - ++md->trId, strlen( adl ), adl ); + int st = msn_ns_write( ic, -1, "RML %d %zd\r\n%s", + ++md->trId, strlen( adl ), adl ); g_free( adl ); - return msn_write( ic, buf, strlen( buf ) ); + return st; } return 1; @@ -602,14 +580,11 @@ int msn_ns_set_display_name( struct im_connection *ic, const char *value ) { struct msn_data *md = ic->proto_data; char fn[strlen(value)*3+1]; - char buf[512]; strcpy( fn, value ); http_encode( fn ); - g_snprintf( buf, sizeof( buf ), "PRP %d MFN %s\r\n", - ++md->trId, fn ); /* Note: We don't actually know if the server accepted the new name, and won't give proper feedback yet if it doesn't. */ - return msn_write( ic, buf, strlen( buf ) ); + return msn_ns_write( ic, -1, "PRP %d MFN %s\r\n", ++md->trId, fn ); } diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index fa445aa7..23a1951d 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -37,11 +37,41 @@ static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int static void msn_ns_send_adl_start( struct im_connection *ic ); static void msn_ns_send_adl( struct im_connection *ic ); +int msn_ns_write( struct im_connection *ic, int fd, const char *fmt, ... ) +{ + struct msn_data *md = ic->proto_data; + va_list params; + char *out; + size_t len; + int st; + + va_start( params, fmt ); + out = g_strdup_vprintf( fmt, params ); + va_end( params ); + + if( fd < 0 ) + fd = md->fd; + + if( getenv( "BITLBEE_DEBUG" ) ) + fprintf( stderr, "->NS%d:%s", fd, out ); + + len = strlen( out ); + st = write( fd, out, len ); + g_free( out ); + if( st != len ) + { + imcb_error( ic, "Short write() to main server" ); + imc_logout( ic, TRUE ); + return 0; + } + + return 1; +} + gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ) { struct im_connection *ic = data; struct msn_data *md; - char s[1024]; if( !g_slist_find( msn_connections, ic ) ) return FALSE; @@ -73,8 +103,7 @@ gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ) md->handler->fd = md->fd; md->handler->rxq = g_new0( char, 1 ); - g_snprintf( s, sizeof( s ), "VER %d %s CVR0\r\n", ++md->trId, MSNP_VER ); - if( msn_write( ic, s, strlen( s ) ) ) + if( msn_ns_write( ic, -1, "VER %d %s CVR0\r\n", ++md->trId, MSNP_VER ) ) { ic->inpa = b_input_add( md->fd, B_EV_IO_READ, msn_ns_callback, ic ); imcb_log( ic, "Connected to server, waiting for reply" ); @@ -103,7 +132,6 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) { struct im_connection *ic = data; struct msn_data *md = ic->proto_data; - char buf[1024]; if( num_parts == 0 ) { @@ -120,15 +148,13 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) return( 0 ); } - g_snprintf( buf, sizeof( buf ), "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s\r\n", - ++md->trId, ic->acc->user ); - return( msn_write( ic, buf, strlen( buf ) ) ); + return( msn_ns_write( ic, -1, "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s\r\n", + ++md->trId, ic->acc->user ) ); } else if( strcmp( cmd[0], "CVR" ) == 0 ) { /* We don't give a damn about the information we just received */ - g_snprintf( buf, sizeof( buf ), "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user ); - return( msn_write( ic, buf, strlen( buf ) ) ); + return msn_ns_write( ic, -1, "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user ); } else if( strcmp( cmd[0], "XFR" ) == 0 ) { @@ -279,6 +305,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) else if( strcmp( cmd[0], "CHL" ) == 0 ) { char *resp; + int st; if( num_parts < 3 ) { @@ -288,12 +315,12 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) } resp = msn_p11_challenge( cmd[2] ); - g_snprintf( buf, sizeof( buf ), "QRY %d %s %zd\r\n%s", - ++md->trId, MSNP11_PROD_ID, - strlen( resp ), resp ); - g_free( resp ); - return( msn_write( ic, buf, strlen( buf ) ) ); + st = msn_ns_write( ic, -1, "QRY %d %s %zd\r\n%s", + ++md->trId, MSNP11_PROD_ID, + strlen( resp ), resp ); + g_free( resp ); + return st; } else if( strcmp( cmd[0], "ILN" ) == 0 ) { @@ -698,10 +725,7 @@ void msn_auth_got_passport_token( struct im_connection *ic, const char *token, c if( token ) { - char buf[1536]; - - g_snprintf( buf, sizeof( buf ), "USR %d SSO S %s %s\r\n", ++md->trId, md->tokens[0], token ); - msn_write( ic, buf, strlen( buf ) ); + msn_ns_write( ic, -1, "USR %d SSO S %s %s\r\n", ++md->trId, md->tokens[0], token ); } else { @@ -712,7 +736,6 @@ void msn_auth_got_passport_token( struct im_connection *ic, const char *token, c void msn_auth_got_contact_list( struct im_connection *ic ) { - char buf[64]; struct msn_data *md; /* Dead connection? */ @@ -720,10 +743,7 @@ void msn_auth_got_contact_list( struct im_connection *ic ) return; md = ic->proto_data; - - - g_snprintf( buf, sizeof( buf ), "BLP %d %s\r\n", ++md->trId, "BL" ); - msn_write( ic, buf, strlen( buf ) ); + msn_ns_write( ic, -1, "BLP %d %s\r\n", ++md->trId, "BL" ); } static gboolean msn_ns_send_adl_1( gpointer key, gpointer value, gpointer data ) @@ -769,7 +789,7 @@ static void msn_ns_send_adl( struct im_connection *ic ) { struct xt_node *adl; struct msn_data *md = ic->proto_data; - char *adls, buf[64]; + char *adls; adl = xt_new_node( "ml", NULL, NULL ); xt_add_attr( adl, "l", "1" ); @@ -781,12 +801,9 @@ static void msn_ns_send_adl( struct im_connection *ic ) xt_free_node( adl ); return; } - adls = xt_to_string( adl ); - - g_snprintf( buf, sizeof( buf ), "ADL %d %zd\r\n", ++md->trId, strlen( adls ) ); - if( msn_write( ic, buf, strlen( buf ) ) ) - msn_write( ic, adls, strlen( adls ) ); + adls = xt_to_string( adl ); + msn_ns_write( ic, -1, "ADL %d %zd\r\n%s", ++md->trId, strlen( adls ), adls ); g_free( adls ); } diff --git a/protocols/msn/sb.c b/protocols/msn/sb.c index 75417fae..d10d7c19 100644 --- a/protocols/msn/sb.c +++ b/protocols/msn/sb.c @@ -34,31 +34,36 @@ static gboolean msn_sb_callback( gpointer data, gint source, b_input_condition c static int msn_sb_command( gpointer data, char **cmd, int num_parts ); static int msn_sb_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts ); -int msn_sb_write( struct msn_switchboard *sb, char *s, int len ) +int msn_sb_write( struct msn_switchboard *sb, const char *fmt, ... ) { + va_list params; + char *out; + size_t len; int st; + va_start( params, fmt ); + out = g_strdup_vprintf( fmt, params ); + va_end( params ); + if( getenv( "BITLBEE_DEBUG" ) ) - { - write( 2, "->SB:", 5 ); - write( 2, s, len ); - } + fprintf( stderr, "->SB%d:%s", sb->fd, out ); - st = write( sb->fd, s, len ); + len = strlen( out ); + st = write( sb->fd, out, len ); + g_free( out ); if( st != len ) { msn_sb_destroy( sb ); - return( 0 ); + return 0; } - return( 1 ); + return 1; } int msn_sb_write_msg( struct im_connection *ic, struct msn_message *m ) { struct msn_data *md = ic->proto_data; struct msn_switchboard *sb; - char buf[1024]; /* FIXME: *CHECK* the reliability of using spare sb's! */ if( ( sb = msn_sb_spare( ic ) ) ) @@ -66,8 +71,7 @@ int msn_sb_write_msg( struct im_connection *ic, struct msn_message *m ) debug( "Trying to use a spare switchboard to message %s", m->who ); sb->who = g_strdup( m->who ); - g_snprintf( buf, sizeof( buf ), "CAL %d %s\r\n", ++sb->trId, m->who ); - if( msn_sb_write( sb, buf, strlen( buf ) ) ) + if( msn_sb_write( sb, "CAL %d %s\r\n", ++sb->trId, m->who ) ) { /* He/She should join the switchboard soon, let's queue the message. */ sb->msgq = g_slist_append( sb->msgq, m ); @@ -78,8 +82,7 @@ int msn_sb_write_msg( struct im_connection *ic, struct msn_message *m ) debug( "Creating a new switchboard to message %s", m->who ); /* If we reach this line, there was no spare switchboard, so let's make one. */ - g_snprintf( buf, sizeof( buf ), "XFR %d SB\r\n", ++md->trId ); - if( !msn_write( ic, buf, strlen( buf ) ) ) + if( !msn_ns_write( ic, -1, "XFR %d SB\r\n", ++md->trId ) ) { g_free( m->who ); g_free( m->text ); @@ -170,7 +173,7 @@ int msn_sb_sendmessage( struct msn_switchboard *sb, char *text ) { if( sb->ready ) { - char *packet, *buf; + char *buf; int i, j; /* Build the message. Convert LF to CR-LF for normal messages. */ @@ -206,17 +209,15 @@ int msn_sb_sendmessage( struct msn_switchboard *sb, char *text ) } /* Build the final packet (MSG command + the message). */ - packet = g_strdup_printf( "MSG %d N %d\r\n%s", ++sb->trId, i, buf ); - g_free( buf ); - if( msn_sb_write( sb, packet, strlen( packet ) ) ) + if( msn_sb_write( sb, "MSG %d N %d\r\n%s", ++sb->trId, i, buf ) ) { - g_free( packet ); - return( 1 ); + g_free( buf ); + return 1; } else { - g_free( packet ); - return( 0 ); + g_free( buf ); + return 0; } } else if( sb->who ) @@ -331,7 +332,7 @@ gboolean msn_sb_connected( gpointer data, gint source, b_input_condition cond ) else g_snprintf( buf, sizeof( buf ), "ANS %d %s %s %d\r\n", ++sb->trId, ic->acc->user, sb->key, sb->session ); - if( msn_sb_write( sb, buf, strlen( buf ) ) ) + if( msn_sb_write( sb, "%s", buf ) ) sb->inp = b_input_add( sb->fd, B_EV_IO_READ, msn_sb_callback, sb ); else debug( "Error %d while connecting to switchboard server", 2 ); @@ -351,7 +352,6 @@ static gboolean msn_sb_callback( gpointer data, gint source, b_input_condition c if( sb->msgq != NULL ) { time_t now = time( NULL ); - char buf[1024]; if( now - md->first_sb_failure > 600 ) { @@ -383,8 +383,7 @@ static gboolean msn_sb_callback( gpointer data, gint source, b_input_condition c debug( "Moved queued messages back to the main queue, " "creating a new switchboard to retry." ); - g_snprintf( buf, sizeof( buf ), "XFR %d SB\r\n", ++md->trId ); - if( !msn_write( ic, buf, strlen( buf ) ) ) + if( !msn_ns_write( ic, -1, "XFR %d SB\r\n", ++md->trId ) ) return FALSE; } @@ -396,7 +395,6 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts ) { struct msn_switchboard *sb = data; struct im_connection *ic = sb->ic; - char buf[1024]; if( !num_parts ) { @@ -425,14 +423,9 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts ) } if( sb->who ) - { - g_snprintf( buf, sizeof( buf ), "CAL %d %s\r\n", ++sb->trId, sb->who ); - return( msn_sb_write( sb, buf, strlen( buf ) ) ); - } + return msn_sb_write( sb, "CAL %d %s\r\n", ++sb->trId, sb->who ); else - { debug( "Just created a switchboard, but I don't know what to do with it." ); - } } else if( strcmp( cmd[0], "IRO" ) == 0 ) { -- cgit v1.2.3 From bae06178bbe3863b39ec307c34d2781a53472272 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Fri, 3 Sep 2010 22:24:58 +0100 Subject: Rearrange things a bit to support multiple NS connections. This is apparently needed for refreshing auth. tokens. --- protocols/msn/msn.c | 27 +++-------- protocols/msn/msn.h | 41 +++++++++-------- protocols/msn/msn_util.c | 4 +- protocols/msn/ns.c | 114 ++++++++++++++++++++++++++++------------------- protocols/msn/sb.c | 12 ++--- 5 files changed, 105 insertions(+), 93 deletions(-) diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c index f37b802e..c5c05087 100644 --- a/protocols/msn/msn.c +++ b/protocols/msn/msn.c @@ -52,7 +52,6 @@ static void msn_login( account_t *acc ) struct msn_data *md = g_new0( struct msn_data, 1 ); ic->proto_data = md; - md->fd = -1; if( strchr( acc->user, '@' ) == NULL ) { @@ -61,21 +60,14 @@ static void msn_login( account_t *acc ) return; } - imcb_log( ic, "Connecting" ); - - md->fd = proxy_connect( "messenger.hotmail.com", 1863, msn_ns_connected, ic ); - if( md->fd < 0 ) - { - imcb_error( ic, "Could not connect to server" ); - imc_logout( ic, TRUE ); - return; - } - md->ic = ic; md->away_state = msn_away_state_list; md->domaintree = g_tree_new( msn_domaintree_cmp ); - msn_connections = g_slist_append( msn_connections, ic ); + msn_connections = g_slist_prepend( msn_connections, ic ); + + imcb_log( ic, "Connecting" ); + msn_ns_connect( ic, md->ns, MSN_NS_HOST, MSN_NS_PORT ); } static void msn_logout( struct im_connection *ic ) @@ -92,15 +84,8 @@ static void msn_logout( struct im_connection *ic ) } */ - if( md->fd >= 0 ) - closesocket( md->fd ); - - if( md->handler ) - { - if( md->handler->rxq ) g_free( md->handler->rxq ); - if( md->handler->cmd_text ) g_free( md->handler->cmd_text ); - g_free( md->handler ); - } + msn_ns_close( md->ns ); + msn_ns_close( md->auth ); while( md->switchboards ) msn_sb_destroy( md->switchboards->data ); diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h index dae115ef..5a195348 100644 --- a/protocols/msn/msn.h +++ b/protocols/msn/msn.h @@ -43,6 +43,9 @@ #define MSNP11_PROD_ID "PROD0101{0RM?UBW" */ +#define MSN_NS_HOST "messenger.hotmail.com" +#define MSN_NS_PORT 1863 + /* Some other version. #define MSNP11_PROD_KEY "O4BG@C7BWLYQX?5G" #define MSNP11_PROD_ID "PROD01065C%ZFN6F" @@ -79,12 +82,27 @@ typedef enum MSN_DONE_ADL = 4, } msn_flags_t; +struct msn_handler_data +{ + int fd, inpa; + int rxlen; + char *rxq; + + int msglen; + char *cmd_text; + + /* Either ic or sb */ + gpointer data; + + int (*exec_command) ( struct msn_handler_data *handler, char **cmd, int count ); + int (*exec_message) ( struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int count ); +}; + struct msn_data { struct im_connection *ic; - int fd; - struct msn_handler_data *handler; + struct msn_handler_data ns[1], auth[1]; msn_flags_t flags; int trId; @@ -110,6 +128,7 @@ struct msn_switchboard { struct im_connection *ic; + /* The following two are also in the handler. TODO: Clean up. */ int fd; gint inp; struct msn_handler_data *handler; @@ -151,21 +170,6 @@ struct msn_groupadd char *group; }; -struct msn_handler_data -{ - int fd; - int rxlen; - char *rxq; - - int msglen; - char *cmd_text; - - gpointer data; - - int (*exec_command) ( gpointer data, char **cmd, int count ); - int (*exec_message) ( gpointer data, char *msg, int msglen, char **cmd, int count ); -}; - typedef enum { MSN_BUDDY_FL = 1, /* Warning: FL,AL,BL *must* be 1,2,4. */ @@ -208,7 +212,8 @@ extern GSList *msn_switchboards; /* ns.c */ int msn_ns_write( struct im_connection *ic, int fd, const char *fmt, ... ); -gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ); +gboolean msn_ns_connect( struct im_connection *ic, struct msn_handler_data *handler, const char *host, int port ); +void msn_ns_close( struct msn_handler_data *handler ); void msn_auth_got_passport_token( struct im_connection *ic, const char *token, const char *error ); void msn_auth_got_contact_list( struct im_connection *ic ); int msn_ns_finish_login( struct im_connection *ic ); diff --git a/protocols/msn/msn_util.c b/protocols/msn/msn_util.c index 6a16ba17..7fa68915 100644 --- a/protocols/msn/msn_util.c +++ b/protocols/msn/msn_util.c @@ -350,7 +350,7 @@ int msn_handler( struct msn_handler_data *h ) cmd_text = g_strndup( h->rxq, i ); cmd = msn_linesplit( cmd_text ); for( count = 0; cmd[count]; count ++ ); - st = h->exec_command( h->data, cmd, count ); + st = h->exec_command( h, cmd, count ); g_free( cmd_text ); /* If the connection broke, don't continue. We don't even exist anymore. */ @@ -385,7 +385,7 @@ int msn_handler( struct msn_handler_data *h ) cmd = msn_linesplit( h->cmd_text ); for( count = 0; cmd[count]; count ++ ); - st = h->exec_message( h->data, msg, h->msglen, cmd, count ); + st = h->exec_message( h, msg, h->msglen, cmd, count ); g_free( msg ); g_free( h->cmd_text ); h->cmd_text = NULL; diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index 23a1951d..6260e300 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -30,9 +30,10 @@ #include "soap.h" #include "xmltree.h" +static gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ); static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition cond ); -static int msn_ns_command( gpointer data, char **cmd, int num_parts ); -static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts ); +static int msn_ns_command( struct msn_handler_data *handler, char **cmd, int num_parts ); +static int msn_ns_message( struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts ); static void msn_ns_send_adl_start( struct im_connection *ic ); static void msn_ns_send_adl( struct im_connection *ic ); @@ -50,7 +51,7 @@ int msn_ns_write( struct im_connection *ic, int fd, const char *fmt, ... ) va_end( params ); if( fd < 0 ) - fd = md->fd; + fd = md->ns->fd; if( getenv( "BITLBEE_DEBUG" ) ) fprintf( stderr, "->NS%d:%s", fd, out ); @@ -68,56 +69,79 @@ int msn_ns_write( struct im_connection *ic, int fd, const char *fmt, ... ) return 1; } -gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ) +gboolean msn_ns_connect( struct im_connection *ic, struct msn_handler_data *handler, const char *host, int port ) { - struct im_connection *ic = data; - struct msn_data *md; - - if( !g_slist_find( msn_connections, ic ) ) - return FALSE; + if( handler->fd >= 0 ) + closesocket( handler->fd ); - if( source == -1 ) + handler->exec_command = msn_ns_command; + handler->exec_message = msn_ns_message; + handler->data = ic; + handler->fd = proxy_connect( host, port, msn_ns_connected, handler ); + if( handler->fd < 0 ) { imcb_error( ic, "Could not connect to server" ); imc_logout( ic, TRUE ); return FALSE; } + return TRUE; +} + +static gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ) +{ + struct msn_handler_data *handler = data; + struct im_connection *ic = handler->data; + struct msn_data *md; + + if( !g_slist_find( msn_connections, ic ) ) + return FALSE; + md = ic->proto_data; - if( !md->handler ) - { - md->handler = g_new0( struct msn_handler_data, 1 ); - md->handler->data = ic; - md->handler->exec_command = msn_ns_command; - md->handler->exec_message = msn_ns_message; - } - else + if( source == -1 ) { - if( md->handler->rxq ) - g_free( md->handler->rxq ); - - md->handler->rxlen = 0; + imcb_error( ic, "Could not connect to server" ); + imc_logout( ic, TRUE ); + return FALSE; } - md->handler->fd = md->fd; - md->handler->rxq = g_new0( char, 1 ); + g_free( handler->rxq ); + handler->rxlen = 0; + handler->rxq = g_new0( char, 1 ); if( msn_ns_write( ic, -1, "VER %d %s CVR0\r\n", ++md->trId, MSNP_VER ) ) { - ic->inpa = b_input_add( md->fd, B_EV_IO_READ, msn_ns_callback, ic ); + handler->inpa = b_input_add( handler->fd, B_EV_IO_READ, msn_ns_callback, handler ); imcb_log( ic, "Connected to server, waiting for reply" ); } return FALSE; } +void msn_ns_close( struct msn_handler_data *handler ) +{ + if( handler->fd >= 0 ) + { + closesocket( handler->fd ); + b_event_remove( handler->inpa ); + } + + handler->fd = handler->inpa = -1; + g_free( handler->rxq ); + g_free( handler->cmd_text ); + + handler->rxlen = 0; + handler->rxq = NULL; + handler->cmd_text = NULL; +} + static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition cond ) { - struct im_connection *ic = data; - struct msn_data *md = ic->proto_data; + struct msn_handler_data *handler = data; + struct im_connection *ic = handler->data; - if( msn_handler( md->handler ) == -1 ) /* Don't do this on ret == 0, it's already done then. */ + if( msn_handler( handler ) == -1 ) /* Don't do this on ret == 0, it's already done then. */ { imcb_error( ic, "Error while reading from server" ); imc_logout( ic, TRUE ); @@ -128,9 +152,9 @@ static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition c return TRUE; } -static int msn_ns_command( gpointer data, char **cmd, int num_parts ) +static int msn_ns_command( struct msn_handler_data *handler, char **cmd, int num_parts ) { - struct im_connection *ic = data; + struct im_connection *ic = handler->data; struct msn_data *md = ic->proto_data; if( num_parts == 0 ) @@ -163,9 +187,8 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( num_parts >= 6 && strcmp( cmd[2], "NS" ) == 0 ) { - b_event_remove( ic->inpa ); - ic->inpa = 0; - closesocket( md->fd ); + b_event_remove( handler->inpa ); + handler->inpa = -1; server = strchr( cmd[3], ':' ); if( !server ) @@ -179,8 +202,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) server = cmd[3]; imcb_log( ic, "Transferring to other server" ); - - md->fd = proxy_connect( server, port, msn_ns_connected, ic ); + return msn_ns_connect( ic, handler, server, port ); } else if( num_parts >= 6 && strcmp( cmd[2], "SB" ) == 0 ) { @@ -272,9 +294,9 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) return( 0 ); } - md->handler->msglen = atoi( cmd[3] ); + handler->msglen = atoi( cmd[3] ); - if( md->handler->msglen <= 0 ) + if( handler->msglen <= 0 ) { imcb_error( ic, "Syntax error" ); imc_logout( ic, TRUE ); @@ -295,7 +317,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) } else if( num_parts >= 3 ) { - md->handler->msglen = atoi( cmd[2] ); + handler->msglen = atoi( cmd[2] ); } } else if( strcmp( cmd[0], "PRP" ) == 0 ) @@ -459,9 +481,9 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) { imcb_error( ic, "Received IPG command, we don't handle them yet." ); - md->handler->msglen = atoi( cmd[1] ); + handler->msglen = atoi( cmd[1] ); - if( md->handler->msglen <= 0 ) + if( handler->msglen <= 0 ) { imcb_error( ic, "Syntax error" ); imc_logout( ic, TRUE ); @@ -518,20 +540,20 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) { /* Coming up is cmd[2] bytes of stuff we're supposed to censore. Meh. */ - md->handler->msglen = atoi( cmd[2] ); + handler->msglen = atoi( cmd[2] ); } else if( strcmp( cmd[0], "UBX" ) == 0 ) { /* Status message. */ if( num_parts >= 4 ) - md->handler->msglen = atoi( cmd[3] ); + handler->msglen = atoi( cmd[3] ); } else if( strcmp( cmd[0], "NOT" ) == 0 ) { /* Some kind of notification, poorly documented but apparently used to announce address book changes. */ if( num_parts >= 2 ) - md->handler->msglen = atoi( cmd[1] ); + handler->msglen = atoi( cmd[1] ); } else if( isdigit( cmd[0][0] ) ) { @@ -548,7 +570,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) /* Oh yes, errors can have payloads too now. Discard them for now. */ if( num_parts >= 3 ) - md->handler->msglen = atoi( cmd[2] ); + handler->msglen = atoi( cmd[2] ); } else { @@ -558,9 +580,9 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) return( 1 ); } -static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts ) +static int msn_ns_message( struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts ) { - struct im_connection *ic = data; + struct im_connection *ic = handler->data; char *body; int blen = 0; diff --git a/protocols/msn/sb.c b/protocols/msn/sb.c index d10d7c19..898fb34f 100644 --- a/protocols/msn/sb.c +++ b/protocols/msn/sb.c @@ -31,8 +31,8 @@ #include "invitation.h" static gboolean msn_sb_callback( gpointer data, gint source, b_input_condition cond ); -static int msn_sb_command( gpointer data, char **cmd, int num_parts ); -static int msn_sb_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts ); +static int msn_sb_command( struct msn_handler_data *handler, char **cmd, int num_parts ); +static int msn_sb_message( struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts ); int msn_sb_write( struct msn_switchboard *sb, const char *fmt, ... ) { @@ -391,9 +391,9 @@ static gboolean msn_sb_callback( gpointer data, gint source, b_input_condition c return FALSE; } -static int msn_sb_command( gpointer data, char **cmd, int num_parts ) +static int msn_sb_command( struct msn_handler_data *handler, char **cmd, int num_parts ) { - struct msn_switchboard *sb = data; + struct msn_switchboard *sb = handler->data; struct im_connection *ic = sb->ic; if( !num_parts ) @@ -664,9 +664,9 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts ) return( 1 ); } -static int msn_sb_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts ) +static int msn_sb_message( struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts ) { - struct msn_switchboard *sb = data; + struct msn_switchboard *sb = handler->data; struct im_connection *ic = sb->ic; char *body; int blen = 0; -- cgit v1.2.3 From 4aa8a046968bff0a08dc5ae96e228861fa21fcbe Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 4 Sep 2010 16:54:52 +0100 Subject: This works (includes some token sabotage code to ease testing), but I just realised there's probably no need for the additional temporary NS connection. --- protocols/msn/msn.c | 7 +++++-- protocols/msn/msn.h | 4 ++-- protocols/msn/ns.c | 15 +++++++++++---- protocols/msn/soap.c | 40 +++++++++++++++++++++++++++++++++++----- protocols/msn/soap.h | 2 +- 5 files changed, 54 insertions(+), 14 deletions(-) diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c index c5c05087..1467f033 100644 --- a/protocols/msn/msn.c +++ b/protocols/msn/msn.c @@ -63,6 +63,7 @@ static void msn_login( account_t *acc ) md->ic = ic; md->away_state = msn_away_state_list; md->domaintree = g_tree_new( msn_domaintree_cmp ); + md->ns->fd = md->auth->fd = -1; msn_connections = g_slist_prepend( msn_connections, ic ); @@ -179,6 +180,8 @@ static void msn_set_away( struct im_connection *ic, char *state, char *message ) char *uux; struct msn_data *md = ic->proto_data; + strcpy( md->tokens[1], md->tokens[2] ); + if( state == NULL ) md->away_state = msn_away_state_list; else if( ( md->away_state = msn_away_state_by_name( state ) ) == NULL ) @@ -280,7 +283,7 @@ static void msn_add_permit( struct im_connection *ic, char *who ) static void msn_rem_permit( struct im_connection *ic, char *who ) { - msn_buddy_list_remove( ic, MSN_BUDDY_AL, who, NULL ); + //msn_buddy_list_remove( ic, MSN_BUDDY_AL, who, NULL ); } static void msn_add_deny( struct im_connection *ic, char *who ) @@ -298,7 +301,7 @@ static void msn_add_deny( struct im_connection *ic, char *who ) static void msn_rem_deny( struct im_connection *ic, char *who ) { - msn_buddy_list_remove( ic, MSN_BUDDY_BL, who, NULL ); + //msn_buddy_list_remove( ic, MSN_BUDDY_BL, who, NULL ); } static int msn_send_typing( struct im_connection *ic, char *who, int typing ) diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h index 5a195348..3def01a4 100644 --- a/protocols/msn/msn.h +++ b/protocols/msn/msn.h @@ -107,9 +107,9 @@ struct msn_data int trId; char *tokens[4]; - char *lock_key; + char *lock_key, *pp_policy; - GSList *msgq, *grpq; + GSList *msgq, *grpq, *soapq; GSList *switchboards; int sb_failures; time_t first_sb_failure; diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index 6260e300..401461b2 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -110,7 +110,7 @@ static gboolean msn_ns_connected( gpointer data, gint source, b_input_condition handler->rxlen = 0; handler->rxq = g_new0( char, 1 ); - if( msn_ns_write( ic, -1, "VER %d %s CVR0\r\n", ++md->trId, MSNP_VER ) ) + if( msn_ns_write( ic, source, "VER %d %s CVR0\r\n", ++md->trId, MSNP_VER ) ) { handler->inpa = b_input_add( handler->fd, B_EV_IO_READ, msn_ns_callback, handler ); imcb_log( ic, "Connected to server, waiting for reply" ); @@ -172,13 +172,13 @@ static int msn_ns_command( struct msn_handler_data *handler, char **cmd, int num return( 0 ); } - return( msn_ns_write( ic, -1, "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s\r\n", + return( msn_ns_write( ic, handler->fd, "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s\r\n", ++md->trId, ic->acc->user ) ); } else if( strcmp( cmd[0], "CVR" ) == 0 ) { /* We don't give a damn about the information we just received */ - return msn_ns_write( ic, -1, "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user ); + return msn_ns_write( ic, handler->fd, "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user ); } else if( strcmp( cmd[0], "XFR" ) == 0 ) { @@ -271,7 +271,14 @@ static int msn_ns_command( struct msn_handler_data *handler, char **cmd, int num if( num_parts >= 6 && strcmp( cmd[2], "SSO" ) == 0 && strcmp( cmd[3], "S" ) == 0 ) { - msn_soap_passport_sso_request( ic, cmd[4], cmd[5] ); + g_free( md->pp_policy ); + md->pp_policy = g_strdup( cmd[4] ); + msn_soap_passport_sso_request( ic, cmd[5] ); + if( handler == md->auth ) + { + msn_ns_close( md->auth ); + return 0; + } } else if( strcmp( cmd[2], "OK" ) == 0 ) { diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c index 8d276108..592dbd4f 100644 --- a/protocols/msn/soap.c +++ b/protocols/msn/soap.c @@ -136,9 +136,24 @@ static void msn_soap_handle_response( struct http_request *http_req ) if( http_req->body_size > 0 ) { struct xt_parser *parser; + struct xt_node *err; parser = xt_new( soap_req->xml_parser, soap_req ); xt_feed( parser, http_req->reply_body, http_req->body_size ); + if( http_req->status_code == 500 && + ( err = xt_find_path( parser->root, "soap:Body/soap:Fault/detail/errorcode" ) ) && + err->text_len > 0 && strcmp( err->text, "PassportAuthFail" ) == 0 ) + { + struct msn_data *md = soap_req->ic->proto_data; + + xt_free( parser ); + if( md->auth->fd == -1 ) + msn_ns_connect( soap_req->ic, md->auth, MSN_NS_HOST, MSN_NS_PORT ); + md->soapq = g_slist_prepend( md->soapq, soap_req ); + + return; + } + xt_handle( parser, NULL, -1 ); xt_free( parser ); } @@ -201,12 +216,24 @@ static void msn_soap_debug_print( const char *headers, const char *payload ) #endif } +static int msn_soapq_empty( struct im_connection *ic ) +{ + struct msn_data *md = ic->proto_data; + + while( md->soapq ) + { + msn_soap_send_request( (struct msn_soap_req_data*) md->soapq->data ); + md->soapq = g_slist_remove( md->soapq, md->soapq->data ); + } + + return MSN_SOAP_OK; +} + /* passport_sso: Authentication MSNP15+ */ struct msn_soap_passport_sso_data { - char *policy; char *nonce; char *secret; char *error; @@ -216,6 +243,7 @@ static int msn_soap_passport_sso_build_request( struct msn_soap_req_data *soap_r { struct msn_soap_passport_sso_data *sd = soap_req->data; struct im_connection *ic = soap_req->ic; + struct msn_data *md = ic->proto_data; if( g_str_has_suffix( ic->acc->user, "@msn.com" ) ) soap_req->url = g_strdup( SOAP_PASSPORT_SSO_URL_MSN ); @@ -223,7 +251,7 @@ static int msn_soap_passport_sso_build_request( struct msn_soap_req_data *soap_r soap_req->url = g_strdup( SOAP_PASSPORT_SSO_URL ); soap_req->payload = g_markup_printf_escaped( SOAP_PASSPORT_SSO_PAYLOAD, - ic->acc->user, ic->acc->pass, sd->policy ); + ic->acc->user, ic->acc->pass, md->pp_policy ); return MSN_SOAP_OK; } @@ -300,6 +328,7 @@ static int msn_soap_passport_sso_handle_response( struct msn_soap_req_data *soap { struct msn_soap_passport_sso_data *sd = soap_req->data; struct im_connection *ic = soap_req->ic; + struct msn_data *md = ic->proto_data; char *key1, *key2, *key3, *blurb64; int key1_len; unsigned char *padnonce, *des3res; @@ -325,6 +354,9 @@ static int msn_soap_passport_sso_handle_response( struct msn_soap_req_data *soap GUINT32_TO_LE( 72 ), }; + if( md->soapq ) + return msn_soapq_empty( ic ); + if( sd->secret == NULL ) { msn_auth_got_passport_token( ic, NULL, sd->error ); @@ -363,7 +395,6 @@ static int msn_soap_passport_sso_free_data( struct msn_soap_req_data *soap_req ) { struct msn_soap_passport_sso_data *sd = soap_req->data; - g_free( sd->policy ); g_free( sd->nonce ); g_free( sd->secret ); g_free( sd->error ); @@ -371,11 +402,10 @@ static int msn_soap_passport_sso_free_data( struct msn_soap_req_data *soap_req ) return MSN_SOAP_OK; } -int msn_soap_passport_sso_request( struct im_connection *ic, const char *policy, const char *nonce ) +int msn_soap_passport_sso_request( struct im_connection *ic, const char *nonce ) { struct msn_soap_passport_sso_data *sd = g_new0( struct msn_soap_passport_sso_data, 1 ); - sd->policy = g_strdup( policy ); sd->nonce = g_strdup( nonce ); return msn_soap_start( ic, sd, msn_soap_passport_sso_build_request, diff --git a/protocols/msn/soap.h b/protocols/msn/soap.h index 9fba5366..3a46af46 100644 --- a/protocols/msn/soap.h +++ b/protocols/msn/soap.h @@ -138,7 +138,7 @@ "" \ "" -int msn_soap_passport_sso_request( struct im_connection *ic, const char *policy, const char *nonce ); +int msn_soap_passport_sso_request( struct im_connection *ic, const char *nonce ); #define SOAP_OIM_SEND_URL "https://ows.messenger.msn.com/OimWS/oim.asmx" -- cgit v1.2.3 From 27053b516db4d0e648d666e6d9e36856af428775 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 4 Sep 2010 18:13:55 +0100 Subject: Finish re-authentication works. Should now work for OIMs as well. --- protocols/msn/msn.c | 10 ++++---- protocols/msn/msn.h | 3 ++- protocols/msn/ns.c | 5 ---- protocols/msn/soap.c | 67 ++++++++++++++++++++++++++++++++++------------------ protocols/msn/soap.h | 2 +- 5 files changed, 51 insertions(+), 36 deletions(-) diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c index 1467f033..65bdd9a6 100644 --- a/protocols/msn/msn.c +++ b/protocols/msn/msn.c @@ -63,7 +63,7 @@ static void msn_login( account_t *acc ) md->ic = ic; md->away_state = msn_away_state_list; md->domaintree = g_tree_new( msn_domaintree_cmp ); - md->ns->fd = md->auth->fd = -1; + md->ns->fd = -1; msn_connections = g_slist_prepend( msn_connections, ic ); @@ -86,7 +86,6 @@ static void msn_logout( struct im_connection *ic ) */ msn_ns_close( md->ns ); - msn_ns_close( md->auth ); while( md->switchboards ) msn_sb_destroy( md->switchboards->data ); @@ -96,6 +95,7 @@ static void msn_logout( struct im_connection *ic ) for( i = 0; i < sizeof( md->tokens ) / sizeof( md->tokens[0] ); i ++ ) g_free( md->tokens[i] ); g_free( md->lock_key ); + g_free( md->pp_policy ); while( md->groups ) { @@ -180,8 +180,6 @@ static void msn_set_away( struct im_connection *ic, char *state, char *message ) char *uux; struct msn_data *md = ic->proto_data; - strcpy( md->tokens[1], md->tokens[2] ); - if( state == NULL ) md->away_state = msn_away_state_list; else if( ( md->away_state = msn_away_state_by_name( state ) ) == NULL ) @@ -283,7 +281,7 @@ static void msn_add_permit( struct im_connection *ic, char *who ) static void msn_rem_permit( struct im_connection *ic, char *who ) { - //msn_buddy_list_remove( ic, MSN_BUDDY_AL, who, NULL ); + msn_buddy_list_remove( ic, MSN_BUDDY_AL, who, NULL ); } static void msn_add_deny( struct im_connection *ic, char *who ) @@ -301,7 +299,7 @@ static void msn_add_deny( struct im_connection *ic, char *who ) static void msn_rem_deny( struct im_connection *ic, char *who ) { - //msn_buddy_list_remove( ic, MSN_BUDDY_BL, who, NULL ); + msn_buddy_list_remove( ic, MSN_BUDDY_BL, who, NULL ); } static int msn_send_typing( struct im_connection *ic, char *who, int typing ) diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h index 3def01a4..829bbd4c 100644 --- a/protocols/msn/msn.h +++ b/protocols/msn/msn.h @@ -80,6 +80,7 @@ typedef enum MSN_GOT_PROFILE = 1, MSN_GOT_PROFILE_DN = 2, MSN_DONE_ADL = 4, + MSN_REAUTHING = 8, } msn_flags_t; struct msn_handler_data @@ -102,7 +103,7 @@ struct msn_data { struct im_connection *ic; - struct msn_handler_data ns[1], auth[1]; + struct msn_handler_data ns[1]; msn_flags_t flags; int trId; diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index 401461b2..d64a71ac 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -274,11 +274,6 @@ static int msn_ns_command( struct msn_handler_data *handler, char **cmd, int num g_free( md->pp_policy ); md->pp_policy = g_strdup( cmd[4] ); msn_soap_passport_sso_request( ic, cmd[5] ); - if( handler == md->auth ) - { - msn_ns_close( md->auth ); - return 0; - } } else if( strcmp( cmd[2], "OK" ) == 0 ) { diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c index 592dbd4f..2c26271b 100644 --- a/protocols/msn/soap.c +++ b/protocols/msn/soap.c @@ -47,6 +47,7 @@ typedef enum { MSN_SOAP_OK, MSN_SOAP_RETRY, + MSN_SOAP_REAUTH, MSN_SOAP_ABORT, } msn_soap_result_t; @@ -133,6 +134,8 @@ static void msn_soap_handle_response( struct http_request *http_req ) return; } + msn_soap_debug_print( http_req->reply_headers, http_req->reply_body ); + if( http_req->body_size > 0 ) { struct xt_parser *parser; @@ -142,33 +145,45 @@ static void msn_soap_handle_response( struct http_request *http_req ) xt_feed( parser, http_req->reply_body, http_req->body_size ); if( http_req->status_code == 500 && ( err = xt_find_path( parser->root, "soap:Body/soap:Fault/detail/errorcode" ) ) && - err->text_len > 0 && strcmp( err->text, "PassportAuthFail" ) == 0 ) + err->text_len > 0 ) { - struct msn_data *md = soap_req->ic->proto_data; - - xt_free( parser ); - if( md->auth->fd == -1 ) - msn_ns_connect( soap_req->ic, md->auth, MSN_NS_HOST, MSN_NS_PORT ); - md->soapq = g_slist_prepend( md->soapq, soap_req ); - - return; + if( strcmp( err->text, "PassportAuthFail" ) == 0 ) + { + xt_free( parser ); + st = MSN_SOAP_REAUTH; + goto fail; + } + /* TODO: Handle/report other errors. */ } xt_handle( parser, NULL, -1 ); xt_free( parser ); } - msn_soap_debug_print( http_req->reply_headers, http_req->reply_body ); - st = soap_req->handle_response( soap_req ); - + +fail: g_free( soap_req->url ); g_free( soap_req->action ); g_free( soap_req->payload ); soap_req->url = soap_req->action = soap_req->payload = NULL; if( st == MSN_SOAP_RETRY && --soap_req->ttl ) + { msn_soap_send_request( soap_req ); + } + else if( st == MSN_SOAP_REAUTH ) + { + struct msn_data *md = soap_req->ic->proto_data; + + if( !( md->flags & MSN_REAUTHING ) ) + { + /* Nonce shouldn't actually be touched for re-auths. */ + msn_soap_passport_sso_request( soap_req->ic, "blaataap" ); + md->flags |= MSN_REAUTHING; + } + md->soapq = g_slist_append( md->soapq, soap_req ); + } else { soap_req->free_data( soap_req ); @@ -241,7 +256,6 @@ struct msn_soap_passport_sso_data static int msn_soap_passport_sso_build_request( struct msn_soap_req_data *soap_req ) { - struct msn_soap_passport_sso_data *sd = soap_req->data; struct im_connection *ic = soap_req->ic; struct msn_data *md = ic->proto_data; @@ -422,7 +436,7 @@ struct msn_soap_oim_send_data char *to; char *msg; int number; - int need_retry; + msn_soap_result_t need_retry; }; static int msn_soap_oim_build_request( struct msn_soap_req_data *soap_req ) @@ -443,28 +457,36 @@ static int msn_soap_oim_build_request( struct msn_soap_req_data *soap_req ) oim->number, oim->number, oim->msg ); g_free( display_name_b64 ); + oim->need_retry = MSN_SOAP_OK; return MSN_SOAP_OK; } -static xt_status msn_soap_oim_send_challenge( struct xt_node *node, gpointer data ) +static xt_status msn_soap_oim_reauth( struct xt_node *node, gpointer data ) { struct msn_soap_req_data *soap_req = data; struct msn_soap_oim_send_data *oim = soap_req->data; struct im_connection *ic = soap_req->ic; struct msn_data *md = ic->proto_data; + struct xt_node *c; - g_free( md->lock_key ); - md->lock_key = msn_p11_challenge( node->text ); - - oim->need_retry = 1; + if( ( c = xt_find_node( node->children, "LockKeyChallenge" ) ) && c->text_len > 0 ) + { + g_free( md->lock_key ); + md->lock_key = msn_p11_challenge( c->text ); + oim->need_retry = MSN_SOAP_RETRY; + } + if( xt_find_node( node->children, "RequiredAuthPolicy" ) ) + { + oim->need_retry = MSN_SOAP_REAUTH; + } return XT_HANDLED; } static const struct xt_handler_entry msn_soap_oim_send_parser[] = { - { "LockKeyChallenge", "detail", msn_soap_oim_send_challenge }, - { NULL, NULL, NULL } + { "detail", "soap:Fault", msn_soap_oim_reauth }, + { NULL, NULL, NULL } }; static int msn_soap_oim_handle_response( struct msn_soap_req_data *soap_req ) @@ -473,8 +495,7 @@ static int msn_soap_oim_handle_response( struct msn_soap_req_data *soap_req ) if( soap_req->http_req->status_code == 500 && oim->need_retry && soap_req->ttl > 0 ) { - oim->need_retry = 0; - return MSN_SOAP_RETRY; + return oim->need_retry; } else if( soap_req->http_req->status_code == 200 ) { diff --git a/protocols/msn/soap.h b/protocols/msn/soap.h index 3a46af46..bd3e0245 100644 --- a/protocols/msn/soap.h +++ b/protocols/msn/soap.h @@ -125,7 +125,7 @@ "" \ "" \ "" \ - "" \ + "" \ "http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue" \ "" \ "" \ -- cgit v1.2.3 From 4e1be76617060e89795e381d356f81cd2cbf32dc Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 4 Sep 2010 18:23:46 +0100 Subject: Clean up any stuff stuck in the soap queue at disconnect time. --- protocols/msn/msn.c | 1 + protocols/msn/soap.c | 25 +++++++++++++++++-------- protocols/msn/soap.h | 3 +++ 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c index 65bdd9a6..1584efa4 100644 --- a/protocols/msn/msn.c +++ b/protocols/msn/msn.c @@ -91,6 +91,7 @@ static void msn_logout( struct im_connection *ic ) msn_sb_destroy( md->switchboards->data ); msn_msgq_purge( ic, &md->msgq ); + msn_soapq_flush( ic, FALSE ); for( i = 0; i < sizeof( md->tokens ) / sizeof( md->tokens[0] ); i ++ ) g_free( md->tokens[i] ); diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c index 2c26271b..05d91109 100644 --- a/protocols/msn/soap.c +++ b/protocols/msn/soap.c @@ -68,6 +68,7 @@ struct msn_soap_req_data }; static int msn_soap_send_request( struct msn_soap_req_data *req ); +static void msn_soap_free( struct msn_soap_req_data *soap_req ); static void msn_soap_debug_print( const char *headers, const char *payload ); static int msn_soap_start( struct im_connection *ic, @@ -126,11 +127,7 @@ static void msn_soap_handle_response( struct http_request *http_req ) if( g_slist_find( msn_connections, soap_req->ic ) == NULL ) { - soap_req->free_data( soap_req ); - g_free( soap_req->url ); - g_free( soap_req->action ); - g_free( soap_req->payload ); - g_free( soap_req ); + msn_soap_free( soap_req ); return; } @@ -231,19 +228,31 @@ static void msn_soap_debug_print( const char *headers, const char *payload ) #endif } -static int msn_soapq_empty( struct im_connection *ic ) +int msn_soapq_flush( struct im_connection *ic, gboolean resend ) { struct msn_data *md = ic->proto_data; while( md->soapq ) { - msn_soap_send_request( (struct msn_soap_req_data*) md->soapq->data ); + if( resend ) + msn_soap_send_request( (struct msn_soap_req_data*) md->soapq->data ); + else + msn_soap_free( (struct msn_soap_req_data*) md->soapq->data ); md->soapq = g_slist_remove( md->soapq, md->soapq->data ); } return MSN_SOAP_OK; } +static void msn_soap_free( struct msn_soap_req_data *soap_req ) +{ + soap_req->free_data( soap_req ); + g_free( soap_req->url ); + g_free( soap_req->action ); + g_free( soap_req->payload ); + g_free( soap_req ); +} + /* passport_sso: Authentication MSNP15+ */ @@ -369,7 +378,7 @@ static int msn_soap_passport_sso_handle_response( struct msn_soap_req_data *soap }; if( md->soapq ) - return msn_soapq_empty( ic ); + return msn_soapq_flush( ic, TRUE ); if( sd->secret == NULL ) { diff --git a/protocols/msn/soap.h b/protocols/msn/soap.h index bd3e0245..b13238a4 100644 --- a/protocols/msn/soap.h +++ b/protocols/msn/soap.h @@ -44,6 +44,9 @@ #include "nogaim.h" +int msn_soapq_flush( struct im_connection *ic, gboolean resend ); + + #define SOAP_HTTP_REQUEST \ "POST %s HTTP/1.0\r\n" \ "Host: %s\r\n" \ -- cgit v1.2.3 From 2c6b0f4dbc367963d21314636c4b114dc7aadd32 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 5 Sep 2010 15:09:43 +0100 Subject: Fix auth for @msn.com accounts. --- protocols/msn/soap.c | 18 +++++++++++++++++- protocols/msn/soap.h | 2 +- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c index 05d91109..21e9feec 100644 --- a/protocols/msn/soap.c +++ b/protocols/msn/soap.c @@ -261,14 +261,21 @@ struct msn_soap_passport_sso_data char *nonce; char *secret; char *error; + char *redirect; }; static int msn_soap_passport_sso_build_request( struct msn_soap_req_data *soap_req ) { + struct msn_soap_passport_sso_data *sd = soap_req->data; struct im_connection *ic = soap_req->ic; struct msn_data *md = ic->proto_data; - if( g_str_has_suffix( ic->acc->user, "@msn.com" ) ) + if( sd->redirect ) + { + soap_req->url = sd->redirect; + sd->redirect = NULL; + } + else if( g_str_has_suffix( ic->acc->user, "@msn.com" ) ) soap_req->url = g_strdup( SOAP_PASSPORT_SSO_URL_MSN ); else soap_req->url = g_strdup( SOAP_PASSPORT_SSO_URL ); @@ -311,9 +318,14 @@ static xt_status msn_soap_passport_failure( struct xt_node *node, gpointer data struct msn_soap_passport_sso_data *sd = soap_req->data; struct xt_node *code = xt_find_node( node->children, "faultcode" ); struct xt_node *string = xt_find_node( node->children, "faultstring" ); + struct xt_node *url; if( code == NULL || code->text_len == 0 ) sd->error = g_strdup( "Unknown error" ); + else if( strcmp( code->text, "psf:Redirect" ) == 0 && + ( url = xt_find_node( node->children, "psf:redirectUrl" ) ) && + url->text_len > 0 ) + sd->redirect = g_strdup( url->text ); else sd->error = g_strdup_printf( "%s (%s)", code->text, string && string->text_len ? string->text : "no description available" ); @@ -377,6 +389,9 @@ static int msn_soap_passport_sso_handle_response( struct msn_soap_req_data *soap GUINT32_TO_LE( 72 ), }; + if( sd->redirect ) + return MSN_SOAP_RETRY; + if( md->soapq ) return msn_soapq_flush( ic, TRUE ); @@ -421,6 +436,7 @@ static int msn_soap_passport_sso_free_data( struct msn_soap_req_data *soap_req ) g_free( sd->nonce ); g_free( sd->secret ); g_free( sd->error ); + g_free( sd->redirect ); return MSN_SOAP_OK; } diff --git a/protocols/msn/soap.h b/protocols/msn/soap.h index b13238a4..f49c86c4 100644 --- a/protocols/msn/soap.h +++ b/protocols/msn/soap.h @@ -61,7 +61,7 @@ int msn_soapq_flush( struct im_connection *ic, gboolean resend ); #define SOAP_PASSPORT_SSO_URL "https://login.live.com/RST.srf" -#define SOAP_PASSPORT_SSO_URL_MSN "https://msnia.login.live.com/pp550/RST.srf" +#define SOAP_PASSPORT_SSO_URL_MSN "https://msnia.login.live.com/pp800/RST.srf" #define SOAP_PASSPORT_SSO_PAYLOAD \ " Date: Fri, 1 Oct 2010 21:21:50 -0700 Subject: Fixed possible crash bug on removing contacts while the auth cookie expired. --- protocols/msn/soap.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c index 21e9feec..baa73718 100644 --- a/protocols/msn/soap.c +++ b/protocols/msn/soap.c @@ -969,13 +969,12 @@ int msn_soap_ab_contact_add( struct im_connection *ic, bee_user_t *bu ) static int msn_soap_ab_contact_del_build_request( struct msn_soap_req_data *soap_req ) { struct msn_data *md = soap_req->ic->proto_data; - bee_user_t *bu = soap_req->data; - struct msn_buddy_data *bd = bu->data; + const char *cid = soap_req->data; soap_req->url = g_strdup( SOAP_ADDRESSBOOK_URL ); soap_req->action = g_strdup( SOAP_AB_CONTACT_DEL_ACTION ); soap_req->payload = msn_soap_abservice_build( SOAP_AB_CONTACT_DEL_PAYLOAD, - "Timer", md->tokens[1], bd->cid ); + "Timer", md->tokens[1], cid ); return 1; } @@ -988,12 +987,15 @@ static int msn_soap_ab_contact_del_handle_response( struct msn_soap_req_data *so static int msn_soap_ab_contact_del_free_data( struct msn_soap_req_data *soap_req ) { + g_free( soap_req->data ); return 0; } int msn_soap_ab_contact_del( struct im_connection *ic, bee_user_t *bu ) { - return msn_soap_start( ic, bu, + struct msn_buddy_data *bd = bu->data; + + return msn_soap_start( ic, g_strdup( bd->cid ), msn_soap_ab_contact_del_build_request, NULL, msn_soap_ab_contact_del_handle_response, -- cgit v1.2.3 From ed86165b5681b7c3ed8a7b2ce8bda0dafd6fcd52 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Fri, 1 Oct 2010 21:22:57 -0700 Subject: Silence some debugging stuff that was still going to stdout. --- protocols/msn/soap.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c index baa73718..63e5c638 100644 --- a/protocols/msn/soap.c +++ b/protocols/msn/soap.c @@ -633,7 +633,8 @@ static xt_status msn_soap_memlist_member( struct xt_node *node, gpointer data ) else if( strcmp( role, "Pending" ) == 0 ) bd->flags |= MSN_BUDDY_PL; - printf( "%p %s %d\n", bu, handle, bd->flags ); + if( getenv( "BITLBEE_DEBUG" ) ) + printf( "%p %s %d\n", bu, handle, bd->flags ); return XT_HANDLED; } @@ -779,7 +780,8 @@ static xt_status msn_soap_addressbook_group( struct xt_node *node, gpointer data md->groups = g_slist_prepend( md->groups, mg ); } - printf( "%s %s\n", id, name ); + if( getenv( "BITLBEE_DEBUG" ) ) + printf( "%s %s\n", id, name ); return XT_HANDLED; } @@ -839,7 +841,8 @@ static xt_status msn_soap_addressbook_contact( struct xt_node *node, gpointer da if( group_id && ( group = msn_group_by_id( ic, group_id ) ) ) imcb_add_buddy( ic, handle, group->name ); - printf( "%s %s %s %s\n", id, type, handle, display_name ); + if( getenv( "BITLBEE_DEBUG" ) ) + printf( "%s %s %s %s\n", id, type, handle, display_name ); return XT_HANDLED; } -- cgit v1.2.3 From 04cd284bce74c114fde3043c951a5c8ef9eb79ae Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Fri, 1 Oct 2010 22:19:27 -0700 Subject: Export block/allow list again. The way this is done is ugly though and needs to change. --- protocols/msn/soap.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c index 63e5c638..a1b5be76 100644 --- a/protocols/msn/soap.c +++ b/protocols/msn/soap.c @@ -625,9 +625,15 @@ static xt_status msn_soap_memlist_member( struct xt_node *node, gpointer data ) bd = bu->data; if( strcmp( role, "Allow" ) == 0 ) + { bd->flags |= MSN_BUDDY_AL; + ic->permit = g_slist_prepend( ic->permit, g_strdup( handle ) ); + } else if( strcmp( role, "Block" ) == 0 ) + { bd->flags |= MSN_BUDDY_BL; + ic->deny = g_slist_prepend( ic->deny, g_strdup( handle ) ); + } else if( strcmp( role, "Reverse" ) == 0 ) bd->flags |= MSN_BUDDY_RL; else if( strcmp( role, "Pending" ) == 0 ) -- cgit v1.2.3