Changeset 62f53b50
- Timestamp:
- 2010-10-02T05:34:53Z (14 years ago)
- Branches:
- master
- Children:
- 2af3e23
- Parents:
- 05bf2a0 (diff), 04cd284 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Files:
-
- 4 added
- 2 deleted
- 23 edited
Legend:
- Unmodified
- Added
- Removed
-
configure
r05bf2a0 r62f53b50 423 423 fi; 424 424 425 if [ "$msn" = "1" -a "$ssl" != "openssl" ]; then 426 # Needed for MSN only. OpenSSL exports nice cipher functions already, 427 # others don't, so use our own 3des code. 428 echo 'DES=des.o' >> Makefile.settings 429 fi 430 425 431 echo 'SSL_CLIENT=ssl_'$ssl'.o' >> Makefile.settings 426 432 -
doc/CHANGES
r05bf2a0 r62f53b50 50 50 for a list of supported protocols (works only in libpurple-enabled 51 51 binaries). 52 - Rewritten MSN module, implementing MSNP15 instead of the old MSNP8: 53 * MSNP8 support from MSN was getting pretty unreliable. There were issues 54 with remembering display names and adding contacts/auth requests. 55 * Support for sending offline messages. 56 * Support for setting and reading status messages. 52 57 - Support for file transfers, in and out. /DCC SEND a file to a contact and 53 58 it becomes a file transfer, and incoming file transfers become /DCC SENDs -
lib/Makefile
r05bf2a0 r62f53b50 13 13 14 14 # [SH] Program variables 15 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.o15 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 16 16 17 17 LFLAGS += -r -
lib/misc.c
r05bf2a0 r62f53b50 298 298 void http_encode( char *s ) 299 299 { 300 char *t;300 char t[strlen(s)+1]; 301 301 int i, j; 302 302 303 t = g_strdup( s ); 304 303 strcpy( t, s ); 305 304 for( i = j = 0; t[i]; i ++, j ++ ) 306 305 { … … 320 319 } 321 320 s[j] = 0; 322 323 g_free( t );324 321 } 325 322 -
lib/sha1.c
r05bf2a0 r62f53b50 36 36 */ 37 37 38 #include <string.h> 38 39 #include "sha1.h" 39 40 … … 374 375 sha1_process_block(context); 375 376 } 377 378 #define HMAC_BLOCK_SIZE 64 379 380 /* BitlBee addition: */ 381 void sha1_hmac(const char *key_, size_t key_len, const char *payload, size_t payload_len, uint8_t Message_Digest[sha1_hash_size]) 382 { 383 sha1_state_t sha1; 384 uint8_t hash[sha1_hash_size]; 385 uint8_t key[HMAC_BLOCK_SIZE+1]; 386 int i; 387 388 if( key_len == 0 ) 389 key_len = strlen( key_ ); 390 if( payload_len == 0 ) 391 payload_len = strlen( payload ); 392 393 /* Create K. If our current key is >64 chars we have to hash it, 394 otherwise just pad. */ 395 memset( key, 0, HMAC_BLOCK_SIZE + 1 ); 396 if( key_len > HMAC_BLOCK_SIZE ) 397 { 398 sha1_init( &sha1 ); 399 sha1_append( &sha1, (uint8_t*) key_, key_len ); 400 sha1_finish( &sha1, key ); 401 } 402 else 403 { 404 memcpy( key, key_, key_len ); 405 } 406 407 /* Inner part: H(K XOR 0x36, text) */ 408 sha1_init( &sha1 ); 409 for( i = 0; i < HMAC_BLOCK_SIZE; i ++ ) 410 key[i] ^= 0x36; 411 sha1_append( &sha1, key, HMAC_BLOCK_SIZE ); 412 sha1_append( &sha1, (const uint8_t*) payload, payload_len ); 413 sha1_finish( &sha1, hash ); 414 415 /* Final result: H(K XOR 0x5C, inner stuff) */ 416 sha1_init( &sha1 ); 417 for( i = 0; i < HMAC_BLOCK_SIZE; i ++ ) 418 key[i] ^= 0x36 ^ 0x5c; 419 sha1_append( &sha1, key, HMAC_BLOCK_SIZE ); 420 sha1_append( &sha1, hash, sha1_hash_size ); 421 sha1_finish( &sha1, Message_Digest ); 422 } -
lib/sha1.h
r05bf2a0 r62f53b50 67 67 G_MODULE_EXPORT int sha1_append(sha1_state_t *, const uint8_t *, unsigned int); 68 68 G_MODULE_EXPORT int sha1_finish(sha1_state_t *, uint8_t Message_Digest[sha1_hash_size]); 69 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]); 69 70 70 71 #endif -
lib/ssl_client.h
r05bf2a0 r62f53b50 78 78 the same action as the handler that just received the SSL_AGAIN.) */ 79 79 G_MODULE_EXPORT b_input_condition ssl_getdirection( void *conn ); 80 81 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); -
lib/ssl_gnutls.c
r05bf2a0 r62f53b50 189 189 ssl_errno = SSL_AGAIN; 190 190 191 if( 0 && getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st ); 192 191 193 return st; 192 194 } … … 207 209 if( st == GNUTLS_E_AGAIN || st == GNUTLS_E_INTERRUPTED ) 208 210 ssl_errno = SSL_AGAIN; 211 212 if( 0 && getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st ); 209 213 210 214 return st; -
lib/ssl_openssl.c
r05bf2a0 r62f53b50 116 116 { 117 117 initialized = TRUE; 118 SSLeay_add_ssl_algorithms(); 118 SSL_library_init(); 119 //SSLeay_add_ssl_algorithms(); 120 //OpenSSL_add_all_algorithms(); 119 121 } 120 122 … … 205 207 } 206 208 209 if( 0 && getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st ); 210 207 211 return st; 208 212 } … … 219 223 220 224 st = SSL_write( ((struct scd*)conn)->ssl, buf, len ); 225 226 if( 0 && getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st ); 221 227 222 228 ssl_errno = SSL_OK; … … 272 278 return( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ? B_EV_IO_WRITE : B_EV_IO_READ ); 273 279 } 280 281 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) 282 { 283 int output_length = 0; 284 EVP_CIPHER_CTX ctx; 285 286 *res = g_new0(unsigned char, 72); 287 288 /* Don't set key or IV because we will modify the parameters */ 289 EVP_CIPHER_CTX_init(&ctx); 290 EVP_CipherInit_ex(&ctx, EVP_des_ede3_cbc(), NULL, NULL, NULL, 1); 291 EVP_CIPHER_CTX_set_key_length(&ctx, key_len); 292 EVP_CIPHER_CTX_set_padding(&ctx, 0); 293 /* We finished modifying parameters so now we can set key and IV */ 294 EVP_CipherInit_ex(&ctx, NULL, NULL, key, iv, 1); 295 EVP_CipherUpdate(&ctx, *res, &output_length, input, input_len); 296 EVP_CipherFinal_ex(&ctx, *res, &output_length); 297 EVP_CIPHER_CTX_cleanup(&ctx); 298 //EVP_cleanup(); 299 300 return output_length; 301 } -
lib/xmltree.c
r05bf2a0 r62f53b50 141 141 /* Feed the parser, don't execute any handler. Returns -1 on errors, 0 on 142 142 end-of-stream and 1 otherwise. */ 143 int xt_feed( struct xt_parser *xt, c har *text, int text_len )143 int xt_feed( struct xt_parser *xt, const char *text, int text_len ) 144 144 { 145 145 if( !g_markup_parse_context_parse( xt->parser, text, text_len, &xt->gerr ) ) … … 174 174 if( node->flags & XT_COMPLETE && !( node->flags & XT_SEEN ) ) 175 175 { 176 for( i = 0; xt->handlers[i].func; i ++ )176 if( xt->handlers ) for( i = 0; xt->handlers[i].func; i ++ ) 177 177 { 178 178 /* This one is fun! \o/ */ 179 179 180 180 /* If handler.name == NULL it means it should always match. */ 181 181 if( ( xt->handlers[i].name == NULL || 182 182 /* If it's not, compare. There should always be a name. */ 183 183 g_strcasecmp( xt->handlers[i].name, node->name ) == 0 ) && 184 184 /* If handler.parent == NULL, it's a match. */ 185 185 ( xt->handlers[i].parent == NULL || 186 186 /* If there's a parent node, see if the name matches. */ 187 187 ( node->parent ? g_strcasecmp( xt->handlers[i].parent, node->parent->name ) == 0 : 188 189 g_strcasecmp( xt->handlers[i].parent, "<root>" ) == 0 ) ) )188 /* If there's no parent, the handler should mention <root> as a parent. */ 189 strcmp( xt->handlers[i].parent, "<root>" ) == 0 ) ) ) 190 190 { 191 191 st = xt->handlers[i].func( node, xt->data ); … … 260 260 } 261 261 262 struct xt_node *xt_from_string( const char *in ) 263 { 264 struct xt_parser *parser; 265 struct xt_node *ret; 266 267 parser = xt_new( NULL, NULL ); 268 xt_feed( parser, in, strlen( in ) ); 269 ret = parser->root; 270 parser->root = NULL; 271 xt_free( parser ); 272 273 return ret; 274 } 275 262 276 static void xt_to_string_real( struct xt_node *node, GString *str ) 263 277 { … … 317 331 /* Indentation */ 318 332 for( c = node; c->parent; c = c->parent ) 319 printf( " \t" );333 printf( " " ); 320 334 321 335 /* Start the tag */ … … 324 338 /* Print the attributes */ 325 339 for( i = 0; node->attr[i].key; i ++ ) 326 printf( " %s=\"%s\"", node->attr[i].key, g_markup_escape_text( node->attr[i].value, -1 ) ); 340 { 341 char *v = g_markup_escape_text( node->attr[i].value, -1 ); 342 printf( " %s=\"%s\"", node->attr[i].key, v ); 343 g_free( v ); 344 } 327 345 328 346 /* /> in case there's really *nothing* inside this tag, otherwise … … 344 362 for( i = 0; node->text[i] && isspace( node->text[i] ); i ++ ); 345 363 if( node->text[i] ) 346 printf( "%s", g_markup_escape_text( node->text, -1 ) ); 364 { 365 char *v = g_markup_escape_text( node->text, -1 ); 366 printf( "%s", v ); 367 g_free( v ); 368 } 347 369 } 348 370 … … 355 377 if( node->children ) 356 378 for( c = node; c->parent; c = c->parent ) 357 printf( " \t" );379 printf( " " ); 358 380 359 381 /* Non-empty tag is now finished. */ … … 460 482 461 483 node = node->next; 484 } 485 486 return node; 487 } 488 489 /* More advanced than the one above, understands something like 490 ../foo/bar to find a subnode bar of a node foo which is a child 491 of node's parent. Pass the node directly, not its list of children. */ 492 struct xt_node *xt_find_path( struct xt_node *node, const char *name ) 493 { 494 while( name && *name && node ) 495 { 496 char *colon, *slash; 497 int n; 498 499 if( ( slash = strchr( name, '/' ) ) ) 500 n = slash - name; 501 else 502 n = strlen( name ); 503 504 if( strncmp( name, "..", n ) == 0 ) 505 { 506 node = node->parent; 507 } 508 else 509 { 510 node = node->children; 511 512 while( node ) 513 { 514 if( g_strncasecmp( node->name, name, n ) == 0 || 515 ( ( colon = strchr( node->name, ':' ) ) && 516 g_strncasecmp( colon + 1, name, n ) == 0 ) ) 517 break; 518 519 node = node->next; 520 } 521 } 522 523 name = slash ? slash + 1 : NULL; 462 524 } 463 525 … … 550 612 } 551 613 614 /* Same, but at the beginning. */ 615 void xt_insert_child( struct xt_node *parent, struct xt_node *child ) 616 { 617 struct xt_node *node, *last; 618 619 for( node = child; node; node = node->next ) 620 { 621 if( node->parent != NULL ) 622 { 623 /* ERROR CONDITION: They seem to have a parent already??? */ 624 } 625 626 node->parent = parent; 627 last = node; 628 } 629 630 last->next = parent->children; 631 parent->children = child; 632 } 633 552 634 void xt_add_attr( struct xt_node *node, const char *key, const char *value ) 553 635 { -
lib/xmltree.h
r05bf2a0 r62f53b50 79 79 struct xt_parser *xt_new( const struct xt_handler_entry *handlers, gpointer data ); 80 80 void xt_reset( struct xt_parser *xt ); 81 int xt_feed( struct xt_parser *xt, c har *text, int text_len );81 int xt_feed( struct xt_parser *xt, const char *text, int text_len ); 82 82 int xt_handle( struct xt_parser *xt, struct xt_node *node, int depth ); 83 83 void xt_cleanup( struct xt_parser *xt, struct xt_node *node, int depth ); 84 struct xt_node *xt_from_string( const char *in ); 84 85 char *xt_to_string( struct xt_node *node ); 85 86 void xt_print( struct xt_node *node ); … … 88 89 void xt_free( struct xt_parser *xt ); 89 90 struct xt_node *xt_find_node( struct xt_node *node, const char *name ); 91 struct xt_node *xt_find_path( struct xt_node *node, const char *name ); 90 92 char *xt_find_attr( struct xt_node *node, const char *key ); 91 93 92 94 struct xt_node *xt_new_node( char *name, const char *text, struct xt_node *children ); 93 95 void xt_add_child( struct xt_node *parent, struct xt_node *child ); 96 void xt_insert_child( struct xt_node *parent, struct xt_node *child ); 94 97 void xt_add_attr( struct xt_node *node, const char *key, const char *value ); 95 98 int xt_remove_attr( struct xt_node *node, const char *key ); -
protocols/bee.h
r05bf2a0 r62f53b50 151 151 * - 'state' and 'message' can be NULL */ 152 152 G_MODULE_EXPORT void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, const char *state, const char *message ); 153 G_MODULE_EXPORT void imcb_buddy_status_msg( struct im_connection *ic, const char *handle, const char *message ); 153 154 G_MODULE_EXPORT void imcb_buddy_times( struct im_connection *ic, const char *handle, time_t login, time_t idle ); 154 155 /* Call when a handle says something. 'flags' and 'sent_at may be just 0. */ -
protocols/bee_user.c
r05bf2a0 r62f53b50 187 187 /* TODO(wilmer): OPT_AWAY, or just state == NULL ? */ 188 188 bu->flags = flags; 189 bu->status = g_strdup( ( flags & OPT_AWAY ) && state == NULL ? "Away" : state );190 189 bu->status_msg = g_strdup( message ); 190 if( state && *state ) 191 bu->status = g_strdup( state ); 192 else if( flags & OPT_AWAY ) 193 bu->status = g_strdup( "Away" ); 194 else 195 bu->status = NULL; 191 196 192 197 if( bu->status == NULL && ( flags & OPT_MOBILE ) && … … 205 210 } 206 211 212 /* Same, but only change the away/status message, not any away/online state info. */ 213 void imcb_buddy_status_msg( struct im_connection *ic, const char *handle, const char *message ) 214 { 215 bee_t *bee = ic->bee; 216 bee_user_t *bu, *old; 217 218 if( !( bu = bee_user_by_handle( bee, ic, handle ) ) ) 219 { 220 return; 221 } 222 223 old = g_memdup( bu, sizeof( bee_user_t ) ); 224 225 bu->status_msg = message && *message ? g_strdup( message ) : NULL; 226 227 if( bee->ui->user_status ) 228 bee->ui->user_status( bee, bu, old ); 229 230 g_free( old->status_msg ); 231 g_free( old ); 232 } 233 207 234 void imcb_buddy_times( struct im_connection *ic, const char *handle, time_t login, time_t idle ) 208 235 { -
protocols/msn/Makefile
r05bf2a0 r62f53b50 13 13 14 14 # [SH] Program variables 15 objects = msn.o msn_util.o ns.o passport.o sb.o tables.o15 objects = msn.o msn_util.o ns.o sb.o soap.o tables.o 16 16 17 17 LFLAGS += -r -
protocols/msn/msn.c
r05bf2a0 r62f53b50 2 2 * BitlBee -- An IRC to other IM-networks gateway * 3 3 * * 4 * Copyright 2002-20 04Wilmer van der Gaast and others *4 * Copyright 2002-2010 Wilmer van der Gaast and others * 5 5 \********************************************************************/ 6 6 … … 25 25 26 26 #include "nogaim.h" 27 #include "soap.h" 27 28 #include "msn.h" 28 29 … … 35 36 static void msn_init( account_t *acc ) 36 37 { 37 set_add( &acc->set, "display_name", NULL, set_eval_display_name, acc ); 38 set_add( &acc->set, "local_display_name", "false", set_eval_bool, acc ); 38 set_t *s; 39 40 s = set_add( &acc->set, "display_name", NULL, set_eval_display_name, acc ); 41 s->flags |= ACC_SET_NOSAVE | ACC_SET_ONLINE_ONLY; 42 39 43 set_add( &acc->set, "mail_notifications", "false", set_eval_bool, acc ); 40 44 set_add( &acc->set, "switchboard_keepalives", "false", set_eval_bool, acc ); 45 46 acc->flags |= ACC_FLAG_AWAY_MESSAGE | ACC_FLAG_STATUS_MESSAGE; 41 47 } 42 48 … … 47 53 48 54 ic->proto_data = md; 49 md->fd = -1;50 55 51 56 if( strchr( acc->user, '@' ) == NULL ) … … 56 61 } 57 62 58 imcb_log( ic, "Connecting" );59 60 md->fd = proxy_connect( "messenger.hotmail.com", 1863, msn_ns_connected, ic );61 if( md->fd < 0 )62 {63 imcb_error( ic, "Could not connect to server" );64 imc_logout( ic, TRUE );65 return;66 }67 68 63 md->ic = ic; 69 64 md->away_state = msn_away_state_list; 70 71 msn_connections = g_slist_append( msn_connections, ic ); 65 md->domaintree = g_tree_new( msn_domaintree_cmp ); 66 md->ns->fd = -1; 67 68 msn_connections = g_slist_prepend( msn_connections, ic ); 69 70 imcb_log( ic, "Connecting" ); 71 msn_ns_connect( ic, md->ns, MSN_NS_HOST, MSN_NS_PORT ); 72 72 } 73 73 … … 76 76 struct msn_data *md = ic->proto_data; 77 77 GSList *l; 78 int i; 78 79 79 80 if( md ) … … 85 86 */ 86 87 87 if( md->fd >= 0 ) 88 closesocket( md->fd ); 89 90 if( md->handler ) 91 { 92 if( md->handler->rxq ) g_free( md->handler->rxq ); 93 if( md->handler->cmd_text ) g_free( md->handler->cmd_text ); 94 g_free( md->handler ); 95 } 88 msn_ns_close( md->ns ); 96 89 97 90 while( md->switchboards ) … … 99 92 100 93 msn_msgq_purge( ic, &md->msgq ); 101 102 while( md->groupcount > 0 ) 103 g_free( md->grouplist[--md->groupcount] ); 104 g_free( md->grouplist ); 94 msn_soapq_flush( ic, FALSE ); 95 96 for( i = 0; i < sizeof( md->tokens ) / sizeof( md->tokens[0] ); i ++ ) 97 g_free( md->tokens[i] ); 98 g_free( md->lock_key ); 99 g_free( md->pp_policy ); 100 101 while( md->groups ) 102 { 103 struct msn_group *mg = md->groups->data; 104 g_free( mg->id ); 105 g_free( mg->name ); 106 g_free( mg ); 107 md->groups = g_slist_remove( md->groups, mg ); 108 } 109 110 g_tree_destroy( md->domaintree ); 111 md->domaintree = NULL; 105 112 106 113 while( md->grpq ) … … 134 141 if( strcmp( who, "raw" ) == 0 ) 135 142 { 136 msn_write( ic, message, strlen( message ) ); 137 msn_write( ic, "\r\n", 2 ); 143 msn_ns_write( ic, -1, "%s\r\n", message ); 138 144 } 139 145 else … … 173 179 static void msn_set_away( struct im_connection *ic, char *state, char *message ) 174 180 { 175 char buf[1024];181 char *uux; 176 182 struct msn_data *md = ic->proto_data; 177 183 … … 181 187 md->away_state = msn_away_state_list + 1; 182 188 183 g_snprintf( buf, sizeof( buf ), "CHG %d %s\r\n", ++md->trId, md->away_state->code );184 msn_write( ic, buf, strlen( buf ) );185 } 186 187 static void msn_set_my_name( struct im_connection *ic, char *info ) 188 { 189 msn_set_display_name( ic, info);189 if( !msn_ns_write( ic, -1, "CHG %d %s\r\n", ++md->trId, md->away_state->code ) ) 190 return; 191 192 uux = g_markup_printf_escaped( "<Data><PSM>%s</PSM><CurrentMedia></CurrentMedia>" 193 "</Data>", message ? message : "" ); 194 msn_ns_write( ic, -1, "UUX %d %zd\r\n%s", ++md->trId, strlen( uux ), uux ); 195 g_free( uux ); 190 196 } 191 197 … … 200 206 struct bee_user *bu = bee_user_by_handle( ic->bee, ic, who ); 201 207 202 msn_buddy_list_add( ic, "FL", who, who, group );208 msn_buddy_list_add( ic, MSN_BUDDY_FL, who, who, group ); 203 209 if( bu && bu->group ) 204 msn_buddy_list_remove( ic, "FL", who, bu->group->name );210 msn_buddy_list_remove( ic, MSN_BUDDY_FL, who, bu->group->name ); 205 211 } 206 212 207 213 static void msn_remove_buddy( struct im_connection *ic, char *who, char *group ) 208 214 { 209 msn_buddy_list_remove( ic, "FL", who, NULL );215 msn_buddy_list_remove( ic, MSN_BUDDY_FL, who, NULL ); 210 216 } 211 217 … … 267 273 static void msn_keepalive( struct im_connection *ic ) 268 274 { 269 msn_ write( ic, "PNG\r\n", strlen( "PNG\r\n" ));275 msn_ns_write( ic, -1, "PNG\r\n" ); 270 276 } 271 277 272 278 static void msn_add_permit( struct im_connection *ic, char *who ) 273 279 { 274 msn_buddy_list_add( ic, "AL", who, who, NULL );280 msn_buddy_list_add( ic, MSN_BUDDY_AL, who, who, NULL ); 275 281 } 276 282 277 283 static void msn_rem_permit( struct im_connection *ic, char *who ) 278 284 { 279 msn_buddy_list_remove( ic, "AL", who, NULL );285 msn_buddy_list_remove( ic, MSN_BUDDY_AL, who, NULL ); 280 286 } 281 287 … … 284 290 struct msn_switchboard *sb; 285 291 286 msn_buddy_list_add( ic, "BL", who, who, NULL );292 msn_buddy_list_add( ic, MSN_BUDDY_BL, who, who, NULL ); 287 293 288 294 /* If there's still a conversation with this person, close it. */ … … 295 301 static void msn_rem_deny( struct im_connection *ic, char *who ) 296 302 { 297 msn_buddy_list_remove( ic, "BL", who, NULL );303 msn_buddy_list_remove( ic, MSN_BUDDY_BL, who, NULL ); 298 304 } 299 305 … … 314 320 account_t *acc = set->data; 315 321 struct im_connection *ic = acc->ic; 316 317 /* Allow any name if we're offline. */ 318 if( ic == NULL ) 319 return value; 322 struct msn_data *md = ic->proto_data; 320 323 321 324 if( strlen( value ) > 129 ) … … 325 328 } 326 329 327 /* Returning NULL would be better, because the server still has to 328 confirm the name change. However, it looks a bit confusing to the 329 user. */ 330 return msn_set_display_name( ic, value ) ? value : NULL; 330 if( md->flags & MSN_GOT_PROFILE_DN ) 331 imcb_log( ic, "Warning: Persistent name changes for this account have to be done " 332 "in the profile. BitlBee doesn't currently support this." ); 333 334 msn_soap_addressbook_set_display_name( ic, value ); 335 return msn_ns_set_display_name( ic, value ) ? value : NULL; 336 } 337 338 static void msn_buddy_data_add( bee_user_t *bu ) 339 { 340 struct msn_data *md = bu->ic->proto_data; 341 bu->data = g_new0( struct msn_buddy_data, 1 ); 342 g_tree_insert( md->domaintree, bu->handle, bu ); 343 } 344 345 static void msn_buddy_data_free( bee_user_t *bu ) 346 { 347 struct msn_data *md = bu->ic->proto_data; 348 g_tree_remove( md->domaintree, bu->handle ); 349 g_free( bu->data ); 331 350 } 332 351 … … 343 362 ret->set_away = msn_set_away; 344 363 ret->get_info = msn_get_info; 345 ret->set_my_name = msn_set_my_name;346 364 ret->add_buddy = msn_add_buddy; 347 365 ret->remove_buddy = msn_remove_buddy; … … 357 375 ret->send_typing = msn_send_typing; 358 376 ret->handle_cmp = g_strcasecmp; 377 ret->buddy_data_add = msn_buddy_data_add; 378 ret->buddy_data_free = msn_buddy_data_free; 379 359 380 //ret->transfer_request = msn_ftp_transfer_request; 360 381 -
protocols/msn/msn.h
r05bf2a0 r62f53b50 2 2 * BitlBee -- An IRC to other IM-networks gateway * 3 3 * * 4 * Copyright 2002-20 04Wilmer van der Gaast and others *4 * Copyright 2002-2010 Wilmer van der Gaast and others * 5 5 \********************************************************************/ 6 6 … … 39 39 #endif 40 40 41 #define QRY_NAME "msmsgs@msnmsgr.com" 42 #define QRY_CODE "Q1P7W2E4J9R8U3S5" 41 /* This should be MSN Messenger 7.0.0813 42 #define MSNP11_PROD_KEY "CFHUR$52U_{VIX5T" 43 #define MSNP11_PROD_ID "PROD0101{0RM?UBW" 44 */ 45 46 #define MSN_NS_HOST "messenger.hotmail.com" 47 #define MSN_NS_PORT 1863 48 49 /* Some other version. 50 #define MSNP11_PROD_KEY "O4BG@C7BWLYQX?5G" 51 #define MSNP11_PROD_ID "PROD01065C%ZFN6F" 52 */ 53 54 #define MSNP11_PROD_KEY "ILTXC!4IXB5FB*PX" 55 #define MSNP11_PROD_ID "PROD0119GSJUC$18" 56 #define MSNP_VER "MSNP15" 57 #define MSNP_BUILD "8.5.1288" 43 58 44 59 #define MSN_SB_NEW -24062002 … … 61 76 #define PROFILE_URL "http://members.msn.com/" 62 77 78 typedef enum 79 { 80 MSN_GOT_PROFILE = 1, 81 MSN_GOT_PROFILE_DN = 2, 82 MSN_DONE_ADL = 4, 83 MSN_REAUTHING = 8, 84 } msn_flags_t; 85 86 struct msn_handler_data 87 { 88 int fd, inpa; 89 int rxlen; 90 char *rxq; 91 92 int msglen; 93 char *cmd_text; 94 95 /* Either ic or sb */ 96 gpointer data; 97 98 int (*exec_command) ( struct msn_handler_data *handler, char **cmd, int count ); 99 int (*exec_message) ( struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int count ); 100 }; 101 63 102 struct msn_data 64 103 { 65 104 struct im_connection *ic; 66 105 67 int fd;68 struct msn_handler_data *handler;106 struct msn_handler_data ns[1]; 107 msn_flags_t flags; 69 108 70 109 int trId; 71 72 GSList *msgq, *grpq; 110 char *tokens[4]; 111 char *lock_key, *pp_policy; 112 113 GSList *msgq, *grpq, *soapq; 73 114 GSList *switchboards; 74 115 int sb_failures; 75 116 time_t first_sb_failure; 76 GSList *filetransfers;77 117 78 118 const struct msn_away_state *away_state; 79 int buddycount; 80 int groupcount; 81 char **grouplist; 119 GSList *groups; 120 121 /* Mostly used for sending the ADL command; since MSNP13 the client 122 is responsible for downloading the contact list and then sending 123 it to the MSNP server. */ 124 GTree *domaintree; 125 int adl_todo; 82 126 }; 83 127 … … 86 130 struct im_connection *ic; 87 131 132 /* The following two are also in the handler. TODO: Clean up. */ 88 133 int fd; 89 134 gint inp; … … 127 172 }; 128 173 129 struct msn_handler_data 130 { 131 int fd; 132 int rxlen; 133 char *rxq; 134 135 int msglen; 136 char *cmd_text; 137 138 gpointer data; 139 140 int (*exec_command) ( gpointer data, char **cmd, int count ); 141 int (*exec_message) ( gpointer data, char *msg, int msglen, char **cmd, int count ); 174 typedef enum 175 { 176 MSN_BUDDY_FL = 1, /* Warning: FL,AL,BL *must* be 1,2,4. */ 177 MSN_BUDDY_AL = 2, 178 MSN_BUDDY_BL = 4, 179 MSN_BUDDY_RL = 8, 180 MSN_BUDDY_PL = 16, 181 MSN_BUDDY_ADL_SYNCED = 256, 182 } msn_buddy_flags_t; 183 184 struct msn_buddy_data 185 { 186 char *cid; 187 msn_buddy_flags_t flags; 188 }; 189 190 struct msn_group 191 { 192 char *name; 193 char *id; 142 194 }; 143 195 … … 161 213 162 214 /* ns.c */ 163 gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ); 215 int msn_ns_write( struct im_connection *ic, int fd, const char *fmt, ... ); 216 gboolean msn_ns_connect( struct im_connection *ic, struct msn_handler_data *handler, const char *host, int port ); 217 void msn_ns_close( struct msn_handler_data *handler ); 218 void msn_auth_got_passport_token( struct im_connection *ic, const char *token, const char *error ); 219 void msn_auth_got_contact_list( struct im_connection *ic ); 220 int msn_ns_finish_login( struct im_connection *ic ); 164 221 165 222 /* msn_util.c */ 166 int msn_write( struct im_connection *ic, char *s, int len );167 223 int msn_logged_in( struct im_connection *ic ); 168 int msn_buddy_list_add( struct im_connection *ic, const char *list, const char *who, const char *realname_, const char *group );169 int msn_buddy_list_remove( struct im_connection *ic, char *list, const char *who, const char *group );170 void msn_buddy_ask( struct im_connection *ic, char *handle, char *realname);224 int msn_buddy_list_add( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *realname_, const char *group ); 225 int msn_buddy_list_remove( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group ); 226 void msn_buddy_ask( bee_user_t *bu ); 171 227 char *msn_findheader( char *text, char *header, int len ); 172 228 char **msn_linesplit( char *line ); 173 229 int msn_handler( struct msn_handler_data *h ); 174 char *msn_http_encode( const char *input );175 230 void msn_msgq_purge( struct im_connection *ic, GSList **list ); 176 gboolean msn_set_display_name( struct im_connection *ic, const char *rawname ); 231 char *msn_p11_challenge( char *challenge ); 232 gint msn_domaintree_cmp( gconstpointer a_, gconstpointer b_ ); 233 struct msn_group *msn_group_by_name( struct im_connection *ic, const char *name ); 234 struct msn_group *msn_group_by_id( struct im_connection *ic, const char *id ); 235 int msn_ns_set_display_name( struct im_connection *ic, const char *value ); 177 236 178 237 /* tables.c */ … … 183 242 184 243 /* sb.c */ 185 int msn_sb_write( struct msn_switchboard *sb, c har *s, int len);244 int msn_sb_write( struct msn_switchboard *sb, const char *fmt, ... ); 186 245 struct msn_switchboard *msn_sb_create( struct im_connection *ic, char *host, int port, char *key, int session ); 187 246 struct msn_switchboard *msn_sb_by_handle( struct im_connection *ic, char *handle ); … … 196 255 void msn_sb_stop_keepalives( struct msn_switchboard *sb ); 197 256 198 /* invitation.c */199 void msn_ftp_transfer_request( struct im_connection *ic, file_transfer_t *ft, char *who );200 201 257 #endif //_MSN_H -
protocols/msn/msn_util.c
r05bf2a0 r62f53b50 2 2 * BitlBee -- An IRC to other IM-networks gateway * 3 3 * * 4 * Copyright 2002-20 04Wilmer van der Gaast and others *4 * Copyright 2002-2010 Wilmer van der Gaast and others * 5 5 \********************************************************************/ 6 6 … … 26 26 #include "nogaim.h" 27 27 #include "msn.h" 28 #include "md5.h" 29 #include "soap.h" 28 30 #include <ctype.h> 29 31 30 int msn_write( struct im_connection *ic, char *s, int len ) 32 int msn_logged_in( struct im_connection *ic ) 33 { 34 imcb_connected( ic ); 35 36 return( 0 ); 37 } 38 39 static char *adlrml_entry( const char *handle_, msn_buddy_flags_t list ) 40 { 41 char *domain, handle[strlen(handle_)+1]; 42 43 strcpy( handle, handle_ ); 44 if( ( domain = strchr( handle, '@' ) ) ) 45 *(domain++) = '\0'; 46 else 47 return NULL; 48 49 return g_markup_printf_escaped( "<ml><d n=\"%s\"><c n=\"%s\" l=\"%d\" t=\"1\"/></d></ml>", 50 domain, handle, list ); 51 } 52 53 int msn_buddy_list_add( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *realname, const char *group ) 31 54 { 32 55 struct msn_data *md = ic->proto_data; 33 int st; 34 35 st = write( md->fd, s, len ); 36 if( st != len ) 37 { 38 imcb_error( ic, "Short write() to main server" ); 39 imc_logout( ic, TRUE ); 40 return 0; 41 } 42 43 return 1; 44 } 45 46 int msn_logged_in( struct im_connection *ic ) 47 { 48 imcb_connected( ic ); 49 50 return( 0 ); 51 } 52 53 int msn_buddy_list_add( struct im_connection *ic, const char *list, const char *who, const char *realname_, const char *group ) 54 { 55 struct msn_data *md = ic->proto_data; 56 char buf[1024], *realname, groupid[8]; 56 char groupid[8]; 57 bee_user_t *bu; 58 struct msn_buddy_data *bd; 59 char *adl; 57 60 58 61 *groupid = '\0'; 62 #if 0 59 63 if( group ) 60 64 { … … 87 91 if( l == NULL ) 88 92 { 89 char *groupname = msn_http_encode( group ); 93 char groupname[strlen(group)+1]; 94 strcpy( groupname, group ); 95 http_encode( groupname ); 90 96 g_snprintf( buf, sizeof( buf ), "ADG %d %s %d\r\n", ++md->trId, groupname, 0 ); 91 g_free( groupname );92 97 return msn_write( ic, buf, strlen( buf ) ); 93 98 } … … 101 106 } 102 107 } 103 104 realname = msn_http_encode( realname_ ); 105 g_snprintf( buf, sizeof( buf ), "ADD %d %s %s %s%s\r\n", ++md->trId, list, who, realname, groupid ); 106 g_free( realname ); 107 108 return msn_write( ic, buf, strlen( buf ) ); 109 } 110 111 int msn_buddy_list_remove( struct im_connection *ic, char *list, const char *who, const char *group ) 108 #endif 109 110 if( !( ( bu = bee_user_by_handle( ic->bee, ic, who ) ) || 111 ( bu = bee_user_new( ic->bee, ic, who, 0 ) ) ) || 112 !( bd = bu->data ) || bd->flags & list ) 113 return 1; 114 115 bd->flags |= list; 116 117 if( list == MSN_BUDDY_FL ) 118 msn_soap_ab_contact_add( ic, bu ); 119 else 120 msn_soap_memlist_edit( ic, who, TRUE, list ); 121 122 if( ( adl = adlrml_entry( who, list ) ) ) 123 { 124 int st = msn_ns_write( ic, -1, "ADL %d %zd\r\n%s", 125 ++md->trId, strlen( adl ), adl ); 126 g_free( adl ); 127 128 return st; 129 } 130 131 return 1; 132 } 133 134 int msn_buddy_list_remove( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group ) 112 135 { 113 136 struct msn_data *md = ic->proto_data; 114 char buf[1024], groupid[8]; 137 char groupid[8]; 138 bee_user_t *bu; 139 struct msn_buddy_data *bd; 140 char *adl; 115 141 116 142 *groupid = '\0'; 143 #if 0 117 144 if( group ) 118 145 { … … 125 152 } 126 153 } 127 128 g_snprintf( buf, sizeof( buf ), "REM %d %s %s%s\r\n", ++md->trId, list, who, groupid ); 129 if( msn_write( ic, buf, strlen( buf ) ) ) 130 return( 1 ); 131 132 return( 0 ); 154 #endif 155 156 if( !( bu = bee_user_by_handle( ic->bee, ic, who ) ) || 157 !( bd = bu->data ) || !( bd->flags & list ) ) 158 return 1; 159 160 bd->flags &= ~list; 161 162 if( list == MSN_BUDDY_FL ) 163 msn_soap_ab_contact_del( ic, bu ); 164 else 165 msn_soap_memlist_edit( ic, who, FALSE, list ); 166 167 if( ( adl = adlrml_entry( who, list ) ) ) 168 { 169 int st = msn_ns_write( ic, -1, "RML %d %zd\r\n%s", 170 ++md->trId, strlen( adl ), adl ); 171 g_free( adl ); 172 173 return st; 174 } 175 176 return 1; 133 177 } 134 178 … … 144 188 struct msn_buddy_ask_data *bla = data; 145 189 146 msn_buddy_list_add( bla->ic, "AL", bla->handle, bla->realname, NULL );190 msn_buddy_list_add( bla->ic, MSN_BUDDY_AL, bla->handle, bla->realname, NULL ); 147 191 148 192 imcb_ask_add( bla->ic, bla->handle, NULL ); … … 157 201 struct msn_buddy_ask_data *bla = data; 158 202 159 msn_buddy_list_add( bla->ic, "BL", bla->handle, bla->realname, NULL );203 msn_buddy_list_add( bla->ic, MSN_BUDDY_BL, bla->handle, bla->realname, NULL ); 160 204 161 205 g_free( bla->handle ); … … 164 208 } 165 209 166 void msn_buddy_ask( struct im_connection *ic, char *handle, char *realname ) 167 { 168 struct msn_buddy_ask_data *bla = g_new0( struct msn_buddy_ask_data, 1 ); 210 void msn_buddy_ask( bee_user_t *bu ) 211 { 212 struct msn_buddy_ask_data *bla; 213 struct msn_buddy_data *bd = bu->data; 169 214 char buf[1024]; 170 215 171 bla->ic = ic; 172 bla->handle = g_strdup( handle ); 173 bla->realname = g_strdup( realname ); 216 if( ( bd->flags & 30 ) != 8 && ( bd->flags & 30 ) != 16 ) 217 return; 218 219 bla = g_new0( struct msn_buddy_ask_data, 1 ); 220 bla->ic = bu->ic; 221 bla->handle = g_strdup( bu->handle ); 222 bla->realname = g_strdup( bu->fullname ); 174 223 175 224 g_snprintf( buf, sizeof( buf ), 176 225 "The user %s (%s) wants to add you to his/her buddy list.", 177 handle, realname );178 imcb_ask( ic, buf, bla, msn_buddy_ask_yes, msn_buddy_ask_no );226 bu->handle, bu->fullname ); 227 imcb_ask( bu->ic, buf, bla, msn_buddy_ask_yes, msn_buddy_ask_no ); 179 228 } 180 229 … … 279 328 if( st <= 0 ) 280 329 return( -1 ); 330 331 if( getenv( "BITLBEE_DEBUG" ) ) 332 { 333 write( 2, "->C:", 4 ); 334 write( 2, h->rxq + h->rxlen - st, st ); 335 } 281 336 282 337 while( st ) … … 296 351 cmd = msn_linesplit( cmd_text ); 297 352 for( count = 0; cmd[count]; count ++ ); 298 st = h->exec_command( h ->data, cmd, count );353 st = h->exec_command( h, cmd, count ); 299 354 g_free( cmd_text ); 300 355 … … 331 386 for( count = 0; cmd[count]; count ++ ); 332 387 333 st = h->exec_message( h ->data, msg, h->msglen, cmd, count );388 st = h->exec_message( h, msg, h->msglen, cmd, count ); 334 389 g_free( msg ); 335 390 g_free( h->cmd_text ); … … 367 422 } 368 423 369 /* The difference between this function and the normal http_encode() function370 is that this one escapes every 7-bit ASCII character because this is said371 to avoid some lame server-side checks when setting a real-name. Also,372 non-ASCII characters are not escaped because MSN servers don't seem to373 appreciate that! */374 char *msn_http_encode( const char *input )375 {376 char *ret, *s;377 int i;378 379 ret = s = g_new0( char, strlen( input ) * 3 + 1 );380 for( i = 0; input[i]; i ++ )381 if( input[i] & 128 )382 {383 *s = input[i];384 s ++;385 }386 else387 {388 g_snprintf( s, 4, "%%%02X", input[i] );389 s += 3;390 }391 392 return ret;393 }394 395 424 void msn_msgq_purge( struct im_connection *ic, GSList **list ) 396 425 { … … 433 462 } 434 463 435 gboolean msn_set_display_name( struct im_connection *ic, const char *rawname ) 436 { 437 char *fn = msn_http_encode( rawname ); 464 /* Copied and heavily modified from http://tmsnc.sourceforge.net/chl.c */ 465 char *msn_p11_challenge( char *challenge ) 466 { 467 char *output, buf[256]; 468 md5_state_t md5c; 469 unsigned char md5Hash[16], *newHash; 470 unsigned int *md5Parts, *chlStringParts, newHashParts[5]; 471 long long nHigh = 0, nLow = 0; 472 int i, n; 473 474 /* Create the MD5 hash */ 475 md5_init(&md5c); 476 md5_append(&md5c, (unsigned char*) challenge, strlen(challenge)); 477 md5_append(&md5c, (unsigned char*) MSNP11_PROD_KEY, strlen(MSNP11_PROD_KEY)); 478 md5_finish(&md5c, md5Hash); 479 480 /* Split it into four integers */ 481 md5Parts = (unsigned int *)md5Hash; 482 for (i = 0; i < 4; i ++) 483 { 484 md5Parts[i] = GUINT32_TO_LE(md5Parts[i]); 485 486 /* & each integer with 0x7FFFFFFF */ 487 /* and save one unmodified array for later */ 488 newHashParts[i] = md5Parts[i]; 489 md5Parts[i] &= 0x7FFFFFFF; 490 } 491 492 /* make a new string and pad with '0' */ 493 n = g_snprintf(buf, sizeof(buf)-5, "%s%s00000000", challenge, MSNP11_PROD_ID); 494 /* truncate at an 8-byte boundary */ 495 buf[n&=~7] = '\0'; 496 497 /* split into integers */ 498 chlStringParts = (unsigned int *)buf; 499 500 /* this is magic */ 501 for (i = 0; i < (n / 4) - 1; i += 2) 502 { 503 long long temp; 504 505 chlStringParts[i] = GUINT32_TO_LE(chlStringParts[i]); 506 chlStringParts[i+1] = GUINT32_TO_LE(chlStringParts[i+1]); 507 508 temp = (md5Parts[0] * (((0x0E79A9C1 * (long long)chlStringParts[i]) % 0x7FFFFFFF)+nHigh) + md5Parts[1])%0x7FFFFFFF; 509 nHigh = (md5Parts[2] * (((long long)chlStringParts[i+1]+temp) % 0x7FFFFFFF) + md5Parts[3]) % 0x7FFFFFFF; 510 nLow = nLow + nHigh + temp; 511 } 512 nHigh = (nHigh+md5Parts[1]) % 0x7FFFFFFF; 513 nLow = (nLow+md5Parts[3]) % 0x7FFFFFFF; 514 515 newHashParts[0] ^= nHigh; 516 newHashParts[1] ^= nLow; 517 newHashParts[2] ^= nHigh; 518 newHashParts[3] ^= nLow; 519 520 /* swap more bytes if big endian */ 521 for (i = 0; i < 4; i ++) 522 newHashParts[i] = GUINT32_TO_LE(newHashParts[i]); 523 524 /* make a string of the parts */ 525 newHash = (unsigned char *)newHashParts; 526 527 /* convert to hexadecimal */ 528 output = g_new(char, 33); 529 for (i = 0; i < 16; i ++) 530 sprintf(output + i * 2, "%02x", newHash[i]); 531 532 return output; 533 } 534 535 gint msn_domaintree_cmp( gconstpointer a_, gconstpointer b_ ) 536 { 537 const char *a = a_, *b = b_; 538 gint ret; 539 540 if( !( a = strchr( a, '@' ) ) || !( b = strchr( b, '@' ) ) || 541 ( ret = strcmp( a, b ) ) == 0 ) 542 ret = strcmp( a_, b_ ); 543 544 return ret; 545 } 546 547 struct msn_group *msn_group_by_name( struct im_connection *ic, const char *name ) 548 { 438 549 struct msn_data *md = ic->proto_data; 439 char buf[1024]; 440 441 g_snprintf( buf, sizeof( buf ), "REA %d %s %s\r\n", ++md->trId, ic->acc->user, fn ); 442 g_free( fn ); 443 444 return msn_write( ic, buf, strlen( buf ) ) != 0; 445 } 550 GSList *l; 551 552 for( l = md->groups; l; l = l->next ) 553 { 554 struct msn_group *mg = l->data; 555 556 if( g_strcasecmp( mg->name, name ) == 0 ) 557 return mg; 558 } 559 560 return NULL; 561 } 562 563 struct msn_group *msn_group_by_id( struct im_connection *ic, const char *id ) 564 { 565 struct msn_data *md = ic->proto_data; 566 GSList *l; 567 568 for( l = md->groups; l; l = l->next ) 569 { 570 struct msn_group *mg = l->data; 571 572 if( g_strcasecmp( mg->id, id ) == 0 ) 573 return mg; 574 } 575 576 return NULL; 577 } 578 579 int msn_ns_set_display_name( struct im_connection *ic, const char *value ) 580 { 581 struct msn_data *md = ic->proto_data; 582 char fn[strlen(value)*3+1]; 583 584 strcpy( fn, value ); 585 http_encode( fn ); 586 587 /* Note: We don't actually know if the server accepted the new name, 588 and won't give proper feedback yet if it doesn't. */ 589 return msn_ns_write( ic, -1, "PRP %d MFN %s\r\n", ++md->trId, fn ); 590 } -
protocols/msn/ns.c
r05bf2a0 r62f53b50 2 2 * BitlBee -- An IRC to other IM-networks gateway * 3 3 * * 4 * Copyright 2002-20 04Wilmer van der Gaast and others *4 * Copyright 2002-2010 Wilmer van der Gaast and others * 5 5 \********************************************************************/ 6 6 … … 27 27 #include "nogaim.h" 28 28 #include "msn.h" 29 #include "passport.h"30 29 #include "md5.h" 31 30 #include "soap.h" 31 #include "xmltree.h" 32 33 static gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ); 32 34 static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition cond ); 33 static int msn_ns_command( gpointer data, char **cmd, int num_parts ); 34 static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts ); 35 36 static void msn_auth_got_passport_token( struct msn_auth_data *mad ); 37 static gboolean msn_ns_got_display_name( struct im_connection *ic, char *name ); 38 39 gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ) 40 { 41 struct im_connection *ic = data; 42 struct msn_data *md; 43 char s[1024]; 44 45 if( !g_slist_find( msn_connections, ic ) ) 46 return FALSE; 47 48 if( source == -1 ) 35 static int msn_ns_command( struct msn_handler_data *handler, char **cmd, int num_parts ); 36 static int msn_ns_message( struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts ); 37 38 static void msn_ns_send_adl_start( struct im_connection *ic ); 39 static void msn_ns_send_adl( struct im_connection *ic ); 40 41 int msn_ns_write( struct im_connection *ic, int fd, const char *fmt, ... ) 42 { 43 struct msn_data *md = ic->proto_data; 44 va_list params; 45 char *out; 46 size_t len; 47 int st; 48 49 va_start( params, fmt ); 50 out = g_strdup_vprintf( fmt, params ); 51 va_end( params ); 52 53 if( fd < 0 ) 54 fd = md->ns->fd; 55 56 if( getenv( "BITLBEE_DEBUG" ) ) 57 fprintf( stderr, "->NS%d:%s", fd, out ); 58 59 len = strlen( out ); 60 st = write( fd, out, len ); 61 g_free( out ); 62 if( st != len ) 63 { 64 imcb_error( ic, "Short write() to main server" ); 65 imc_logout( ic, TRUE ); 66 return 0; 67 } 68 69 return 1; 70 } 71 72 gboolean msn_ns_connect( struct im_connection *ic, struct msn_handler_data *handler, const char *host, int port ) 73 { 74 if( handler->fd >= 0 ) 75 closesocket( handler->fd ); 76 77 handler->exec_command = msn_ns_command; 78 handler->exec_message = msn_ns_message; 79 handler->data = ic; 80 handler->fd = proxy_connect( host, port, msn_ns_connected, handler ); 81 if( handler->fd < 0 ) 49 82 { 50 83 imcb_error( ic, "Could not connect to server" ); … … 53 86 } 54 87 88 return TRUE; 89 } 90 91 static gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ) 92 { 93 struct msn_handler_data *handler = data; 94 struct im_connection *ic = handler->data; 95 struct msn_data *md; 96 97 if( !g_slist_find( msn_connections, ic ) ) 98 return FALSE; 99 55 100 md = ic->proto_data; 56 101 57 if( !md->handler ) 58 { 59 md->handler = g_new0( struct msn_handler_data, 1 ); 60 md->handler->data = ic; 61 md->handler->exec_command = msn_ns_command; 62 md->handler->exec_message = msn_ns_message; 63 } 64 else 65 { 66 if( md->handler->rxq ) 67 g_free( md->handler->rxq ); 68 69 md->handler->rxlen = 0; 70 } 71 72 md->handler->fd = md->fd; 73 md->handler->rxq = g_new0( char, 1 ); 74 75 g_snprintf( s, sizeof( s ), "VER %d MSNP8 CVR0\r\n", ++md->trId ); 76 if( msn_write( ic, s, strlen( s ) ) ) 77 { 78 ic->inpa = b_input_add( md->fd, B_EV_IO_READ, msn_ns_callback, ic ); 102 if( source == -1 ) 103 { 104 imcb_error( ic, "Could not connect to server" ); 105 imc_logout( ic, TRUE ); 106 return FALSE; 107 } 108 109 g_free( handler->rxq ); 110 handler->rxlen = 0; 111 handler->rxq = g_new0( char, 1 ); 112 113 if( msn_ns_write( ic, source, "VER %d %s CVR0\r\n", ++md->trId, MSNP_VER ) ) 114 { 115 handler->inpa = b_input_add( handler->fd, B_EV_IO_READ, msn_ns_callback, handler ); 79 116 imcb_log( ic, "Connected to server, waiting for reply" ); 80 117 } … … 83 120 } 84 121 122 void msn_ns_close( struct msn_handler_data *handler ) 123 { 124 if( handler->fd >= 0 ) 125 { 126 closesocket( handler->fd ); 127 b_event_remove( handler->inpa ); 128 } 129 130 handler->fd = handler->inpa = -1; 131 g_free( handler->rxq ); 132 g_free( handler->cmd_text ); 133 134 handler->rxlen = 0; 135 handler->rxq = NULL; 136 handler->cmd_text = NULL; 137 } 138 85 139 static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition cond ) 86 140 { 87 struct im_connection *ic= data;88 struct msn_data *md = ic->proto_data;89 90 if( msn_handler( md->handler ) == -1 ) /* Don't do this on ret == 0, it's already done then. */141 struct msn_handler_data *handler = data; 142 struct im_connection *ic = handler->data; 143 144 if( msn_handler( handler ) == -1 ) /* Don't do this on ret == 0, it's already done then. */ 91 145 { 92 146 imcb_error( ic, "Error while reading from server" ); … … 99 153 } 100 154 101 static int msn_ns_command( gpointer data, char **cmd, int num_parts )102 { 103 struct im_connection *ic = data;155 static int msn_ns_command( struct msn_handler_data *handler, char **cmd, int num_parts ) 156 { 157 struct im_connection *ic = handler->data; 104 158 struct msn_data *md = ic->proto_data; 105 char buf[1024];106 159 107 160 if( num_parts == 0 ) … … 113 166 if( strcmp( cmd[0], "VER" ) == 0 ) 114 167 { 115 if( cmd[2] && strncmp( cmd[2], "MSNP8", 5 ) != 0 )168 if( cmd[2] && strncmp( cmd[2], MSNP_VER, 5 ) != 0 ) 116 169 { 117 170 imcb_error( ic, "Unsupported protocol" ); … … 120 173 } 121 174 122 g_snprintf( buf, sizeof( buf ), "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s\r\n", 123 ++md->trId, ic->acc->user ); 124 return( msn_write( ic, buf, strlen( buf ) ) ); 175 return( msn_ns_write( ic, handler->fd, "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s\r\n", 176 ++md->trId, ic->acc->user ) ); 125 177 } 126 178 else if( strcmp( cmd[0], "CVR" ) == 0 ) 127 179 { 128 180 /* We don't give a damn about the information we just received */ 129 g_snprintf( buf, sizeof( buf ), "USR %d TWN I %s\r\n", ++md->trId, ic->acc->user ); 130 return( msn_write( ic, buf, strlen( buf ) ) ); 181 return msn_ns_write( ic, handler->fd, "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user ); 131 182 } 132 183 else if( strcmp( cmd[0], "XFR" ) == 0 ) … … 135 186 int port; 136 187 137 if( num_parts == 6 && strcmp( cmd[2], "NS" ) == 0 ) 138 { 139 b_event_remove( ic->inpa ); 140 ic->inpa = 0; 141 closesocket( md->fd ); 188 if( num_parts >= 6 && strcmp( cmd[2], "NS" ) == 0 ) 189 { 190 b_event_remove( handler->inpa ); 191 handler->inpa = -1; 142 192 143 193 server = strchr( cmd[3], ':' ); … … 153 203 154 204 imcb_log( ic, "Transferring to other server" ); 155 156 md->fd = proxy_connect( server, port, msn_ns_connected, ic ); 157 } 158 else if( num_parts == 6 && strcmp( cmd[2], "SB" ) == 0 ) 205 return msn_ns_connect( ic, handler, server, port ); 206 } 207 else if( num_parts >= 6 && strcmp( cmd[2], "SB" ) == 0 ) 159 208 { 160 209 struct msn_switchboard *sb; … … 220 269 else if( strcmp( cmd[0], "USR" ) == 0 ) 221 270 { 222 if( num_parts == 5 && strcmp( cmd[2], "TWN" ) == 0 && strcmp( cmd[3], "S" ) == 0 ) 223 { 224 /* Time for some Passport black magic... */ 225 if( !passport_get_token( msn_auth_got_passport_token, ic, ic->acc->user, ic->acc->pass, cmd[4] ) ) 226 { 227 imcb_error( ic, "Error while contacting Passport server" ); 228 imc_logout( ic, TRUE ); 229 return( 0 ); 230 } 231 } 232 else if( num_parts >= 7 && strcmp( cmd[2], "OK" ) == 0 ) 233 { 234 if( num_parts == 7 ) 235 msn_ns_got_display_name( ic, cmd[4] ); 236 else 237 imcb_log( ic, "Warning: Friendly name in server response was corrupted" ); 238 271 if( num_parts >= 6 && strcmp( cmd[2], "SSO" ) == 0 && 272 strcmp( cmd[3], "S" ) == 0 ) 273 { 274 g_free( md->pp_policy ); 275 md->pp_policy = g_strdup( cmd[4] ); 276 msn_soap_passport_sso_request( ic, cmd[5] ); 277 } 278 else if( strcmp( cmd[2], "OK" ) == 0 ) 279 { 239 280 imcb_log( ic, "Authenticated, getting buddy list" ); 240 241 g_snprintf( buf, sizeof( buf ), "SYN %d 0\r\n", ++md->trId ); 242 return( msn_write( ic, buf, strlen( buf ) ) ); 281 msn_soap_memlist_request( ic ); 243 282 } 244 283 else … … 251 290 else if( strcmp( cmd[0], "MSG" ) == 0 ) 252 291 { 253 if( num_parts != 4 ) 254 { 255 imcb_error( ic, "Syntax error" ); 256 imc_logout( ic, TRUE ); 257 return( 0 ); 258 } 259 260 md->handler->msglen = atoi( cmd[3] ); 261 262 if( md->handler->msglen <= 0 ) 263 { 264 imcb_error( ic, "Syntax error" ); 265 imc_logout( ic, TRUE ); 266 return( 0 ); 267 } 268 } 269 else if( strcmp( cmd[0], "SYN" ) == 0 ) 270 { 271 if( num_parts == 5 ) 272 { 273 int i, groupcount; 274 275 groupcount = atoi( cmd[4] ); 276 if( groupcount > 0 ) 277 { 278 /* valgrind says this is leaking memory, I'm guessing 279 that this happens during server redirects. */ 280 if( md->grouplist ) 281 { 282 for( i = 0; i < md->groupcount; i ++ ) 283 g_free( md->grouplist[i] ); 284 g_free( md->grouplist ); 285 } 286 287 md->groupcount = groupcount; 288 md->grouplist = g_new0( char *, md->groupcount ); 289 } 290 291 md->buddycount = atoi( cmd[3] ); 292 if( !*cmd[3] || md->buddycount == 0 ) 293 msn_logged_in( ic ); 294 } 295 else 296 { 297 /* Hrrm... This SYN reply doesn't really look like something we expected. 298 Let's assume everything is okay. */ 299 300 msn_logged_in( ic ); 301 } 302 } 303 else if( strcmp( cmd[0], "LST" ) == 0 ) 304 { 305 int list; 306 307 if( num_parts != 4 && num_parts != 5 ) 308 { 309 imcb_error( ic, "Syntax error" ); 310 imc_logout( ic, TRUE ); 311 return( 0 ); 312 } 313 314 http_decode( cmd[2] ); 315 list = atoi( cmd[3] ); 316 317 if( list & 1 ) /* FL */ 318 { 319 char *group = NULL; 320 int num; 321 322 if( cmd[4] != NULL && sscanf( cmd[4], "%d", &num ) == 1 && num < md->groupcount ) 323 group = md->grouplist[num]; 324 325 imcb_add_buddy( ic, cmd[1], group ); 326 imcb_rename_buddy( ic, cmd[1], cmd[2] ); 327 } 328 if( list & 2 ) /* AL */ 329 { 330 ic->permit = g_slist_append( ic->permit, g_strdup( cmd[1] ) ); 331 } 332 if( list & 4 ) /* BL */ 333 { 334 ic->deny = g_slist_append( ic->deny, g_strdup( cmd[1] ) ); 335 } 336 if( list & 8 ) /* RL */ 337 { 338 if( ( list & 6 ) == 0 ) 339 msn_buddy_ask( ic, cmd[1], cmd[2] ); 340 } 341 342 if( --md->buddycount == 0 ) 343 { 344 if( ic->flags & OPT_LOGGED_IN ) 345 { 346 imcb_log( ic, "Successfully transferred to different server" ); 347 g_snprintf( buf, sizeof( buf ), "CHG %d %s %d\r\n", ++md->trId, md->away_state->code, 0 ); 348 return( msn_write( ic, buf, strlen( buf ) ) ); 349 } 350 else 351 { 352 msn_logged_in( ic ); 353 } 354 } 355 } 356 else if( strcmp( cmd[0], "LSG" ) == 0 ) 357 { 358 int num; 359 360 if( num_parts != 4 ) 361 { 362 imcb_error( ic, "Syntax error" ); 363 imc_logout( ic, TRUE ); 364 return( 0 ); 365 } 366 367 http_decode( cmd[2] ); 368 num = atoi( cmd[1] ); 369 370 if( num < md->groupcount ) 371 md->grouplist[num] = g_strdup( cmd[2] ); 292 if( num_parts < 4 ) 293 { 294 imcb_error( ic, "Syntax error" ); 295 imc_logout( ic, TRUE ); 296 return( 0 ); 297 } 298 299 handler->msglen = atoi( cmd[3] ); 300 301 if( handler->msglen <= 0 ) 302 { 303 imcb_error( ic, "Syntax error" ); 304 imc_logout( ic, TRUE ); 305 return( 0 ); 306 } 307 } 308 else if( strcmp( cmd[0], "BLP" ) == 0 ) 309 { 310 msn_ns_send_adl_start( ic ); 311 return msn_ns_finish_login( ic ); 312 } 313 else if( strcmp( cmd[0], "ADL" ) == 0 ) 314 { 315 if( num_parts >= 3 && strcmp( cmd[2], "OK" ) == 0 ) 316 { 317 msn_ns_send_adl( ic ); 318 return msn_ns_finish_login( ic ); 319 } 320 else if( num_parts >= 3 ) 321 { 322 handler->msglen = atoi( cmd[2] ); 323 } 324 } 325 else if( strcmp( cmd[0], "PRP" ) == 0 ) 326 { 327 imcb_connected( ic ); 372 328 } 373 329 else if( strcmp( cmd[0], "CHL" ) == 0 ) 374 330 { 375 md5_state_t state; 376 md5_byte_t digest[16]; 377 int i; 378 379 if( num_parts != 3 ) 380 { 381 imcb_error( ic, "Syntax error" ); 382 imc_logout( ic, TRUE ); 383 return( 0 ); 384 } 385 386 md5_init( &state ); 387 md5_append( &state, (const md5_byte_t *) cmd[2], strlen( cmd[2] ) ); 388 md5_append( &state, (const md5_byte_t *) QRY_CODE, strlen( QRY_CODE ) ); 389 md5_finish( &state, digest ); 390 391 g_snprintf( buf, sizeof( buf ), "QRY %d %s %d\r\n", ++md->trId, QRY_NAME, 32 ); 392 for( i = 0; i < 16; i ++ ) 393 g_snprintf( buf + strlen( buf ), 3, "%02x", digest[i] ); 394 395 return( msn_write( ic, buf, strlen( buf ) ) ); 331 char *resp; 332 int st; 333 334 if( num_parts < 3 ) 335 { 336 imcb_error( ic, "Syntax error" ); 337 imc_logout( ic, TRUE ); 338 return( 0 ); 339 } 340 341 resp = msn_p11_challenge( cmd[2] ); 342 343 st = msn_ns_write( ic, -1, "QRY %d %s %zd\r\n%s", 344 ++md->trId, MSNP11_PROD_ID, 345 strlen( resp ), resp ); 346 g_free( resp ); 347 return st; 396 348 } 397 349 else if( strcmp( cmd[0], "ILN" ) == 0 ) … … 399 351 const struct msn_away_state *st; 400 352 401 if( num_parts !=6 )402 { 403 imcb_error( ic, "Syntax error" ); 404 imc_logout( ic, TRUE ); 405 return( 0 ); 406 } 407 408 http_decode( cmd[ 4] );409 imcb_rename_buddy( ic, cmd[3], cmd[ 4] );353 if( num_parts < 6 ) 354 { 355 imcb_error( ic, "Syntax error" ); 356 imc_logout( ic, TRUE ); 357 return( 0 ); 358 } 359 360 http_decode( cmd[5] ); 361 imcb_rename_buddy( ic, cmd[3], cmd[5] ); 410 362 411 363 st = msn_away_state_by_code( cmd[2] ); … … 432 384 { 433 385 const struct msn_away_state *st; 434 435 if( num_parts != 5 ) 436 { 437 imcb_error( ic, "Syntax error" ); 438 imc_logout( ic, TRUE ); 439 return( 0 ); 440 } 441 442 http_decode( cmd[3] ); 443 imcb_rename_buddy( ic, cmd[2], cmd[3] ); 386 int cap; 387 388 if( num_parts < 6 ) 389 { 390 imcb_error( ic, "Syntax error" ); 391 imc_logout( ic, TRUE ); 392 return( 0 ); 393 } 394 395 http_decode( cmd[4] ); 396 cap = atoi( cmd[5] ); 397 imcb_rename_buddy( ic, cmd[2], cmd[4] ); 444 398 445 399 st = msn_away_state_by_code( cmd[1] ); … … 451 405 452 406 imcb_buddy_status( ic, cmd[2], OPT_LOGGED_IN | 453 ( st != msn_away_state_list ? OPT_AWAY : 0 ), 407 ( st != msn_away_state_list ? OPT_AWAY : 0 ) | 408 ( cap & 1 ? OPT_MOBILE : 0 ), 454 409 st->name, NULL ); 455 410 … … 462 417 int session, port; 463 418 464 if( num_parts !=7 )419 if( num_parts < 7 ) 465 420 { 466 421 imcb_error( ic, "Syntax error" ); … … 504 459 } 505 460 } 506 else if( strcmp( cmd[0], "ADD" ) == 0 )507 {508 if( num_parts == 6 && strcmp( cmd[2], "RL" ) == 0 )509 {510 GSList *l;511 512 http_decode( cmd[5] );513 514 if( strchr( cmd[4], '@' ) == NULL )515 {516 imcb_error( ic, "Syntax error" );517 imc_logout( ic, TRUE );518 return 0;519 }520 521 /* We got added by someone. If we don't have this522 person in permit/deny yet, inform the user. */523 for( l = ic->permit; l; l = l->next )524 if( g_strcasecmp( l->data, cmd[4] ) == 0 )525 return 1;526 527 for( l = ic->deny; l; l = l->next )528 if( g_strcasecmp( l->data, cmd[4] ) == 0 )529 return 1;530 531 msn_buddy_ask( ic, cmd[4], cmd[5] );532 }533 else if( num_parts >= 6 && strcmp( cmd[2], "FL" ) == 0 )534 {535 const char *group = NULL;536 int num;537 538 if( cmd[6] != NULL && sscanf( cmd[6], "%d", &num ) == 1 && num < md->groupcount )539 group = md->grouplist[num];540 541 http_decode( cmd[5] );542 imcb_add_buddy( ic, cmd[4], group );543 imcb_rename_buddy( ic, cmd[4], cmd[5] );544 }545 }546 461 else if( strcmp( cmd[0], "OUT" ) == 0 ) 547 462 { … … 565 480 return( 0 ); 566 481 } 482 else if( strcmp( cmd[0], "IPG" ) == 0 ) 483 { 484 imcb_error( ic, "Received IPG command, we don't handle them yet." ); 485 486 handler->msglen = atoi( cmd[1] ); 487 488 if( handler->msglen <= 0 ) 489 { 490 imcb_error( ic, "Syntax error" ); 491 imc_logout( ic, TRUE ); 492 return( 0 ); 493 } 494 } 567 495 #if 0 568 /* Discard this one completely for now since I don't care about the ack569 and since MSN servers can apparently screw up the formatting. */570 else if( strcmp( cmd[0], "REA" ) == 0 )571 {572 if( num_parts != 5 )573 {574 imcb_error( ic, "Syntax error" );575 imc_logout( ic, TRUE );576 return( 0 );577 }578 579 if( g_strcasecmp( cmd[3], ic->acc->user ) == 0 )580 {581 set_t *s;582 583 http_decode( cmd[4] );584 strncpy( ic->displayname, cmd[4], sizeof( ic->displayname ) );585 ic->displayname[sizeof(ic->displayname)-1] = 0;586 587 if( ( s = set_find( &ic->acc->set, "display_name" ) ) )588 {589 g_free( s->value );590 s->value = g_strdup( cmd[4] );591 }592 }593 else594 {595 /* This is not supposed to happen, but let's handle it anyway... */596 http_decode( cmd[4] );597 imcb_rename_buddy( ic, cmd[3], cmd[4] );598 }599 }600 #endif601 else if( strcmp( cmd[0], "IPG" ) == 0 )602 {603 imcb_error( ic, "Received IPG command, we don't handle them yet." );604 605 md->handler->msglen = atoi( cmd[1] );606 607 if( md->handler->msglen <= 0 )608 {609 imcb_error( ic, "Syntax error" );610 imc_logout( ic, TRUE );611 return( 0 );612 }613 }614 496 else if( strcmp( cmd[0], "ADG" ) == 0 ) 615 497 { … … 656 538 } 657 539 } 540 #endif 541 else if( strcmp( cmd[0], "GCF" ) == 0 ) 542 { 543 /* Coming up is cmd[2] bytes of stuff we're supposed to 544 censore. Meh. */ 545 handler->msglen = atoi( cmd[2] ); 546 } 547 else if( strcmp( cmd[0], "UBX" ) == 0 ) 548 { 549 /* Status message. */ 550 if( num_parts >= 4 ) 551 handler->msglen = atoi( cmd[3] ); 552 } 553 else if( strcmp( cmd[0], "NOT" ) == 0 ) 554 { 555 /* Some kind of notification, poorly documented but 556 apparently used to announce address book changes. */ 557 if( num_parts >= 2 ) 558 handler->msglen = atoi( cmd[1] ); 559 } 658 560 else if( isdigit( cmd[0][0] ) ) 659 561 { … … 668 570 return( 0 ); 669 571 } 572 573 /* Oh yes, errors can have payloads too now. Discard them for now. */ 574 if( num_parts >= 3 ) 575 handler->msglen = atoi( cmd[2] ); 670 576 } 671 577 else … … 677 583 } 678 584 679 static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts )680 { 681 struct im_connection *ic = data;585 static int msn_ns_message( struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts ) 586 { 587 struct im_connection *ic = handler->data; 682 588 char *body; 683 589 int blen = 0; … … 765 671 } 766 672 } 673 else if( strcmp( cmd[0], "UBX" ) == 0 ) 674 { 675 struct xt_node *psm; 676 char *psm_text = NULL; 677 678 psm = xt_from_string( msg ); 679 if( psm && strcmp( psm->name, "Data" ) == 0 && 680 ( psm = xt_find_node( psm->children, "PSM" ) ) ) 681 psm_text = psm->text; 682 683 imcb_buddy_status_msg( ic, cmd[1], psm_text ); 684 xt_free_node( psm ); 685 } 686 else if( strcmp( cmd[0], "ADL" ) == 0 ) 687 { 688 struct xt_node *adl, *d, *c; 689 690 if( !( adl = xt_from_string( msg ) ) ) 691 return 1; 692 693 for( d = adl->children; d; d = d->next ) 694 { 695 char *dn; 696 if( strcmp( d->name, "d" ) != 0 || 697 ( dn = xt_find_attr( d, "n" ) ) == NULL ) 698 continue; 699 for( c = d->children; c; c = c->next ) 700 { 701 bee_user_t *bu; 702 struct msn_buddy_data *bd; 703 char *cn, *handle, *f, *l; 704 int flags; 705 706 if( strcmp( c->name, "c" ) != 0 || 707 ( l = xt_find_attr( c, "l" ) ) == NULL || 708 ( cn = xt_find_attr( c, "n" ) ) == NULL ) 709 continue; 710 711 handle = g_strdup_printf( "%s@%s", cn, dn ); 712 if( !( ( bu = bee_user_by_handle( ic->bee, ic, handle ) ) || 713 ( bu = bee_user_new( ic->bee, ic, handle, 0 ) ) ) ) 714 { 715 g_free( handle ); 716 continue; 717 } 718 g_free( handle ); 719 bd = bu->data; 720 721 if( ( f = xt_find_attr( c, "f" ) ) ) 722 { 723 http_decode( f ); 724 imcb_rename_buddy( ic, bu->handle, f ); 725 } 726 727 flags = atoi( l ) & 15; 728 if( bd->flags != flags ) 729 { 730 bd->flags = flags; 731 msn_buddy_ask( bu ); 732 } 733 } 734 } 735 } 767 736 768 737 return( 1 ); 769 738 } 770 739 771 static void msn_auth_got_passport_token( struct msn_auth_data *mad ) 772 { 773 struct im_connection *ic = mad->data; 740 void msn_auth_got_passport_token( struct im_connection *ic, const char *token, const char *error ) 741 { 774 742 struct msn_data *md; 775 743 … … 779 747 780 748 md = ic->proto_data; 781 if( mad->token ) 782 { 783 char buf[1024]; 784 785 g_snprintf( buf, sizeof( buf ), "USR %d TWN S %s\r\n", ++md->trId, mad->token ); 786 msn_write( ic, buf, strlen( buf ) ); 749 750 if( token ) 751 { 752 msn_ns_write( ic, -1, "USR %d SSO S %s %s\r\n", ++md->trId, md->tokens[0], token ); 787 753 } 788 754 else 789 755 { 790 imcb_error( ic, "Error during Passport authentication: %s", mad->error );756 imcb_error( ic, "Error during Passport authentication: %s", error ); 791 757 imc_logout( ic, TRUE ); 792 758 } 793 759 } 794 760 795 static gboolean msn_ns_got_display_name( struct im_connection *ic, char *name ) 796 { 797 set_t *s; 798 799 if( ( s = set_find( &ic->acc->set, "display_name" ) ) == NULL ) 800 return FALSE; /* Shouldn't happen.. */ 801 802 http_decode( name ); 803 804 if( s->value && strcmp( s->value, name ) == 0 ) 805 { 806 return TRUE; 807 /* The names match, nothing to worry about. */ 808 } 809 else if( s->value != NULL && 810 ( strcmp( name, ic->acc->user ) == 0 || 811 set_getbool( &ic->acc->set, "local_display_name" ) ) ) 812 { 813 /* The server thinks our display name is our e-mail address 814 which is probably wrong, or the user *wants* us to do this: 815 Always use the locally set display_name. */ 816 return msn_set_display_name( ic, s->value ); 817 } 761 void msn_auth_got_contact_list( struct im_connection *ic ) 762 { 763 struct msn_data *md; 764 765 /* Dead connection? */ 766 if( g_slist_find( msn_connections, ic ) == NULL ) 767 return; 768 769 md = ic->proto_data; 770 msn_ns_write( ic, -1, "BLP %d %s\r\n", ++md->trId, "BL" ); 771 } 772 773 static gboolean msn_ns_send_adl_1( gpointer key, gpointer value, gpointer data ) 774 { 775 struct xt_node *adl = data, *d, *c; 776 struct bee_user *bu = value; 777 struct msn_buddy_data *bd = bu->data; 778 struct msn_data *md = bu->ic->proto_data; 779 char handle[strlen(bu->handle)]; 780 char *domain; 781 char l[4]; 782 783 if( ( bd->flags & 7 ) == 0 || ( bd->flags & MSN_BUDDY_ADL_SYNCED ) ) 784 return FALSE; 785 786 strcpy( handle, bu->handle ); 787 if( ( domain = strchr( handle, '@' ) ) == NULL ) /* WTF */ 788 return FALSE; 789 *domain = '\0'; 790 domain ++; 791 792 if( ( d = adl->children ) == NULL || 793 g_strcasecmp( xt_find_attr( d, "n" ), domain ) != 0 ) 794 { 795 d = xt_new_node( "d", NULL, NULL ); 796 xt_add_attr( d, "n", domain ); 797 xt_insert_child( adl, d ); 798 } 799 800 g_snprintf( l, sizeof( l ), "%d", bd->flags & 7 ); 801 c = xt_new_node( "c", NULL, NULL ); 802 xt_add_attr( c, "n", handle ); 803 xt_add_attr( c, "l", l ); 804 xt_add_attr( c, "t", "1" ); /* 1 means normal, 4 means mobile? */ 805 xt_insert_child( d, c ); 806 807 /* Do this in batches of 100. */ 808 bd->flags |= MSN_BUDDY_ADL_SYNCED; 809 return (--md->adl_todo % 140) == 0; 810 } 811 812 static void msn_ns_send_adl( struct im_connection *ic ) 813 { 814 struct xt_node *adl; 815 struct msn_data *md = ic->proto_data; 816 char *adls; 817 818 adl = xt_new_node( "ml", NULL, NULL ); 819 xt_add_attr( adl, "l", "1" ); 820 g_tree_foreach( md->domaintree, msn_ns_send_adl_1, adl ); 821 if( adl->children == NULL ) 822 { 823 /* This tells the caller that we're done now. */ 824 md->adl_todo = -1; 825 xt_free_node( adl ); 826 return; 827 } 828 829 adls = xt_to_string( adl ); 830 msn_ns_write( ic, -1, "ADL %d %zd\r\n%s", ++md->trId, strlen( adls ), adls ); 831 g_free( adls ); 832 } 833 834 static void msn_ns_send_adl_start( struct im_connection *ic ) 835 { 836 struct msn_data *md; 837 GSList *l; 838 839 /* Dead connection? */ 840 if( g_slist_find( msn_connections, ic ) == NULL ) 841 return; 842 843 md = ic->proto_data; 844 md->adl_todo = 0; 845 for( l = ic->bee->users; l; l = l->next ) 846 { 847 bee_user_t *bu = l->data; 848 struct msn_buddy_data *bd = bu->data; 849 850 if( bu->ic != ic || ( bd->flags & 7 ) == 0 ) 851 continue; 852 853 bd->flags &= ~MSN_BUDDY_ADL_SYNCED; 854 md->adl_todo++; 855 } 856 857 msn_ns_send_adl( ic ); 858 } 859 860 int msn_ns_finish_login( struct im_connection *ic ) 861 { 862 struct msn_data *md = ic->proto_data; 863 864 if( ic->flags & OPT_LOGGED_IN ) 865 return 1; 866 867 if( md->adl_todo < 0 ) 868 md->flags |= MSN_DONE_ADL; 869 870 if( ( md->flags & MSN_DONE_ADL ) && ( md->flags & MSN_GOT_PROFILE ) ) 871 return msn_ns_set_display_name( ic, set_getstr( &ic->acc->set, "display_name" ) ); 818 872 else 819 { 820 if( s->value && *s->value ) 821 imcb_log( ic, "BitlBee thinks your display name is `%s' but " 822 "the MSN server says it's `%s'. Using the MSN " 823 "server's name. Set local_display_name to true " 824 "to use the local name.", s->value, name ); 825 826 if( g_utf8_validate( name, -1, NULL ) ) 827 { 828 g_free( s->value ); 829 s->value = g_strdup( name ); 830 } 831 else 832 { 833 imcb_log( ic, "Warning: Friendly name in server response was corrupted" ); 834 } 835 836 return TRUE; 837 } 838 } 873 return 1; 874 } -
protocols/msn/sb.c
r05bf2a0 r62f53b50 2 2 * BitlBee -- An IRC to other IM-networks gateway * 3 3 * * 4 * Copyright 2002-20 05Wilmer van der Gaast and others *4 * Copyright 2002-2010 Wilmer van der Gaast and others * 5 5 \********************************************************************/ 6 6 … … 27 27 #include "nogaim.h" 28 28 #include "msn.h" 29 #include "passport.h"30 29 #include "md5.h" 30 #include "soap.h" 31 31 #include "invitation.h" 32 32 33 33 static gboolean msn_sb_callback( gpointer data, gint source, b_input_condition cond ); 34 static int msn_sb_command( gpointer data, char **cmd, int num_parts ); 35 static int msn_sb_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts ); 36 37 int msn_sb_write( struct msn_switchboard *sb, char *s, int len ) 38 { 34 static int msn_sb_command( struct msn_handler_data *handler, char **cmd, int num_parts ); 35 static int msn_sb_message( struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts ); 36 37 int msn_sb_write( struct msn_switchboard *sb, const char *fmt, ... ) 38 { 39 va_list params; 40 char *out; 41 size_t len; 39 42 int st; 40 43 41 st = write( sb->fd, s, len ); 44 va_start( params, fmt ); 45 out = g_strdup_vprintf( fmt, params ); 46 va_end( params ); 47 48 if( getenv( "BITLBEE_DEBUG" ) ) 49 fprintf( stderr, "->SB%d:%s", sb->fd, out ); 50 51 len = strlen( out ); 52 st = write( sb->fd, out, len ); 53 g_free( out ); 42 54 if( st != len ) 43 55 { 44 56 msn_sb_destroy( sb ); 45 return ( 0 );46 } 47 48 return ( 1 );57 return 0; 58 } 59 60 return 1; 49 61 } 50 62 … … 53 65 struct msn_data *md = ic->proto_data; 54 66 struct msn_switchboard *sb; 55 char buf[1024];56 67 57 68 /* FIXME: *CHECK* the reliability of using spare sb's! */ … … 61 72 62 73 sb->who = g_strdup( m->who ); 63 g_snprintf( buf, sizeof( buf ), "CAL %d %s\r\n", ++sb->trId, m->who ); 64 if( msn_sb_write( sb, buf, strlen( buf ) ) ) 74 if( msn_sb_write( sb, "CAL %d %s\r\n", ++sb->trId, m->who ) ) 65 75 { 66 76 /* He/She should join the switchboard soon, let's queue the message. */ … … 73 83 74 84 /* If we reach this line, there was no spare switchboard, so let's make one. */ 75 g_snprintf( buf, sizeof( buf ), "XFR %d SB\r\n", ++md->trId ); 76 if( !msn_write( ic, buf, strlen( buf ) ) ) 85 if( !msn_ns_write( ic, -1, "XFR %d SB\r\n", ++md->trId ) ) 77 86 { 78 87 g_free( m->who ); … … 165 174 if( sb->ready ) 166 175 { 167 char * packet, *buf;176 char *buf; 168 177 int i, j; 169 178 … … 201 210 202 211 /* Build the final packet (MSG command + the message). */ 203 packet = g_strdup_printf( "MSG %d N %d\r\n%s", ++sb->trId, i, buf ); 204 g_free( buf ); 205 if( msn_sb_write( sb, packet, strlen( packet ) ) ) 206 { 207 g_free( packet ); 208 return( 1 ); 212 if( msn_sb_write( sb, "MSG %d N %d\r\n%s", ++sb->trId, i, buf ) ) 213 { 214 g_free( buf ); 215 return 1; 209 216 } 210 217 else 211 218 { 212 g_free( packet);213 return ( 0 );219 g_free( buf ); 220 return 0; 214 221 } 215 222 } … … 326 333 g_snprintf( buf, sizeof( buf ), "ANS %d %s %s %d\r\n", ++sb->trId, ic->acc->user, sb->key, sb->session ); 327 334 328 if( msn_sb_write( sb, buf, strlen( buf )) )335 if( msn_sb_write( sb, "%s", buf ) ) 329 336 sb->inp = b_input_add( sb->fd, B_EV_IO_READ, msn_sb_callback, sb ); 330 337 else … … 346 353 { 347 354 time_t now = time( NULL ); 348 char buf[1024];349 355 350 356 if( now - md->first_sb_failure > 600 ) … … 378 384 debug( "Moved queued messages back to the main queue, " 379 385 "creating a new switchboard to retry." ); 380 g_snprintf( buf, sizeof( buf ), "XFR %d SB\r\n", ++md->trId ); 381 if( !msn_write( ic, buf, strlen( buf ) ) ) 386 if( !msn_ns_write( ic, -1, "XFR %d SB\r\n", ++md->trId ) ) 382 387 return FALSE; 383 388 } … … 387 392 } 388 393 389 static int msn_sb_command( gpointer data, char **cmd, int num_parts )390 { 391 struct msn_switchboard *sb = data;394 static int msn_sb_command( struct msn_handler_data *handler, char **cmd, int num_parts ) 395 { 396 struct msn_switchboard *sb = handler->data; 392 397 struct im_connection *ic = sb->ic; 393 char buf[1024];394 398 395 399 if( !num_parts ) … … 407 411 else if( strcmp( cmd[0], "USR" ) == 0 ) 408 412 { 409 if( num_parts !=5 )413 if( num_parts < 5 ) 410 414 { 411 415 msn_sb_destroy( sb ); … … 420 424 421 425 if( sb->who ) 422 { 423 g_snprintf( buf, sizeof( buf ), "CAL %d %s\r\n", ++sb->trId, sb->who ); 424 return( msn_sb_write( sb, buf, strlen( buf ) ) ); 425 } 426 return msn_sb_write( sb, "CAL %d %s\r\n", ++sb->trId, sb->who ); 426 427 else 427 {428 428 debug( "Just created a switchboard, but I don't know what to do with it." ); 429 }430 429 } 431 430 else if( strcmp( cmd[0], "IRO" ) == 0 ) … … 433 432 int num, tot; 434 433 435 if( num_parts !=6 )434 if( num_parts < 6 ) 436 435 { 437 436 msn_sb_destroy( sb ); … … 470 469 else if( strcmp( cmd[0], "ANS" ) == 0 ) 471 470 { 472 if( num_parts !=3 )471 if( num_parts < 3 ) 473 472 { 474 473 msn_sb_destroy( sb ); … … 489 488 else if( strcmp( cmd[0], "CAL" ) == 0 ) 490 489 { 491 if( num_parts !=4 || !isdigit( cmd[3][0] ) )490 if( num_parts < 4 || !isdigit( cmd[3][0] ) ) 492 491 { 493 492 msn_sb_destroy( sb ); … … 499 498 else if( strcmp( cmd[0], "JOI" ) == 0 ) 500 499 { 501 if( num_parts !=3 )500 if( num_parts < 3 ) 502 501 { 503 502 msn_sb_destroy( sb ); … … 560 559 else if( strcmp( cmd[0], "MSG" ) == 0 ) 561 560 { 562 if( num_parts !=4 )561 if( num_parts < 4 ) 563 562 { 564 563 msn_sb_destroy( sb ); … … 625 624 const struct msn_status_code *err = msn_status_by_number( num ); 626 625 627 imcb_error( ic, "Error reported by switchboard server: %s", err->text ); 626 /* If the person is offline, send an offline message instead, 627 and don't report an error. */ 628 if( num == 217 ) 629 msn_soap_oim_send_queue( ic, &sb->msgq ); 630 else 631 imcb_error( ic, "Error reported by switchboard server: %s", err->text ); 628 632 629 633 if( err->flags & STATUS_SB_FATAL ) … … 661 665 } 662 666 663 static int msn_sb_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts )664 { 665 struct msn_switchboard *sb = data;667 static int msn_sb_message( struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts ) 668 { 669 struct msn_switchboard *sb = handler->data; 666 670 struct im_connection *ic = sb->ic; 667 671 char *body; … … 741 745 else if( g_strncasecmp( ct, "application/x-msnmsgrp2p", 24 ) == 0 ) 742 746 { 743 imcb_error( sb->ic, "Cannot receive file from %s: BitlBee does not "744 "support msnmsgrp2p yet.", sb->who );747 /* Not currently implemented. Don't warn about it since 748 this seems to be used for avatars now. */ 745 749 g_free( ct ); 746 750 } -
protocols/msn/tables.c
r05bf2a0 r62f53b50 2 2 * BitlBee -- An IRC to other IM-networks gateway * 3 3 * * 4 * Copyright 2002-20 04Wilmer van der Gaast and others *4 * Copyright 2002-2010 Wilmer van der Gaast and others * 5 5 \********************************************************************/ 6 6 … … 83 83 { 230, "Cannot remove that group", 0 }, 84 84 { 231, "Invalid group", 0 }, 85 { 240, "ADL/RML command with corrupted payload", STATUS_FATAL }, 86 { 241, "ADL/RML command with invalid modification", 0 }, 85 87 { 280, "Switchboard failed", STATUS_SB_FATAL }, 86 88 { 281, "Transfer to switchboard failed", 0 }, -
protocols/nogaim.c
r05bf2a0 r62f53b50 252 252 serv_got_crap( ic, "Error: %s", text ); 253 253 else 254 serv_got_crap( ic, " Couldn't log in: %s", text );254 serv_got_crap( ic, "Login error: %s", text ); 255 255 256 256 g_free( text ); … … 325 325 326 326 imcb_log( ic, "Signing off.." ); 327 328 b_event_remove( ic->keepalive );329 ic->keepalive = 0;330 ic->acc->prpl->logout( ic );331 b_event_remove( ic->inpa );332 333 g_free( ic->away );334 ic->away = NULL;335 327 336 328 for( l = bee->users; l; ) … … 344 336 l = next; 345 337 } 338 339 b_event_remove( ic->keepalive ); 340 ic->keepalive = 0; 341 ic->acc->prpl->logout( ic ); 342 b_event_remove( ic->inpa ); 343 344 g_free( ic->away ); 345 ic->away = NULL; 346 346 347 347 query_del_by_conn( (irc_t*) ic->bee->ui_data, ic ); -
protocols/nogaim.h
r05bf2a0 r62f53b50 195 195 this info via imcb_log(). Implementing these are optional. */ 196 196 void (* get_info) (struct im_connection *, char *who); 197 /* set_my_name is *DEPRECATED*, not used by the UI anymore. Use the 198 display_name setting instead. */ 197 199 void (* set_my_name) (struct im_connection *, char *name); 198 200 void (* set_name) (struct im_connection *, char *who, char *name); -
storage_xml.c
r05bf2a0 r62f53b50 320 320 else if( g_strcasecmp( g_markup_parse_context_get_element( ctx ), "setting" ) == 0 && xd->current_setting ) 321 321 { 322 if( xd->current_account ) 323 { 324 set_t *s = set_find( xd->current_set_head, xd->current_setting ); 325 if( s && ( s->flags & ACC_SET_ONLINE_ONLY ) ) 326 { 327 g_free( xd->current_setting ); 328 xd->current_setting = NULL; 329 return; 330 } 331 } 322 332 set_setstr( xd->current_set_head, xd->current_setting, (char*) text ); 323 333 g_free( xd->current_setting );
Note: See TracChangeset
for help on using the changeset viewer.