Changes in / [b0a89cc:feb1bad]
- Files:
-
- 4 added
- 2 deleted
- 23 edited
Legend:
- Unmodified
- Added
- Removed
-
configure
rb0a89cc rfeb1bad 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
rb0a89cc rfeb1bad 4 4 http://bugs.bitlbee.org/bitlbee/timeline?daysback=90&changeset=on 5 5 6 Version 1.3dev:6 Version ... 7 7 - For the first time since 2007, a dev snapshot. Like then, this is pretty 8 8 stable already (running on testing.bitlbee.org for weeks by now), but not … … 52 52 for a list of supported protocols (works only in libpurple-enabled 53 53 binaries). 54 - Rewritten MSN module, implementing MSNP15 instead of the old MSNP8: 55 * MSNP8 support from MSN was getting pretty unreliable. There were issues 56 with remembering display names and adding contacts/auth requests. 57 * Support for sending offline messages. 58 * Support for setting and reading status messages. 54 59 - Support for file transfers, in and out. /DCC SEND a file to a contact and 55 60 it becomes a file transfer, and incoming file transfers become /DCC SENDs … … 59 64 fixes issues with authorization requests. 60 65 61 Finished 6 Aug 201066 Finished ... 62 67 63 68 Version 1.2.8: -
lib/Makefile
rb0a89cc rfeb1bad 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
rb0a89cc rfeb1bad 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
rb0a89cc rfeb1bad 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
rb0a89cc rfeb1bad 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
rb0a89cc rfeb1bad 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
rb0a89cc rfeb1bad 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
rb0a89cc rfeb1bad 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
rb0a89cc rfeb1bad 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
rb0a89cc rfeb1bad 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
rb0a89cc rfeb1bad 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
rb0a89cc rfeb1bad 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
rb0a89cc rfeb1bad 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
rb0a89cc rfeb1bad 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 … … 68 74 md->ic = ic; 69 75 md->away_state = msn_away_state_list; 76 md->domaintree = g_tree_new( msn_domaintree_cmp ); 70 77 71 78 msn_connections = g_slist_append( msn_connections, ic ); … … 76 83 struct msn_data *md = ic->proto_data; 77 84 GSList *l; 85 int i; 78 86 79 87 if( md ) … … 100 108 msn_msgq_purge( ic, &md->msgq ); 101 109 102 while( md->groupcount > 0 ) 103 g_free( md->grouplist[--md->groupcount] ); 104 g_free( md->grouplist ); 110 for( i = 0; i < sizeof( md->tokens ) / sizeof( md->tokens[0] ); i ++ ) 111 g_free( md->tokens[i] ); 112 g_free( md->lock_key ); 113 114 while( md->groups ) 115 { 116 struct msn_group *mg = md->groups->data; 117 g_free( mg->id ); 118 g_free( mg->name ); 119 g_free( mg ); 120 md->groups = g_slist_remove( md->groups, mg ); 121 } 122 123 g_tree_destroy( md->domaintree ); 124 md->domaintree = NULL; 105 125 106 126 while( md->grpq ) … … 174 194 { 175 195 char buf[1024]; 196 char *uux; 176 197 struct msn_data *md = ic->proto_data; 177 198 … … 182 203 183 204 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 ); 205 if( !msn_write( ic, buf, strlen( buf ) ) ) 206 return; 207 208 uux = g_markup_printf_escaped( "<Data><PSM>%s</PSM><CurrentMedia></CurrentMedia>" 209 "</Data>", message ? message : "" ); 210 g_snprintf( buf, sizeof( buf ), "UUX %d %zd\r\n%s", ++md->trId, strlen( uux ), uux ); 211 if( !msn_write( ic, buf, strlen( buf ) ) ) 212 return; 190 213 } 191 214 … … 200 223 struct bee_user *bu = bee_user_by_handle( ic->bee, ic, who ); 201 224 202 msn_buddy_list_add( ic, "FL", who, who, group );225 msn_buddy_list_add( ic, MSN_BUDDY_FL, who, who, group ); 203 226 if( bu && bu->group ) 204 msn_buddy_list_remove( ic, "FL", who, bu->group->name );227 msn_buddy_list_remove( ic, MSN_BUDDY_FL, who, bu->group->name ); 205 228 } 206 229 207 230 static void msn_remove_buddy( struct im_connection *ic, char *who, char *group ) 208 231 { 209 msn_buddy_list_remove( ic, "FL", who, NULL );232 msn_buddy_list_remove( ic, MSN_BUDDY_FL, who, NULL ); 210 233 } 211 234 … … 272 295 static void msn_add_permit( struct im_connection *ic, char *who ) 273 296 { 274 msn_buddy_list_add( ic, "AL", who, who, NULL );297 msn_buddy_list_add( ic, MSN_BUDDY_AL, who, who, NULL ); 275 298 } 276 299 277 300 static void msn_rem_permit( struct im_connection *ic, char *who ) 278 301 { 279 msn_buddy_list_remove( ic, "AL", who, NULL );302 msn_buddy_list_remove( ic, MSN_BUDDY_AL, who, NULL ); 280 303 } 281 304 … … 284 307 struct msn_switchboard *sb; 285 308 286 msn_buddy_list_add( ic, "BL", who, who, NULL );309 msn_buddy_list_add( ic, MSN_BUDDY_BL, who, who, NULL ); 287 310 288 311 /* If there's still a conversation with this person, close it. */ … … 295 318 static void msn_rem_deny( struct im_connection *ic, char *who ) 296 319 { 297 msn_buddy_list_remove( ic, "BL", who, NULL );320 msn_buddy_list_remove( ic, MSN_BUDDY_BL, who, NULL ); 298 321 } 299 322 … … 314 337 account_t *acc = set->data; 315 338 struct im_connection *ic = acc->ic; 316 317 /* Allow any name if we're offline. */ 318 if( ic == NULL ) 319 return value; 339 struct msn_data *md = ic->proto_data; 320 340 321 341 if( strlen( value ) > 129 ) … … 325 345 } 326 346 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; 347 if( md->flags & MSN_GOT_PROFILE_DN ) 348 imcb_log( ic, "Warning: Persistent name changes for this account have to be done " 349 "in the profile. BitlBee doesn't currently support this." ); 350 351 msn_soap_addressbook_set_display_name( ic, value ); 352 return msn_ns_set_display_name( ic, value ) ? value : NULL; 353 } 354 355 static void msn_buddy_data_add( bee_user_t *bu ) 356 { 357 struct msn_data *md = bu->ic->proto_data; 358 bu->data = g_new0( struct msn_buddy_data, 1 ); 359 g_tree_insert( md->domaintree, bu->handle, bu ); 360 } 361 362 static void msn_buddy_data_free( bee_user_t *bu ) 363 { 364 struct msn_data *md = bu->ic->proto_data; 365 g_tree_remove( md->domaintree, bu->handle ); 366 g_free( bu->data ); 331 367 } 332 368 … … 343 379 ret->set_away = msn_set_away; 344 380 ret->get_info = msn_get_info; 345 ret->set_my_name = msn_set_my_name;346 381 ret->add_buddy = msn_add_buddy; 347 382 ret->remove_buddy = msn_remove_buddy; … … 357 392 ret->send_typing = msn_send_typing; 358 393 ret->handle_cmp = g_strcasecmp; 394 ret->buddy_data_add = msn_buddy_data_add; 395 ret->buddy_data_free = msn_buddy_data_free; 396 359 397 //ret->transfer_request = msn_ftp_transfer_request; 360 398 -
protocols/msn/msn.h
rb0a89cc rfeb1bad 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 /* Some other version. 47 #define MSNP11_PROD_KEY "O4BG@C7BWLYQX?5G" 48 #define MSNP11_PROD_ID "PROD01065C%ZFN6F" 49 */ 50 51 #define MSNP11_PROD_KEY "ILTXC!4IXB5FB*PX" 52 #define MSNP11_PROD_ID "PROD0119GSJUC$18" 53 #define MSNP_VER "MSNP15" 54 #define MSNP_BUILD "8.5.1288" 43 55 44 56 #define MSN_SB_NEW -24062002 … … 61 73 #define PROFILE_URL "http://members.msn.com/" 62 74 75 typedef enum 76 { 77 MSN_GOT_PROFILE = 1, 78 MSN_GOT_PROFILE_DN = 2, 79 MSN_DONE_ADL = 4, 80 } msn_flags_t; 81 63 82 struct msn_data 64 83 { … … 67 86 int fd; 68 87 struct msn_handler_data *handler; 88 msn_flags_t flags; 69 89 70 90 int trId; 91 char *tokens[4]; 92 char *lock_key; 71 93 72 94 GSList *msgq, *grpq; … … 74 96 int sb_failures; 75 97 time_t first_sb_failure; 76 GSList *filetransfers;77 98 78 99 const struct msn_away_state *away_state; 79 int buddycount; 80 int groupcount; 81 char **grouplist; 100 GSList *groups; 101 102 /* Mostly used for sending the ADL command; since MSNP13 the client 103 is responsible for downloading the contact list and then sending 104 it to the MSNP server. */ 105 GTree *domaintree; 106 int adl_todo; 82 107 }; 83 108 … … 140 165 int (*exec_command) ( gpointer data, char **cmd, int count ); 141 166 int (*exec_message) ( gpointer data, char *msg, int msglen, char **cmd, int count ); 167 }; 168 169 typedef enum 170 { 171 MSN_BUDDY_FL = 1, /* Warning: FL,AL,BL *must* be 1,2,4. */ 172 MSN_BUDDY_AL = 2, 173 MSN_BUDDY_BL = 4, 174 MSN_BUDDY_RL = 8, 175 MSN_BUDDY_PL = 16, 176 MSN_BUDDY_ADL_SYNCED = 256, 177 } msn_buddy_flags_t; 178 179 struct msn_buddy_data 180 { 181 char *cid; 182 msn_buddy_flags_t flags; 183 }; 184 185 struct msn_group 186 { 187 char *name; 188 char *id; 142 189 }; 143 190 … … 162 209 /* ns.c */ 163 210 gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ); 211 void msn_auth_got_passport_token( struct im_connection *ic, const char *token, const char *error ); 212 void msn_auth_got_contact_list( struct im_connection *ic ); 213 int msn_ns_finish_login( struct im_connection *ic ); 164 214 165 215 /* msn_util.c */ 166 216 int msn_write( struct im_connection *ic, char *s, int len ); 167 217 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);218 int msn_buddy_list_add( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *realname_, const char *group ); 219 int msn_buddy_list_remove( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group ); 220 void msn_buddy_ask( bee_user_t *bu ); 171 221 char *msn_findheader( char *text, char *header, int len ); 172 222 char **msn_linesplit( char *line ); 173 223 int msn_handler( struct msn_handler_data *h ); 174 char *msn_http_encode( const char *input );175 224 void msn_msgq_purge( struct im_connection *ic, GSList **list ); 176 gboolean msn_set_display_name( struct im_connection *ic, const char *rawname ); 225 char *msn_p11_challenge( char *challenge ); 226 gint msn_domaintree_cmp( gconstpointer a_, gconstpointer b_ ); 227 struct msn_group *msn_group_by_name( struct im_connection *ic, const char *name ); 228 struct msn_group *msn_group_by_id( struct im_connection *ic, const char *id ); 229 int msn_ns_set_display_name( struct im_connection *ic, const char *value ); 177 230 178 231 /* tables.c */ … … 196 249 void msn_sb_stop_keepalives( struct msn_switchboard *sb ); 197 250 198 /* invitation.c */199 void msn_ftp_transfer_request( struct im_connection *ic, file_transfer_t *ft, char *who );200 201 251 #endif //_MSN_H -
protocols/msn/msn_util.c
rb0a89cc rfeb1bad 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 … … 32 34 struct msn_data *md = ic->proto_data; 33 35 int st; 36 37 if( getenv( "BITLBEE_DEBUG" ) ) 38 { 39 write( 2, "->NS:", 5 ); 40 write( 2, s, len ); 41 } 34 42 35 43 st = write( md->fd, s, len ); … … 51 59 } 52 60 53 int msn_buddy_list_add( struct im_connection *ic, const char *list, const char *who, const char *realname_, const char *group ) 61 static char *adlrml_entry( const char *handle_, msn_buddy_flags_t list ) 62 { 63 char *domain, handle[strlen(handle_)+1]; 64 65 strcpy( handle, handle_ ); 66 if( ( domain = strchr( handle, '@' ) ) ) 67 *(domain++) = '\0'; 68 else 69 return NULL; 70 71 return g_markup_printf_escaped( "<ml><d n=\"%s\"><c n=\"%s\" l=\"%d\" t=\"1\"/></d></ml>", 72 domain, handle, list ); 73 } 74 75 int msn_buddy_list_add( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *realname, const char *group ) 54 76 { 55 77 struct msn_data *md = ic->proto_data; 56 char buf[1024], *realname, groupid[8]; 78 char buf[1024], groupid[8]; 79 bee_user_t *bu; 80 struct msn_buddy_data *bd; 81 char *adl; 57 82 58 83 *groupid = '\0'; 84 #if 0 59 85 if( group ) 60 86 { … … 87 113 if( l == NULL ) 88 114 { 89 char *groupname = msn_http_encode( group ); 115 char groupname[strlen(group)+1]; 116 strcpy( groupname, group ); 117 http_encode( groupname ); 90 118 g_snprintf( buf, sizeof( buf ), "ADG %d %s %d\r\n", ++md->trId, groupname, 0 ); 91 g_free( groupname );92 119 return msn_write( ic, buf, strlen( buf ) ); 93 120 } … … 101 128 } 102 129 } 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 ) 130 #endif 131 132 if( !( ( bu = bee_user_by_handle( ic->bee, ic, who ) ) || 133 ( bu = bee_user_new( ic->bee, ic, who, 0 ) ) ) || 134 !( bd = bu->data ) || bd->flags & list ) 135 return 1; 136 137 bd->flags |= list; 138 139 if( list == MSN_BUDDY_FL ) 140 msn_soap_ab_contact_add( ic, bu ); 141 else 142 msn_soap_memlist_edit( ic, who, TRUE, list ); 143 144 if( ( adl = adlrml_entry( who, list ) ) ) 145 { 146 g_snprintf( buf, sizeof( buf ), "ADL %d %zd\r\n%s", 147 ++md->trId, strlen( adl ), adl ); 148 g_free( adl ); 149 150 return msn_write( ic, buf, strlen( buf ) ); 151 } 152 153 return 1; 154 } 155 156 int msn_buddy_list_remove( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group ) 112 157 { 113 158 struct msn_data *md = ic->proto_data; 114 159 char buf[1024], groupid[8]; 160 bee_user_t *bu; 161 struct msn_buddy_data *bd; 162 char *adl; 115 163 116 164 *groupid = '\0'; 165 #if 0 117 166 if( group ) 118 167 { … … 125 174 } 126 175 } 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 ); 176 #endif 177 178 if( !( bu = bee_user_by_handle( ic->bee, ic, who ) ) || 179 !( bd = bu->data ) || !( bd->flags & list ) ) 180 return 1; 181 182 bd->flags &= ~list; 183 184 if( list == MSN_BUDDY_FL ) 185 msn_soap_ab_contact_del( ic, bu ); 186 else 187 msn_soap_memlist_edit( ic, who, FALSE, list ); 188 189 if( ( adl = adlrml_entry( who, list ) ) ) 190 { 191 g_snprintf( buf, sizeof( buf ), "RML %d %zd\r\n%s", 192 ++md->trId, strlen( adl ), adl ); 193 g_free( adl ); 194 195 return msn_write( ic, buf, strlen( buf ) ); 196 } 197 198 return 1; 133 199 } 134 200 … … 144 210 struct msn_buddy_ask_data *bla = data; 145 211 146 msn_buddy_list_add( bla->ic, "AL", bla->handle, bla->realname, NULL );212 msn_buddy_list_add( bla->ic, MSN_BUDDY_AL, bla->handle, bla->realname, NULL ); 147 213 148 214 imcb_ask_add( bla->ic, bla->handle, NULL ); … … 157 223 struct msn_buddy_ask_data *bla = data; 158 224 159 msn_buddy_list_add( bla->ic, "BL", bla->handle, bla->realname, NULL );225 msn_buddy_list_add( bla->ic, MSN_BUDDY_BL, bla->handle, bla->realname, NULL ); 160 226 161 227 g_free( bla->handle ); … … 164 230 } 165 231 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 ); 232 void msn_buddy_ask( bee_user_t *bu ) 233 { 234 struct msn_buddy_ask_data *bla; 235 struct msn_buddy_data *bd = bu->data; 169 236 char buf[1024]; 170 237 171 bla->ic = ic; 172 bla->handle = g_strdup( handle ); 173 bla->realname = g_strdup( realname ); 238 if( ( bd->flags & 30 ) != 8 && ( bd->flags & 30 ) != 16 ) 239 return; 240 241 bla = g_new0( struct msn_buddy_ask_data, 1 ); 242 bla->ic = bu->ic; 243 bla->handle = g_strdup( bu->handle ); 244 bla->realname = g_strdup( bu->fullname ); 174 245 175 246 g_snprintf( buf, sizeof( buf ), 176 247 "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 );248 bu->handle, bu->fullname ); 249 imcb_ask( bu->ic, buf, bla, msn_buddy_ask_yes, msn_buddy_ask_no ); 179 250 } 180 251 … … 279 350 if( st <= 0 ) 280 351 return( -1 ); 352 353 if( getenv( "BITLBEE_DEBUG" ) ) 354 { 355 write( 2, "->C:", 4 ); 356 write( 2, h->rxq + h->rxlen - st, st ); 357 } 281 358 282 359 while( st ) … … 367 444 } 368 445 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 446 void msn_msgq_purge( struct im_connection *ic, GSList **list ) 396 447 { … … 433 484 } 434 485 435 gboolean msn_set_display_name( struct im_connection *ic, const char *rawname ) 436 { 437 char *fn = msn_http_encode( rawname ); 486 /* Copied and heavily modified from http://tmsnc.sourceforge.net/chl.c */ 487 char *msn_p11_challenge( char *challenge ) 488 { 489 char *output, buf[256]; 490 md5_state_t md5c; 491 unsigned char md5Hash[16], *newHash; 492 unsigned int *md5Parts, *chlStringParts, newHashParts[5]; 493 long long nHigh = 0, nLow = 0; 494 int i, n; 495 496 /* Create the MD5 hash */ 497 md5_init(&md5c); 498 md5_append(&md5c, (unsigned char*) challenge, strlen(challenge)); 499 md5_append(&md5c, (unsigned char*) MSNP11_PROD_KEY, strlen(MSNP11_PROD_KEY)); 500 md5_finish(&md5c, md5Hash); 501 502 /* Split it into four integers */ 503 md5Parts = (unsigned int *)md5Hash; 504 for (i = 0; i < 4; i ++) 505 { 506 md5Parts[i] = GUINT32_TO_LE(md5Parts[i]); 507 508 /* & each integer with 0x7FFFFFFF */ 509 /* and save one unmodified array for later */ 510 newHashParts[i] = md5Parts[i]; 511 md5Parts[i] &= 0x7FFFFFFF; 512 } 513 514 /* make a new string and pad with '0' */ 515 n = g_snprintf(buf, sizeof(buf)-5, "%s%s00000000", challenge, MSNP11_PROD_ID); 516 /* truncate at an 8-byte boundary */ 517 buf[n&=~7] = '\0'; 518 519 /* split into integers */ 520 chlStringParts = (unsigned int *)buf; 521 522 /* this is magic */ 523 for (i = 0; i < (n / 4) - 1; i += 2) 524 { 525 long long temp; 526 527 chlStringParts[i] = GUINT32_TO_LE(chlStringParts[i]); 528 chlStringParts[i+1] = GUINT32_TO_LE(chlStringParts[i+1]); 529 530 temp = (md5Parts[0] * (((0x0E79A9C1 * (long long)chlStringParts[i]) % 0x7FFFFFFF)+nHigh) + md5Parts[1])%0x7FFFFFFF; 531 nHigh = (md5Parts[2] * (((long long)chlStringParts[i+1]+temp) % 0x7FFFFFFF) + md5Parts[3]) % 0x7FFFFFFF; 532 nLow = nLow + nHigh + temp; 533 } 534 nHigh = (nHigh+md5Parts[1]) % 0x7FFFFFFF; 535 nLow = (nLow+md5Parts[3]) % 0x7FFFFFFF; 536 537 newHashParts[0] ^= nHigh; 538 newHashParts[1] ^= nLow; 539 newHashParts[2] ^= nHigh; 540 newHashParts[3] ^= nLow; 541 542 /* swap more bytes if big endian */ 543 for (i = 0; i < 4; i ++) 544 newHashParts[i] = GUINT32_TO_LE(newHashParts[i]); 545 546 /* make a string of the parts */ 547 newHash = (unsigned char *)newHashParts; 548 549 /* convert to hexadecimal */ 550 output = g_new(char, 33); 551 for (i = 0; i < 16; i ++) 552 sprintf(output + i * 2, "%02x", newHash[i]); 553 554 return output; 555 } 556 557 gint msn_domaintree_cmp( gconstpointer a_, gconstpointer b_ ) 558 { 559 const char *a = a_, *b = b_; 560 gint ret; 561 562 if( !( a = strchr( a, '@' ) ) || !( b = strchr( b, '@' ) ) || 563 ( ret = strcmp( a, b ) ) == 0 ) 564 ret = strcmp( a_, b_ ); 565 566 return ret; 567 } 568 569 struct msn_group *msn_group_by_name( struct im_connection *ic, const char *name ) 570 { 438 571 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 } 572 GSList *l; 573 574 for( l = md->groups; l; l = l->next ) 575 { 576 struct msn_group *mg = l->data; 577 578 if( g_strcasecmp( mg->name, name ) == 0 ) 579 return mg; 580 } 581 582 return NULL; 583 } 584 585 struct msn_group *msn_group_by_id( struct im_connection *ic, const char *id ) 586 { 587 struct msn_data *md = ic->proto_data; 588 GSList *l; 589 590 for( l = md->groups; l; l = l->next ) 591 { 592 struct msn_group *mg = l->data; 593 594 if( g_strcasecmp( mg->id, id ) == 0 ) 595 return mg; 596 } 597 598 return NULL; 599 } 600 601 int msn_ns_set_display_name( struct im_connection *ic, const char *value ) 602 { 603 struct msn_data *md = ic->proto_data; 604 char fn[strlen(value)*3+1]; 605 char buf[512]; 606 607 strcpy( fn, value ); 608 http_encode( fn ); 609 g_snprintf( buf, sizeof( buf ), "PRP %d MFN %s\r\n", 610 ++md->trId, fn ); 611 612 /* Note: We don't actually know if the server accepted the new name, 613 and won't give proper feedback yet if it doesn't. */ 614 return msn_write( ic, buf, strlen( buf ) ); 615 } -
protocols/msn/ns.c
rb0a89cc rfeb1bad 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" 30 #include "soap.h" 31 #include "xmltree.h" 31 32 32 33 static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition cond ); … … 34 35 static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts ); 35 36 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);37 static void msn_ns_send_adl_start( struct im_connection *ic ); 38 static void msn_ns_send_adl( struct im_connection *ic ); 38 39 39 40 gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ) … … 73 74 md->handler->rxq = g_new0( char, 1 ); 74 75 75 g_snprintf( s, sizeof( s ), "VER %d MSNP8 CVR0\r\n", ++md->trId);76 g_snprintf( s, sizeof( s ), "VER %d %s CVR0\r\n", ++md->trId, MSNP_VER ); 76 77 if( msn_write( ic, s, strlen( s ) ) ) 77 78 { … … 113 114 if( strcmp( cmd[0], "VER" ) == 0 ) 114 115 { 115 if( cmd[2] && strncmp( cmd[2], "MSNP8", 5 ) != 0 )116 if( cmd[2] && strncmp( cmd[2], MSNP_VER, 5 ) != 0 ) 116 117 { 117 118 imcb_error( ic, "Unsupported protocol" ); … … 127 128 { 128 129 /* We don't give a damn about the information we just received */ 129 g_snprintf( buf, sizeof( buf ), "USR %d TWNI %s\r\n", ++md->trId, ic->acc->user );130 g_snprintf( buf, sizeof( buf ), "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user ); 130 131 return( msn_write( ic, buf, strlen( buf ) ) ); 131 132 } … … 135 136 int port; 136 137 137 if( num_parts == 6 && strcmp( cmd[2], "NS" ) == 0 )138 if( num_parts >= 6 && strcmp( cmd[2], "NS" ) == 0 ) 138 139 { 139 140 b_event_remove( ic->inpa ); … … 156 157 md->fd = proxy_connect( server, port, msn_ns_connected, ic ); 157 158 } 158 else if( num_parts == 6 && strcmp( cmd[2], "SB" ) == 0 )159 else if( num_parts >= 6 && strcmp( cmd[2], "SB" ) == 0 ) 159 160 { 160 161 struct msn_switchboard *sb; … … 220 221 else if( strcmp( cmd[0], "USR" ) == 0 ) 221 222 { 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 223 if( num_parts >= 6 && strcmp( cmd[2], "SSO" ) == 0 && 224 strcmp( cmd[3], "S" ) == 0 ) 225 { 226 msn_soap_passport_sso_request( ic, cmd[4], cmd[5] ); 227 } 228 else if( strcmp( cmd[2], "OK" ) == 0 ) 229 { 239 230 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 ) ) ); 231 msn_soap_memlist_request( ic ); 243 232 } 244 233 else … … 251 240 else if( strcmp( cmd[0], "MSG" ) == 0 ) 252 241 { 253 if( num_parts !=4 )242 if( num_parts < 4 ) 254 243 { 255 244 imcb_error( ic, "Syntax error" ); … … 267 256 } 268 257 } 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] ); 258 else if( strcmp( cmd[0], "BLP" ) == 0 ) 259 { 260 msn_ns_send_adl_start( ic ); 261 return msn_ns_finish_login( ic ); 262 } 263 else if( strcmp( cmd[0], "ADL" ) == 0 ) 264 { 265 if( num_parts >= 3 && strcmp( cmd[2], "OK" ) == 0 ) 266 { 267 msn_ns_send_adl( ic ); 268 return msn_ns_finish_login( ic ); 269 } 270 else if( num_parts >= 3 ) 271 { 272 md->handler->msglen = atoi( cmd[2] ); 273 } 274 } 275 else if( strcmp( cmd[0], "PRP" ) == 0 ) 276 { 277 imcb_connected( ic ); 372 278 } 373 279 else if( strcmp( cmd[0], "CHL" ) == 0 ) 374 280 { 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] ); 281 char *resp; 282 283 if( num_parts < 3 ) 284 { 285 imcb_error( ic, "Syntax error" ); 286 imc_logout( ic, TRUE ); 287 return( 0 ); 288 } 289 290 resp = msn_p11_challenge( cmd[2] ); 291 g_snprintf( buf, sizeof( buf ), "QRY %d %s %zd\r\n%s", 292 ++md->trId, MSNP11_PROD_ID, 293 strlen( resp ), resp ); 294 g_free( resp ); 394 295 395 296 return( msn_write( ic, buf, strlen( buf ) ) ); … … 399 300 const struct msn_away_state *st; 400 301 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] );302 if( num_parts < 6 ) 303 { 304 imcb_error( ic, "Syntax error" ); 305 imc_logout( ic, TRUE ); 306 return( 0 ); 307 } 308 309 http_decode( cmd[5] ); 310 imcb_rename_buddy( ic, cmd[3], cmd[5] ); 410 311 411 312 st = msn_away_state_by_code( cmd[2] ); … … 432 333 { 433 334 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] ); 335 int cap; 336 337 if( num_parts < 6 ) 338 { 339 imcb_error( ic, "Syntax error" ); 340 imc_logout( ic, TRUE ); 341 return( 0 ); 342 } 343 344 http_decode( cmd[4] ); 345 cap = atoi( cmd[5] ); 346 imcb_rename_buddy( ic, cmd[2], cmd[4] ); 444 347 445 348 st = msn_away_state_by_code( cmd[1] ); … … 451 354 452 355 imcb_buddy_status( ic, cmd[2], OPT_LOGGED_IN | 453 ( st != msn_away_state_list ? OPT_AWAY : 0 ), 356 ( st != msn_away_state_list ? OPT_AWAY : 0 ) | 357 ( cap & 1 ? OPT_MOBILE : 0 ), 454 358 st->name, NULL ); 455 359 … … 462 366 int session, port; 463 367 464 if( num_parts !=7 )368 if( num_parts < 7 ) 465 369 { 466 370 imcb_error( ic, "Syntax error" ); … … 504 408 } 505 409 } 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 410 else if( strcmp( cmd[0], "OUT" ) == 0 ) 547 411 { … … 565 429 return( 0 ); 566 430 } 431 else if( strcmp( cmd[0], "IPG" ) == 0 ) 432 { 433 imcb_error( ic, "Received IPG command, we don't handle them yet." ); 434 435 md->handler->msglen = atoi( cmd[1] ); 436 437 if( md->handler->msglen <= 0 ) 438 { 439 imcb_error( ic, "Syntax error" ); 440 imc_logout( ic, TRUE ); 441 return( 0 ); 442 } 443 } 567 444 #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 445 else if( strcmp( cmd[0], "ADG" ) == 0 ) 615 446 { … … 655 486 } 656 487 } 488 } 489 #endif 490 else if( strcmp( cmd[0], "GCF" ) == 0 ) 491 { 492 /* Coming up is cmd[2] bytes of stuff we're supposed to 493 censore. Meh. */ 494 md->handler->msglen = atoi( cmd[2] ); 495 } 496 else if( strcmp( cmd[0], "UBX" ) == 0 ) 497 { 498 /* Status message. */ 499 if( num_parts >= 4 ) 500 md->handler->msglen = atoi( cmd[3] ); 501 } 502 else if( strcmp( cmd[0], "NOT" ) == 0 ) 503 { 504 /* Some kind of notification, poorly documented but 505 apparently used to announce address book changes. */ 506 if( num_parts >= 2 ) 507 md->handler->msglen = atoi( cmd[1] ); 657 508 } 658 509 else if( isdigit( cmd[0][0] ) ) … … 765 616 } 766 617 } 618 else if( strcmp( cmd[0], "UBX" ) == 0 ) 619 { 620 struct xt_node *psm; 621 char *psm_text = NULL; 622 623 psm = xt_from_string( msg ); 624 if( psm && strcmp( psm->name, "Data" ) == 0 && 625 ( psm = xt_find_node( psm->children, "PSM" ) ) ) 626 psm_text = psm->text; 627 628 imcb_buddy_status_msg( ic, cmd[1], psm_text ); 629 xt_free_node( psm ); 630 } 631 else if( strcmp( cmd[0], "ADL" ) == 0 ) 632 { 633 struct xt_node *adl, *d, *c; 634 635 if( !( adl = xt_from_string( msg ) ) ) 636 return 1; 637 638 for( d = adl->children; d; d = d->next ) 639 { 640 char *dn; 641 if( strcmp( d->name, "d" ) != 0 || 642 ( dn = xt_find_attr( d, "n" ) ) == NULL ) 643 continue; 644 for( c = d->children; c; c = c->next ) 645 { 646 bee_user_t *bu; 647 struct msn_buddy_data *bd; 648 char *cn, *handle, *f, *l; 649 int flags; 650 651 if( strcmp( c->name, "c" ) != 0 || 652 ( l = xt_find_attr( c, "l" ) ) == NULL || 653 ( cn = xt_find_attr( c, "n" ) ) == NULL ) 654 continue; 655 656 handle = g_strdup_printf( "%s@%s", cn, dn ); 657 if( !( ( bu = bee_user_by_handle( ic->bee, ic, handle ) ) || 658 ( bu = bee_user_new( ic->bee, ic, handle, 0 ) ) ) ) 659 { 660 g_free( handle ); 661 continue; 662 } 663 g_free( handle ); 664 bd = bu->data; 665 666 if( ( f = xt_find_attr( c, "f" ) ) ) 667 { 668 http_decode( f ); 669 imcb_rename_buddy( ic, bu->handle, f ); 670 } 671 672 flags = atoi( l ) & 15; 673 if( bd->flags != flags ) 674 { 675 bd->flags = flags; 676 msn_buddy_ask( bu ); 677 } 678 } 679 } 680 } 767 681 768 682 return( 1 ); 769 683 } 770 684 771 static void msn_auth_got_passport_token( struct msn_auth_data *mad ) 772 { 773 struct im_connection *ic = mad->data; 685 void msn_auth_got_passport_token( struct im_connection *ic, const char *token, const char *error ) 686 { 774 687 struct msn_data *md; 775 688 … … 779 692 780 693 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 ); 694 695 if( token ) 696 { 697 char buf[1536]; 698 699 g_snprintf( buf, sizeof( buf ), "USR %d SSO S %s %s\r\n", ++md->trId, md->tokens[0], token ); 786 700 msn_write( ic, buf, strlen( buf ) ); 787 701 } 788 702 else 789 703 { 790 imcb_error( ic, "Error during Passport authentication: %s", mad->error );704 imcb_error( ic, "Error during Passport authentication: %s", error ); 791 705 imc_logout( ic, TRUE ); 792 706 } 793 707 } 794 708 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 } 709 void msn_auth_got_contact_list( struct im_connection *ic ) 710 { 711 char buf[64]; 712 struct msn_data *md; 713 714 /* Dead connection? */ 715 if( g_slist_find( msn_connections, ic ) == NULL ) 716 return; 717 718 md = ic->proto_data; 719 720 721 g_snprintf( buf, sizeof( buf ), "BLP %d %s\r\n", ++md->trId, "BL" ); 722 msn_write( ic, buf, strlen( buf ) ); 723 } 724 725 static gboolean msn_ns_send_adl_1( gpointer key, gpointer value, gpointer data ) 726 { 727 struct xt_node *adl = data, *d, *c; 728 struct bee_user *bu = value; 729 struct msn_buddy_data *bd = bu->data; 730 struct msn_data *md = bu->ic->proto_data; 731 char handle[strlen(bu->handle)]; 732 char *domain; 733 char l[4]; 734 735 if( ( bd->flags & 7 ) == 0 || ( bd->flags & MSN_BUDDY_ADL_SYNCED ) ) 736 return FALSE; 737 738 strcpy( handle, bu->handle ); 739 if( ( domain = strchr( handle, '@' ) ) == NULL ) /* WTF */ 740 return FALSE; 741 *domain = '\0'; 742 domain ++; 743 744 if( ( d = adl->children ) == NULL || 745 g_strcasecmp( xt_find_attr( d, "n" ), domain ) != 0 ) 746 { 747 d = xt_new_node( "d", NULL, NULL ); 748 xt_add_attr( d, "n", domain ); 749 xt_insert_child( adl, d ); 750 } 751 752 g_snprintf( l, sizeof( l ), "%d", bd->flags & 7 ); 753 c = xt_new_node( "c", NULL, NULL ); 754 xt_add_attr( c, "n", handle ); 755 xt_add_attr( c, "l", l ); 756 xt_add_attr( c, "t", "1" ); /* 1 means normal, 4 means mobile? */ 757 xt_insert_child( d, c ); 758 759 /* Do this in batches of 100. */ 760 bd->flags |= MSN_BUDDY_ADL_SYNCED; 761 return (--md->adl_todo % 140) == 0; 762 } 763 764 static void msn_ns_send_adl( struct im_connection *ic ) 765 { 766 struct xt_node *adl; 767 struct msn_data *md = ic->proto_data; 768 char *adls, buf[64]; 769 770 adl = xt_new_node( "ml", NULL, NULL ); 771 xt_add_attr( adl, "l", "1" ); 772 g_tree_foreach( md->domaintree, msn_ns_send_adl_1, adl ); 773 if( adl->children == NULL ) 774 { 775 /* This tells the caller that we're done now. */ 776 md->adl_todo = -1; 777 xt_free_node( adl ); 778 return; 779 } 780 adls = xt_to_string( adl ); 781 782 g_snprintf( buf, sizeof( buf ), "ADL %d %zd\r\n", ++md->trId, strlen( adls ) ); 783 if( msn_write( ic, buf, strlen( buf ) ) ) 784 msn_write( ic, adls, strlen( adls ) ); 785 786 g_free( adls ); 787 } 788 789 static void msn_ns_send_adl_start( struct im_connection *ic ) 790 { 791 struct msn_data *md; 792 GSList *l; 793 794 /* Dead connection? */ 795 if( g_slist_find( msn_connections, ic ) == NULL ) 796 return; 797 798 md = ic->proto_data; 799 md->adl_todo = 0; 800 for( l = ic->bee->users; l; l = l->next ) 801 { 802 bee_user_t *bu = l->data; 803 struct msn_buddy_data *bd = bu->data; 804 805 if( bu->ic != ic || ( bd->flags & 7 ) == 0 ) 806 continue; 807 808 bd->flags &= ~MSN_BUDDY_ADL_SYNCED; 809 md->adl_todo++; 810 } 811 812 msn_ns_send_adl( ic ); 813 } 814 815 int msn_ns_finish_login( struct im_connection *ic ) 816 { 817 struct msn_data *md = ic->proto_data; 818 819 if( ic->flags & OPT_LOGGED_IN ) 820 return 1; 821 822 if( md->adl_todo < 0 ) 823 md->flags |= MSN_DONE_ADL; 824 825 if( ( md->flags & MSN_DONE_ADL ) && ( md->flags & MSN_GOT_PROFILE ) ) 826 return msn_ns_set_display_name( ic, set_getstr( &ic->acc->set, "display_name" ) ); 818 827 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 } 828 return 1; 829 } -
protocols/msn/sb.c
rb0a89cc rfeb1bad 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 … … 38 38 { 39 39 int st; 40 41 if( getenv( "BITLBEE_DEBUG" ) ) 42 { 43 write( 2, "->SB:", 5 ); 44 write( 2, s, len ); 45 } 40 46 41 47 st = write( sb->fd, s, len ); … … 407 413 else if( strcmp( cmd[0], "USR" ) == 0 ) 408 414 { 409 if( num_parts !=5 )415 if( num_parts < 5 ) 410 416 { 411 417 msn_sb_destroy( sb ); … … 433 439 int num, tot; 434 440 435 if( num_parts !=6 )441 if( num_parts < 6 ) 436 442 { 437 443 msn_sb_destroy( sb ); … … 470 476 else if( strcmp( cmd[0], "ANS" ) == 0 ) 471 477 { 472 if( num_parts !=3 )478 if( num_parts < 3 ) 473 479 { 474 480 msn_sb_destroy( sb ); … … 489 495 else if( strcmp( cmd[0], "CAL" ) == 0 ) 490 496 { 491 if( num_parts !=4 || !isdigit( cmd[3][0] ) )497 if( num_parts < 4 || !isdigit( cmd[3][0] ) ) 492 498 { 493 499 msn_sb_destroy( sb ); … … 499 505 else if( strcmp( cmd[0], "JOI" ) == 0 ) 500 506 { 501 if( num_parts !=3 )507 if( num_parts < 3 ) 502 508 { 503 509 msn_sb_destroy( sb ); … … 560 566 else if( strcmp( cmd[0], "MSG" ) == 0 ) 561 567 { 562 if( num_parts !=4 )568 if( num_parts < 4 ) 563 569 { 564 570 msn_sb_destroy( sb ); … … 625 631 const struct msn_status_code *err = msn_status_by_number( num ); 626 632 627 imcb_error( ic, "Error reported by switchboard server: %s", err->text ); 633 /* If the person is offline, send an offline message instead, 634 and don't report an error. */ 635 if( num == 217 ) 636 msn_soap_oim_send_queue( ic, &sb->msgq ); 637 else 638 imcb_error( ic, "Error reported by switchboard server: %s", err->text ); 628 639 629 640 if( err->flags & STATUS_SB_FATAL ) … … 741 752 else if( g_strncasecmp( ct, "application/x-msnmsgrp2p", 24 ) == 0 ) 742 753 { 743 imcb_error( sb->ic, "Cannot receive file from %s: BitlBee does not "744 "support msnmsgrp2p yet.", sb->who );754 /* Not currently implemented. Don't warn about it since 755 this seems to be used for avatars now. */ 745 756 g_free( ct ); 746 757 } -
protocols/msn/tables.c
rb0a89cc rfeb1bad 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
rb0a89cc rfeb1bad 326 326 imcb_log( ic, "Signing off.." ); 327 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 336 328 for( l = bee->users; l; ) 337 329 { … … 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
rb0a89cc rfeb1bad 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
rb0a89cc rfeb1bad 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.