Changes in / [88de0c9:8e9e2b7]
- Files:
-
- 4 added
- 2 deleted
- 43 edited
Legend:
- Unmodified
- Added
- Removed
-
bitlbee.c
r88de0c9 r8e9e2b7 136 136 137 137 setsid(); 138 chdir( "/" ); 138 i = chdir( "/" ); 139 /* Don't use i, just make gcc happy. :-/ */ 139 140 140 141 if( getenv( "_BITLBEE_RESTART_STATE" ) == NULL ) -
bitlbee.h
r88de0c9 r8e9e2b7 137 137 #include "log.h" 138 138 #include "ini.h" 139 #include "help.h"140 139 #include "query.h" 141 140 #include "sock.h" … … 147 146 int listen_socket; 148 147 gint listen_watch_source_id; 149 help_t*help;148 struct help *help; 150 149 char *conf_file; 151 150 conf_t *conf; -
configure
r88de0c9 r8e9e2b7 425 425 fi; 426 426 427 if [ "$msn" = "1" -a "$ssl" != "openssl" ]; then 428 # Needed for MSN only. OpenSSL exports nice cipher functions already, 429 # others don't, so use our own 3des code. 430 echo 'DES=des.o' >> Makefile.settings 431 fi 432 427 433 echo 'SSL_CLIENT=ssl_'$ssl'.o' >> Makefile.settings 428 434 -
doc/CHANGES
r88de0c9 r8e9e2b7 4 4 http://bugs.bitlbee.org/bitlbee/timeline?daysback=90&changeset=on 5 5 6 Version 1.3dev: 7 - For the first time since 2007, a dev snapshot. Like then, this is pretty 8 stable already (running on testing.bitlbee.org for weeks by now), but not 9 all planned features for the next major release are ready yet, and there 10 may be some rough edges in the interface and documentation. 11 - Loads of new stuff, mostly ready for a new major release, but starting with 12 a dev snapshot. A few changes that were planned for a long time already: 6 Version 7 - Important: This version drops backward compatibility with the file format 8 used for user settings in versions before 1.2. If you're upgrading from 9 very old BitlBee versions (like 1.0.x), you'll have to recreate your 10 BitlBee account - or use an 1.2.x BitlBee once to do the conversion. 13 11 - Rewrote the IRC core, which brings: 14 12 * Support for multiple (control) channels, so you can have one channel per … … 52 50 for a list of supported protocols (works only in libpurple-enabled 53 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 (or 55 even contacts silently getting blocked!). This upgrade should fix all 56 of that. 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 … … 58 63 - Updated Yahoo! module to be in sync again with libyahoo2. This mostly 59 64 fixes issues with authorization requests. 60 61 Finished 6 Aug 2010 65 - Show if a contact is mobile or not. See "help set mobile_is_away". 66 - Easier handling of XMPP chatroom invitations. 67 - The chatroom mode of the Twitter module is now enabled by default, since 68 this was by far the most popular. To disable it, see "help set mode". 69 - Added some Twitter-specific commands that can only be used in the Twitter 70 window. Most important addition: Retweets. See "help set commands". 71 - Removed some ancient account/nick migration scripts and added one for 72 easier switching from Pidgin and other libpurple-based clients to BitlBee. 73 - Many bug fixes in both the core and IM modules, small feature enhancements 74 and other minor changes. 75 76 Finished ... 62 77 63 78 Version 1.2.8: -
doc/FAQ
r88de0c9 r8e9e2b7 62 62 These days, we replaced the Yahoo! code with libyahoo2 (which is a 63 63 separate Yahoo! module. It's derived from Gaim, but separately 64 maintained) and wrote our own MSN module. More modules are probably going 65 to be changed, so in the near future, the API might be the only thing 66 left from Gaim. 67 68 Q: What's that Gaim doing in BitlBee error messages and my Jabber resource? 69 A: Ah, well, as you probably know we use some of Gaim's IM-modules, and we 70 don't think it's worth our time to do a search-and-replace over the whole 71 source to get rid of every reference to Gaim. In fact, we don't want to, 72 since we don't want to pretend we wrote all that code. 64 maintained) and wrote our own MSN, Jabber and Twitter modules from 65 scratch. Most of the API has also been changed, so by now the only traces 66 of Gaim left are in the "nogaim" filename. 73 67 74 About Jabber: If you want a different resource string, you can set it 75 when logging in by appending it to your Jabber ID, like: 76 lintux@jabber.com/BitlBee 68 There is good news for Gaim (or now Pidgin, of course) fans though: 69 BitlBee can now be compiled to use libpurple for all IM interactions. 70 This makes BitlBee a bit more resource-hungry, but adds support for many 71 IM protocols/networks that couldn't be used from BitlBee so far. -
doc/README
r88de0c9 r8e9e2b7 71 71 --otr=1 or --otr=0 to force it on or off, respectively. 72 72 73 These days, MSN Messenger clients have to connect to the MS Passport servers74 through HTTPS. BitlBee can use several SSL libraries for this: GnuTLS, NSS 75 (which comes with Mozilla) and OpenSSL. OpenSSL is not GPL-compatible in some 76 situations, so using GnuTLS or NSS is preferred. However, especially on *BSD,77 OpenSSL can be considered part of the operating system, which eliminates the 78 GPL incompatibility.73 These days, many IM protocols use SSL/TLS connections (for authentication 74 or for the whole session). BitlBee can use several SSL libraries for this: 75 GnuTLS, NSS (which comes with Mozilla) and OpenSSL. OpenSSL is not GPL- 76 compatible in some situations, so using GnuTLS is preferred. However, 77 especially on *BSD, OpenSSL can be considered part of the operating system, 78 which eliminates the GPL incompatibility. 79 79 80 80 The incompatibility is also the reason why the SSL library detection code -
doc/user-guide/commands.xml
r88de0c9 r8e9e2b7 1655 1655 Only the <emphasis>group list</emphasis> command is supported at the moment, which shows a list of all groups defined so far. 1656 1656 </para> 1657 1658 <para> 1659 If you want to move contacts between groups, you can use the IRC <emphasis>/invite</emphasis> command. Also, if you use the <emphasis>add</emphasis> command in a control channel configured to show just one group, the new contact will automatically be added to that group. 1660 </para> 1657 1661 </description> 1658 1662 </bitlbee-command> -
doc/user-guide/misc.xml
r88de0c9 r8e9e2b7 175 175 176 176 <para> 177 If you want to configure your own channels, you can use the <emphasis>channel set</emphasis>. 177 If you want to configure your own channels, you can use the <emphasis>channel set</emphasis> command. See <emphasis>help channels3</emphasis> for more information. 178 </para> 179 180 </sect1> 181 182 <sect1 id="channels3"> 183 <title>Configuring a control channel</title> 184 185 <para> 186 The most important setting for a control channel is <emphasis>fill_by</emphasis>. It 187 tells BitlBee what information should be used to decide if someone should be shown 188 in the channel or not. After setting this setting to, for example, <emphasis>account</emphasis>, you 189 also have to set the <emphasis>account</emphasis> setting. Example: 190 </para> 191 192 <ircexample> 193 <ircline nick="wilmer">chan set &wlm fill_by account</ircline> 194 <ircline nick="root">fill_by = `account'</ircline> 195 <ircline nick="wilmer">chan set &wlm account msn</ircline> 196 <ircline nick="root">account = `msn'</ircline> 197 </ircexample> 198 199 <para> 200 Also, each channel has a <emphasis>show_users</emphasis> setting which lets you 201 choose, for example, if you want to see only online contacts in a channel, or 202 also/just offline contacts. Example: 203 </para> 204 205 <ircexample> 206 <ircline nick="wilmer">chan set &offline show_users offline</ircline> 207 <ircline nick="root">show_users = `offline'</ircline> 208 </ircexample> 209 210 <para> 211 See the help information for all these settings for more information. 178 212 </para> 179 213 … … 234 268 </sect1> 235 269 270 <sect1 id="whatsnew010206"> 271 <title>New stuff in BitlBee 1.2.6</title> 272 273 <para> 274 Twitter support. See <emphasis>help account add twitter</emphasis>. 275 </para> 276 </sect1> 277 278 <sect1 id="whatsnew010300"> 279 <title>New stuff in BitlBee 1.3dev</title> 280 281 <para> 282 Support for multiple configurable control channels, each with a subset of 283 your contact list. See <emphasis>help channels</emphasis> for more 284 information. 285 </para> 286 287 <para> 288 File transfer support for some protocols (more if you use libpurple). Just 289 /DCC SEND stuff. Incoming files also become DCC transfers. 290 </para> 291 292 <para> 293 Only if you run your own BitlBee instance: You can build a BitlBee that uses 294 libpurple for connecting to IM networks instead of its own code, adding 295 support for some of the more obscure IM protocols and features. 296 </para> 297 298 <para> 299 Many more things, briefly described in <emphasis>help news1.3</emphasis>. 300 </para> 301 </sect1> 302 236 303 <sect1 id="news1.3"> 237 <title>New stuff in BitlBee 1.3dev </title>304 <title>New stuff in BitlBee 1.3dev (details)</title> 238 305 239 306 <para> -
help.c
r88de0c9 r8e9e2b7 2 2 * BitlBee -- An IRC to other IM-networks gateway * 3 3 * * 4 * Copyright 2002-20 09Wilmer van der Gaast and others *4 * Copyright 2002-2010 Wilmer van der Gaast and others * 5 5 \********************************************************************/ 6 6 … … 26 26 #define BITLBEE_CORE 27 27 #include "bitlbee.h" 28 #include "help.h" 28 29 #undef read 29 30 #undef write … … 157 158 } 158 159 159 lseek( h->fd, h->offset.file_offset, SEEK_SET ); 160 read( h->fd, s, h->length ); 160 if( lseek( h->fd, h->offset.file_offset, SEEK_SET ) == -1 || 161 read( h->fd, s, h->length ) != h->length ) 162 return NULL; 161 163 } 162 164 else … … 193 195 return 1; 194 196 } 197 198 char *help_get_whatsnew( help_t **help, int old ) 199 { 200 GString *ret = NULL; 201 help_t *h; 202 int v; 203 204 for( h = *help; h; h = h->next ) 205 if( h->title != NULL && strncmp( h->title, "whatsnew", 8 ) == 0 && 206 sscanf( h->title + 8, "%x", &v ) == 1 && v > old ) 207 { 208 char *s = help_get( &h, h->title ); 209 if( ret == NULL ) 210 ret = g_string_new( s ); 211 else 212 g_string_append_printf( ret, "\n\n%s", s ); 213 g_free( s ); 214 } 215 216 return ret ? g_string_free( ret, FALSE ) : NULL; 217 } -
help.h
r88de0c9 r8e9e2b7 47 47 char *help_get( help_t **help, char *title ); 48 48 int help_add_mem( help_t **help, const char *title, const char *content_ ); 49 char *help_get_whatsnew( help_t **help, int old ); 49 50 50 51 #endif -
irc.c
r88de0c9 r8e9e2b7 114 114 s = set_add( &b->set, "last_version", NULL, NULL, irc ); 115 115 s->flags |= SET_HIDDEN; 116 s->value = g_strdup_printf( "%d", BITLBEE_VERSION_CODE ); 116 117 s = set_add( &b->set, "lcnicks", "true", set_eval_bool, irc ); 117 118 s = set_add( &b->set, "nick_format", "%-@nick", NULL, irc ); -
irc_channel.c
r88de0c9 r8e9e2b7 192 192 if( strcmp( value, "control" ) == 0 ) 193 193 new = &control_channel_funcs; 194 else if( strcmp( value, "chat" ) == 0 )194 else if( ic != ic->irc->default_channel && strcmp( value, "chat" ) == 0 ) 195 195 new = &irc_channel_im_chat_funcs; 196 196 else -
irc_commands.c
r88de0c9 r8e9e2b7 26 26 #define BITLBEE_CORE 27 27 #include "bitlbee.h" 28 #include "help.h" 28 29 #include "ipc.h" 29 30 -
irc_im.c
r88de0c9 r8e9e2b7 590 590 irc_channel_t *ic = c->ui_data; 591 591 592 if( ic == NULL )592 if( ic == NULL || bu == NULL ) 593 593 return FALSE; 594 594 … … 753 753 { 754 754 *s = '\0'; 755 if( ( iu = irc_user_by_name( ic->irc, nick ) ) && 755 if( ( iu = irc_user_by_name( ic->irc, nick ) ) && iu->bu && 756 756 iu->bu->nick && irc_channel_has_user( ic, iu ) ) 757 757 { … … 858 858 c->ic->acc->prpl->chat_topic( c, topic ); 859 859 g_free( topic ); 860 return TRUE;861 }862 860 } 861 862 /* Whatever happened, the IM module should ack the topic change. */ 863 863 return FALSE; 864 864 } -
irc_send.c
r88de0c9 r8e9e2b7 53 53 void irc_send_motd( irc_t *irc ) 54 54 { 55 char motd[2048]; 56 size_t len; 55 57 int fd; 56 58 57 59 fd = open( global.conf->motdfile, O_RDONLY ); 58 if( fd == -1 )60 if( fd == -1 || ( len = read( fd, motd, sizeof( motd ) - 1 ) ) <= 0 ) 59 61 { 60 62 irc_send_num( irc, 422, ":We don't need MOTDs." ); … … 62 64 else 63 65 { 64 char linebuf[80]; /* Max. line length for MOTD's is 79 chars. It's what most IRC networks seem to do. */ 65 char *add, max; 66 int len; 67 66 char linebuf[80]; 67 char *add = "", max, *in; 68 69 in = motd; 70 motd[len] = '\0'; 68 71 linebuf[79] = len = 0; 69 72 max = sizeof( linebuf ) - 1; 70 73 71 74 irc_send_num( irc, 375, ":- %s Message Of The Day - ", irc->root->host ); 72 while( read( fd, linebuf + len, 1 ) == 1)75 while( ( linebuf[len] = *(in++) ) ) 73 76 { 74 77 if( linebuf[len] == '\n' || len == max ) … … 80 83 else if( linebuf[len] == '%' ) 81 84 { 82 read( fd, linebuf + len, 1);85 linebuf[len] = *(in++); 83 86 if( linebuf[len] == 'h' ) 84 87 add = irc->root->host; … … 87 90 else if( linebuf[len] == 'n' ) 88 91 add = irc->user->nick; 92 else if( linebuf[len] == '\0' ) 93 in --; 89 94 else 90 95 add = "%"; … … 99 104 } 100 105 irc_send_num( irc, 376, ":End of MOTD" ); 106 } 107 108 if( fd != -1 ) 101 109 close( fd ); 102 }103 110 } 104 111 … … 107 114 irc_channel_t *ic = NULL; 108 115 irc_user_t *iu = irc->root; 109 char text[1 024];116 char text[1100]; 110 117 va_list params; 111 118 char *dst; -
lib/Makefile
r88de0c9 r8e9e2b7 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
r88de0c9 r8e9e2b7 308 308 void http_encode( char *s ) 309 309 { 310 char *t;310 char t[strlen(s)+1]; 311 311 int i, j; 312 312 313 t = g_strdup( s ); 314 313 strcpy( t, s ); 315 314 for( i = j = 0; t[i]; i ++, j ++ ) 316 315 { … … 330 329 } 331 330 s[j] = 0; 332 333 g_free( t );334 331 } 335 332 -
lib/sha1.c
r88de0c9 r8e9e2b7 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
r88de0c9 r8e9e2b7 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
r88de0c9 r8e9e2b7 81 81 the same action as the handler that just received the SSL_AGAIN.) */ 82 82 G_MODULE_EXPORT b_input_condition ssl_getdirection( void *conn ); 83 84 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
r88de0c9 r8e9e2b7 194 194 ssl_errno = SSL_AGAIN; 195 195 196 if( 0 && getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st ); 197 196 198 return st; 197 199 } … … 212 214 if( st == GNUTLS_E_AGAIN || st == GNUTLS_E_INTERRUPTED ) 213 215 ssl_errno = SSL_AGAIN; 216 217 if( 0 && getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st ); 214 218 215 219 return st; -
lib/ssl_openssl.c
r88de0c9 r8e9e2b7 60 60 { 61 61 initialized = TRUE; 62 SSLeay_add_ssl_algorithms(); 62 SSL_library_init(); 63 // SSLeay_add_ssl_algorithms(); 63 64 } 64 65 … … 210 211 } 211 212 213 if( 0 && getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st ); 214 212 215 return st; 213 216 } … … 224 227 225 228 st = SSL_write( ((struct scd*)conn)->ssl, buf, len ); 229 230 if( 0 && getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st ); 226 231 227 232 ssl_errno = SSL_OK; … … 277 282 return( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ? B_EV_IO_WRITE : B_EV_IO_READ ); 278 283 } 284 285 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) 286 { 287 int output_length = 0; 288 EVP_CIPHER_CTX ctx; 289 290 *res = g_new0(unsigned char, 72); 291 292 /* Don't set key or IV because we will modify the parameters */ 293 EVP_CIPHER_CTX_init(&ctx); 294 EVP_CipherInit_ex(&ctx, EVP_des_ede3_cbc(), NULL, NULL, NULL, 1); 295 EVP_CIPHER_CTX_set_key_length(&ctx, key_len); 296 EVP_CIPHER_CTX_set_padding(&ctx, 0); 297 /* We finished modifying parameters so now we can set key and IV */ 298 EVP_CipherInit_ex(&ctx, NULL, NULL, key, iv, 1); 299 EVP_CipherUpdate(&ctx, *res, &output_length, input, input_len); 300 EVP_CipherFinal_ex(&ctx, *res, &output_length); 301 EVP_CIPHER_CTX_cleanup(&ctx); 302 //EVP_cleanup(); 303 304 return output_length; 305 } -
lib/xmltree.c
r88de0c9 r8e9e2b7 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
r88de0c9 r8e9e2b7 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
r88de0c9 r8e9e2b7 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_chat.c
r88de0c9 r8e9e2b7 196 196 } 197 197 198 if( bee->ui->chat_remove_user )198 if( bee->ui->chat_remove_user && bu ) 199 199 bee->ui->chat_remove_user( bee, c, bu ); 200 200 } -
protocols/bee_user.c
r88de0c9 r8e9e2b7 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/jabber/conference.c
r88de0c9 r8e9e2b7 312 312 char *s; 313 313 314 if( subject && chat ) 315 { 316 s = bud ? strchr( bud->ext_jid, '/' ) : NULL; 317 if( s ) *s = 0; 318 imcb_chat_topic( chat, bud ? bud->ext_jid : NULL, subject->text_len > 0 ? 319 subject->text : NULL, jabber_get_timestamp( node ) ); 320 if( s ) *s = '/'; 321 } 322 314 323 if( bud == NULL || ( jc && ~jc->flags & JCFLAG_MESSAGE_SENT && bud == jc->me ) ) 315 324 { … … 366 375 return; 367 376 } 368 369 if( subject )370 {371 s = strchr( bud->ext_jid, '/' );372 if( s ) *s = 0;373 imcb_chat_topic( chat, bud->ext_jid, subject->text_len > 0 ?374 subject->text : NULL, jabber_get_timestamp( node ) );375 if( s ) *s = '/';376 }377 377 if( body && body->text_len > 0 ) 378 378 { -
protocols/msn/Makefile
r88de0c9 r8e9e2b7 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
r88de0c9 r8e9e2b7 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 … … 344 363 ret->set_away = msn_set_away; 345 364 ret->get_info = msn_get_info; 346 ret->set_my_name = msn_set_my_name;347 365 ret->add_buddy = msn_add_buddy; 348 366 ret->remove_buddy = msn_remove_buddy; … … 358 376 ret->send_typing = msn_send_typing; 359 377 ret->handle_cmp = g_strcasecmp; 378 ret->buddy_data_add = msn_buddy_data_add; 379 ret->buddy_data_free = msn_buddy_data_free; 380 360 381 //ret->transfer_request = msn_ftp_transfer_request; 361 382 -
protocols/msn/msn.h
r88de0c9 r8e9e2b7 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
r88de0c9 r8e9e2b7 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
r88de0c9 r8e9e2b7 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
r88de0c9 r8e9e2b7 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
r88de0c9 r8e9e2b7 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
r88de0c9 r8e9e2b7 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
r88de0c9 r8e9e2b7 200 200 this info via imcb_log(). Implementing these are optional. */ 201 201 void (* get_info) (struct im_connection *, char *who); 202 /* set_my_name is *DEPRECATED*, not used by the UI anymore. Use the 203 display_name setting instead. */ 202 204 void (* set_my_name) (struct im_connection *, char *name); 203 205 void (* set_name) (struct im_connection *, char *who, char *name); -
protocols/oscar/ssi.c
r88de0c9 r8e9e2b7 415 415 if (!parentgroup) { 416 416 char *newgroup; 417 newgroup = (char*)g_malloc(strlen("Unknown") *sizeof(char));417 newgroup = (char*)g_malloc(strlen("Unknown")+1); 418 418 strcpy(newgroup, "Unknown"); 419 419 aim_ssi_addgroups(sess, conn, &newgroup, 1); -
protocols/purple/purple.c
r88de0c9 r8e9e2b7 80 80 char help_title[64]; 81 81 GString *help; 82 static gboolean dir_fixed = FALSE; 83 84 /* Layer violation coming up: Making an exception for libpurple here. 85 Dig in the IRC state a bit to get a username. Ideally we should 86 check if s/he identified but this info doesn't seem *that* important. 87 It's just that fecking libpurple can't *not* store this shit. 88 89 Remember that libpurple is not really meant to be used on public 90 servers anyway! */ 91 if( !dir_fixed ) 92 { 93 irc_t *irc = acc->bee->ui_data; 94 char *dir; 95 96 dir = g_strdup_printf( "%s/purple/%s", global.conf->configdir, irc->user->nick ); 97 purple_util_set_user_dir( dir ); 98 g_free( dir ); 99 100 purple_blist_load(); 101 purple_prefs_load(); 102 dir_fixed = TRUE; 103 } 82 104 83 105 help = g_string_new( "" ); … … 254 276 PurpleAccount *pa; 255 277 256 if( local_bee != NULL && local_bee != acc->bee ) 278 if( ( local_bee != NULL && local_bee != acc->bee ) || 279 ( global.conf->runmode == RUNMODE_DAEMON && !getenv( "BITLBEE_DEBUG" ) ) ) 257 280 { 258 281 imcb_error( ic, "Daemon mode detected. Do *not* try to use libpurple in daemon mode! " … … 351 374 account_t *acc = set->data; 352 375 struct im_connection *ic = acc->ic; 376 377 if( ic ) 378 imcb_log( ic, "Changing display_name not currently supported with libpurple!" ); 353 379 354 380 return NULL; … … 517 543 } 518 544 519 struct groupchat *purple_chat_join( struct im_connection *ic, const char *room, const char *nick, const char *password )545 struct groupchat *purple_chat_join( struct im_connection *ic, const char *room, const char *nick, const char *password, set_t **sets ) 520 546 { 521 547 PurpleAccount *pa = ic->proto_data; … … 1132 1158 GList *prots; 1133 1159 GString *help; 1160 char *dir; 1134 1161 1135 1162 if( B_EV_IO_READ != PURPLE_INPUT_READ || … … 1140 1167 } 1141 1168 1142 purple_util_set_user_dir( "/tmp" ); 1169 dir = g_strdup_printf( "%s/purple", global.conf->configdir ); 1170 purple_util_set_user_dir( dir ); 1171 g_free( dir ); 1172 1143 1173 purple_debug_set_enabled( FALSE ); 1144 1174 purple_core_set_ui_ops( &bee_core_uiops ); … … 1151 1181 } 1152 1182 1153 /* This seems like stateful shit we don't want... */1154 1183 purple_set_blist( purple_blist_new() ); 1155 purple_blist_load();1156 1157 /* Meh? */1158 purple_prefs_load();1159 1184 1160 1185 /* No, really. So far there were ui_ops for everything, but now suddenly … … 1221 1246 1222 1247 g_string_append( help, "\n\nFor used protocols, more information about available " 1223 "settings can be found using \x02help purple <protocol name>\x02" ); 1248 "settings can be found using \x02help purple <protocol name>\x02 " 1249 "(create an account using that protocol first!)" ); 1224 1250 1225 1251 /* Add a simple dynamically-generated help item listing all -
protocols/twitter/twitter.c
r88de0c9 r8e9e2b7 29 29 #include "url.h" 30 30 31 #define twitter_msg( ic, fmt... ) \ 32 do { \ 33 struct twitter_data *td = ic->proto_data; \ 34 if( td->home_timeline_gc ) \ 35 imcb_chat_log( td->home_timeline_gc, fmt ); \ 36 else \ 37 imcb_log( ic, fmt ); \ 38 } while( 0 ); 39 40 31 41 /** 32 42 * Main loop function … … 436 446 if( id ) 437 447 twitter_status_destroy( ic, id ); 448 else 449 twitter_msg( ic, "Could not undo last action" ); 438 450 439 451 g_free( cmds ); … … 467 479 if( id ) 468 480 twitter_status_retweet( ic, id ); 481 else 482 twitter_msg( ic, "User `%s' does not exist or didn't " 483 "post any statuses recently", cmd[1] ); 469 484 470 485 g_free( cmds ); -
root_commands.c
r88de0c9 r8e9e2b7 1293 1293 { 1294 1294 int last = set_getint( &irc->b->set, "last_version" ); 1295 GString *msg = g_string_new( "" ); 1296 char s[16]; 1295 char s[16], *msg; 1297 1296 1298 1297 if( last >= BITLBEE_VERSION_CODE ) 1299 1298 return; 1300 1299 1301 if( last < 0x010206 ) /* 1.2.6 */ 1302 { 1303 g_string_append( msg, 1304 "Twitter support. See \x02help account add twitter\x02.\n" ); 1305 } 1306 if( last < 0x010300 ) /* 1.3dev */ 1307 { 1308 g_string_append( msg, 1309 "Support for multiple configurable control channels, " 1310 "each with a subset of your contact list. See " 1311 "\x02help channels\x02 for more information.\n" 1312 "File transfer support for some protocols (more if " 1313 "you use libpurple). Just /DCC SEND stuff. Incoming " 1314 "files also become DCC transfers.\n" 1315 "Many more things, briefly described in " 1316 "\x02help news1.3\x02.\n" ); 1317 } 1318 1319 if( msg->len > 0 ) 1300 msg = help_get_whatsnew( &(global.help), last ); 1301 1302 if( msg ) 1320 1303 irc_usermsg( irc, "%s: This seems to be your first time using this " 1321 1304 "this version of BitlBee. Here's a list of new " 1322 1305 "features you may like to know about:\n\n%s\n", 1323 irc->user->nick, msg->str ); 1324 1325 g_string_free( msg, TRUE ); 1306 irc->user->nick, msg ); 1307 1308 g_free( msg ); 1309 1326 1310 g_snprintf( s, sizeof( s ), "%d", BITLBEE_VERSION_CODE ); 1327 1311 set_setstr( &irc->b->set, "last_version", s ); -
storage_xml.c
r88de0c9 r8e9e2b7 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 ); -
unix.c
r88de0c9 r8e9e2b7 181 181 doesn't make a copy. Odd. */ 182 182 183 chdir( old_cwd );183 i = chdir( old_cwd ); 184 184 close( global.listen_socket ); 185 185
Note: See TracChangeset
for help on using the changeset viewer.