Changes in / [3ad8036:508588a]


Ignore:
Files:
4 added
2 deleted
46 edited

Legend:

Unmodified
Added
Removed
  • bitlbee.c

    r3ad8036 r508588a  
    136136               
    137137                setsid();
    138                 chdir( "/" );
     138                i = chdir( "/" );
     139                /* Don't use i, just make gcc happy. :-/ */
    139140               
    140141                if( getenv( "_BITLBEE_RESTART_STATE" ) == NULL )
  • bitlbee.h

    r3ad8036 r508588a  
    137137#include "log.h"
    138138#include "ini.h"
    139 #include "help.h"
    140139#include "query.h"
    141140#include "sock.h"
     
    147146        int listen_socket;
    148147        gint listen_watch_source_id;
    149         help_t *help;
     148        struct help *help;
    150149        char *conf_file;
    151150        conf_t *conf;
  • configure

    r3ad8036 r508588a  
    3434gcov=0
    3535plugins=1
    36 otr=auto
     36otr=0
    3737
    3838events=glib
     
    7373
    7474--purple=0/1    Disable/enable libpurple support        $purple
     75                (automatically disables other protocol modules)
    7576
    7677--debug=0/1     Disable/enable debugging                $debug
     
    7879--gcov=0/1      Disable/enable test coverage reporting  $gcov
    7980--plugins=0/1   Disable/enable plugins support          $plugins
    80 --otr=0/1       Disable/enable OTR encryption support   $otr
     81--otr=0/1/auto/plugin
     82                Disable/enable OTR encryption support   $otr
    8183
    8284--events=...    Event handler (glib, libevent)          $events
     
    425427fi;
    426428
     429if [ "$msn" = "1" -a "$ssl" != "openssl" ]; then
     430        # Needed for MSN only. OpenSSL exports nice cipher functions already,
     431        # others don't, so use our own 3des code.
     432        echo 'DES=des.o' >> Makefile.settings
     433fi
     434
    427435echo 'SSL_CLIENT=ssl_'$ssl'.o' >> Makefile.settings
    428436
  • doc/CHANGES

    r3ad8036 r508588a  
    44http://bugs.bitlbee.org/bitlbee/timeline?daysback=90&changeset=on
    55
    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:
     6Version
     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.
    1311- Rewrote the IRC core, which brings:
    1412  * Support for multiple (control) channels, so you can have one channel per
     
    5250    for a list of supported protocols (works only in libpurple-enabled
    5351    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.
    5459- Support for file transfers, in and out. /DCC SEND a file to a contact and
    5560  it becomes a file transfer, and incoming file transfers become /DCC SENDs
     
    5863- Updated Yahoo! module to be in sync again with libyahoo2. This mostly
    5964  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
     76Finished ...
    6277
    6378Version 1.2.8:
  • doc/FAQ

    r3ad8036 r508588a  
    6262   These days, we replaced the Yahoo! code with libyahoo2 (which is a
    6363   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.
    7367   
    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

    r3ad8036 r508588a  
    6767platform. Any recent version of GLib (2.4 or higher) will work.
    6868
    69 Off-the-Record encryption support will be included by default if the
    70 configure script finds libotr in one of the usual places. You can pass
    71 --otr=1 or --otr=0 to force it on or off, respectively.
     69Off-the-Record encryption support can be included if libotr is available on
     70your machine. Pass --otr=1 to configure to build it into BitlBee, or
     71--otr=plugin to build it as a separate loadable plugin (mostly meant for
     72distro packages).
    7273
    73 These days, MSN Messenger clients have to connect to the MS Passport servers
    74 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.
     74These days, many IM protocols use SSL/TLS connections (for authentication
     75or for the whole session). BitlBee can use several SSL libraries for this:
     76GnuTLS, NSS (which comes with Mozilla) and OpenSSL. OpenSSL is not GPL-
     77compatible in some situations, so using GnuTLS is preferred. However,
     78especially on *BSD, OpenSSL can be considered part of the operating system,
     79which eliminates the GPL incompatibility.
    7980
    8081The incompatibility is also the reason why the SSL library detection code
  • doc/user-guide/commands.xml

    r3ad8036 r508588a  
    16671667                                Only the <emphasis>group list</emphasis> command is supported at the moment, which shows a list of all groups defined so far.
    16681668                        </para>
     1669                       
     1670                        <para>
     1671                                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.
     1672                        </para>
    16691673                </description>
    16701674        </bitlbee-command>
  • doc/user-guide/misc.xml

    r3ad8036 r508588a  
    175175
    176176<para>
    177 If you want to configure your own channels, you can use the <emphasis>channel set</emphasis>.
     177If 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>
     186The most important setting for a control channel is <emphasis>fill_by</emphasis>. It
     187tells BitlBee what information should be used to decide if someone should be shown
     188in the channel or not. After setting this setting to, for example, <emphasis>account</emphasis>, you
     189also have to set the <emphasis>account</emphasis> setting. Example:
     190</para>
     191
     192<ircexample>
     193        <ircline nick="wilmer">chan set &amp;wlm fill_by account</ircline>
     194        <ircline nick="root">fill_by = `account'</ircline>
     195        <ircline nick="wilmer">chan set &amp;wlm account msn</ircline>
     196        <ircline nick="root">account = `msn'</ircline>
     197</ircexample>
     198
     199<para>
     200Also, each channel has a <emphasis>show_users</emphasis> setting which lets you
     201choose, for example, if you want to see only online contacts in a channel, or
     202also/just offline contacts. Example:
     203</para>
     204
     205<ircexample>
     206        <ircline nick="wilmer">chan set &amp;offline show_users offline</ircline>
     207        <ircline nick="root">show_users = `offline'</ircline>
     208</ircexample>
     209
     210<para>
     211See the help information for all these settings for more information.
    178212</para>
    179213
     
    234268</sect1>
    235269
     270<sect1 id="whatsnew010206">
     271<title>New stuff in BitlBee 1.2.6</title>
     272
     273<para>
     274Twitter 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>
     282Support for multiple configurable control channels, each with a subset of
     283your contact list. See <emphasis>help channels</emphasis> for more
     284information.
     285</para>
     286
     287<para>
     288File 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>
     293Only if you run your own BitlBee instance: You can build a BitlBee that uses
     294libpurple for connecting to IM networks instead of its own code, adding
     295support for some of the more obscure IM protocols and features.
     296</para>
     297
     298<para>
     299Many more things, briefly described in <emphasis>help news1.3</emphasis>.
     300</para>
     301</sect1>
     302
    236303<sect1 id="news1.3">
    237 <title>New stuff in BitlBee 1.3dev</title>
     304<title>New stuff in BitlBee 1.3dev (details)</title>
    238305
    239306<para>
  • help.c

    r3ad8036 r508588a  
    22  * BitlBee -- An IRC to other IM-networks gateway                     *
    33  *                                                                    *
    4   * Copyright 2002-2009 Wilmer van der Gaast and others                *
     4  * Copyright 2002-2010 Wilmer van der Gaast and others                *
    55  \********************************************************************/
    66
     
    2626#define BITLBEE_CORE
    2727#include "bitlbee.h"
     28#include "help.h"
    2829#undef read
    2930#undef write
     
    157158                        }
    158159                       
    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;
    161163                }
    162164                else
     
    193195        return 1;
    194196}
     197
     198char *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

    r3ad8036 r508588a  
    4747char *help_get( help_t **help, char *title );
    4848int help_add_mem( help_t **help, const char *title, const char *content_ );
     49char *help_get_whatsnew( help_t **help, int old );
    4950
    5051#endif
  • irc.c

    r3ad8036 r508588a  
    114114        s = set_add( &b->set, "last_version", NULL, NULL, irc );
    115115        s->flags |= SET_HIDDEN;
     116        s->value = g_strdup_printf( "%d", BITLBEE_VERSION_CODE );
    116117        s = set_add( &b->set, "lcnicks", "true", set_eval_bool, irc );
    117118        s = set_add( &b->set, "nick_format", "%-@nick", NULL, irc );
  • irc_channel.c

    r3ad8036 r508588a  
    192192        if( strcmp( value, "control" ) == 0 )
    193193                new = &control_channel_funcs;
    194         else if( strcmp( value, "chat" ) == 0 )
     194        else if( ic != ic->irc->default_channel && strcmp( value, "chat" ) == 0 )
    195195                new = &irc_channel_im_chat_funcs;
    196196        else
  • irc_commands.c

    r3ad8036 r508588a  
    2626#define BITLBEE_CORE
    2727#include "bitlbee.h"
     28#include "help.h"
    2829#include "ipc.h"
    2930
  • irc_im.c

    r3ad8036 r508588a  
    590590        irc_channel_t *ic = c->ui_data;
    591591       
    592         if( ic == NULL )
     592        if( ic == NULL || bu == NULL )
    593593                return FALSE;
    594594       
     
    753753                {
    754754                        *s = '\0';
    755                         if( ( iu = irc_user_by_name( ic->irc, nick ) ) &&
     755                        if( ( iu = irc_user_by_name( ic->irc, nick ) ) && iu->bu &&
    756756                            iu->bu->nick && irc_channel_has_user( ic, iu ) )
    757757                        {
     
    858858                c->ic->acc->prpl->chat_topic( c, topic );
    859859                g_free( topic );
    860                 return TRUE;
    861         }
    862                
     860        }
     861               
     862        /* Whatever happened, the IM module should ack the topic change. */
    863863        return FALSE;
    864864}
  • irc_send.c

    r3ad8036 r508588a  
    5353void irc_send_motd( irc_t *irc )
    5454{
     55        char motd[2048];
     56        size_t len;
    5557        int fd;
    5658       
    5759        fd = open( global.conf->motdfile, O_RDONLY );
    58         if( fd == -1 )
     60        if( fd == -1 || ( len = read( fd, motd, sizeof( motd ) - 1 ) ) <= 0 )
    5961        {
    6062                irc_send_num( irc, 422, ":We don't need MOTDs." );
     
    6264        else
    6365        {
    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';
    6871                linebuf[79] = len = 0;
    6972                max = sizeof( linebuf ) - 1;
    7073               
    7174                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++) ) )
    7376                {
    7477                        if( linebuf[len] == '\n' || len == max )
     
    8083                        else if( linebuf[len] == '%' )
    8184                        {
    82                                 read( fd, linebuf + len, 1 );
     85                                linebuf[len] = *(in++);
    8386                                if( linebuf[len] == 'h' )
    8487                                        add = irc->root->host;
     
    8790                                else if( linebuf[len] == 'n' )
    8891                                        add = irc->user->nick;
     92                                else if( linebuf[len] == '\0' )
     93                                        in --;
    8994                                else
    9095                                        add = "%";
     
    99104                }
    100105                irc_send_num( irc, 376, ":End of MOTD" );
     106        }
     107       
     108        if( fd != -1 )
    101109                close( fd );
    102         }
    103110}
    104111
     
    107114        irc_channel_t *ic = NULL;
    108115        irc_user_t *iu = irc->root;
    109         char text[1024];
     116        char text[1100];
    110117        va_list params;
    111118        char *dst;
  • lib/Makefile

    r3ad8036 r508588a  
    1313
    1414# [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.o
     15objects = 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
    1616
    1717LFLAGS += -r
  • lib/events.h

    r3ad8036 r508588a  
    8181G_MODULE_EXPORT void b_event_remove(gint id);
    8282
    83 /* For now, closesocket() is only a function when using libevent. With GLib
    84    it's a preprocessor macro. */
    85 #ifdef EVENTS_LIBEVENT
     83/* With libevent, this one also cleans up event handlers if that wasn't already
     84   done (the caller is expected to do so but may miss it sometimes). */
    8685G_MODULE_EXPORT void closesocket(int fd);
    87 #endif
    8886
    8987#endif /* _EVENTS_H_ */
  • lib/events_glib.c

    r3ad8036 r508588a  
    147147                g_source_remove(tag);
    148148}
     149
     150void closesocket( int fd )
     151{
     152        close( fd );
     153}
  • lib/misc.c

    r3ad8036 r508588a  
    308308void http_encode( char *s )
    309309{
    310         char *t;
     310        char t[strlen(s)+1];
    311311        int i, j;
    312312       
    313         t = g_strdup( s );
    314        
     313        strcpy( t, s );
    315314        for( i = j = 0; t[i]; i ++, j ++ )
    316315        {
     
    330329        }
    331330        s[j] = 0;
    332        
    333         g_free( t );
    334331}
    335332
  • lib/sha1.c

    r3ad8036 r508588a  
    3636 */
    3737
     38#include <string.h>
    3839#include "sha1.h"
    3940
     
    374375        sha1_process_block(context);
    375376}
     377
     378#define HMAC_BLOCK_SIZE 64
     379
     380/* BitlBee addition: */
     381void 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

    r3ad8036 r508588a  
    6767G_MODULE_EXPORT int sha1_append(sha1_state_t *, const uint8_t *, unsigned int);
    6868G_MODULE_EXPORT int sha1_finish(sha1_state_t *, uint8_t Message_Digest[sha1_hash_size]);
     69G_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]);
    6970
    7071#endif
  • lib/ssl_client.h

    r3ad8036 r508588a  
    8181   the same action as the handler that just received the SSL_AGAIN.) */
    8282G_MODULE_EXPORT b_input_condition ssl_getdirection( void *conn );
     83
     84G_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

    r3ad8036 r508588a  
    194194                ssl_errno = SSL_AGAIN;
    195195       
     196        if( 0 && getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st );
     197       
    196198        return st;
    197199}
     
    212214        if( st == GNUTLS_E_AGAIN || st == GNUTLS_E_INTERRUPTED )
    213215                ssl_errno = SSL_AGAIN;
     216       
     217        if( 0 && getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st );
    214218       
    215219        return st;
  • lib/ssl_openssl.c

    r3ad8036 r508588a  
    6060{
    6161        initialized = TRUE;
    62         SSLeay_add_ssl_algorithms();
     62        SSL_library_init();
     63        // SSLeay_add_ssl_algorithms();
    6364}
    6465
     
    210211        }
    211212       
     213        if( 0 && getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st );
     214       
    212215        return st;
    213216}
     
    224227       
    225228        st = SSL_write( ((struct scd*)conn)->ssl, buf, len );
     229       
     230        if( 0 && getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st );
    226231       
    227232        ssl_errno = SSL_OK;
     
    277282        return( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ? B_EV_IO_WRITE : B_EV_IO_READ );
    278283}
     284
     285size_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

    r3ad8036 r508588a  
    141141/* Feed the parser, don't execute any handler. Returns -1 on errors, 0 on
    142142   end-of-stream and 1 otherwise. */
    143 int xt_feed( struct xt_parser *xt, char *text, int text_len )
     143int xt_feed( struct xt_parser *xt, const char *text, int text_len )
    144144{
    145145        if( !g_markup_parse_context_parse( xt->parser, text, text_len, &xt->gerr ) )
     
    174174        if( node->flags & XT_COMPLETE && !( node->flags & XT_SEEN ) )
    175175        {
    176                 for( i = 0; xt->handlers[i].func; i ++ )
     176                if( xt->handlers ) for( i = 0; xt->handlers[i].func; i ++ )
    177177                {
    178178                        /* This one is fun! \o/ */
    179179                       
    180                                                 /* If handler.name == NULL it means it should always match. */
     180                            /* If handler.name == NULL it means it should always match. */
    181181                        if( ( xt->handlers[i].name == NULL ||
    182                                                 /* If it's not, compare. There should always be a name. */
     182                              /* If it's not, compare. There should always be a name. */
    183183                              g_strcasecmp( xt->handlers[i].name, node->name ) == 0 ) &&
    184                                                 /* If handler.parent == NULL, it's a match. */
     184                            /* If handler.parent == NULL, it's a match. */
    185185                            ( xt->handlers[i].parent == NULL ||
    186                                                 /* If there's a parent node, see if the name matches. */
     186                              /* If there's a parent node, see if the name matches. */
    187187                              ( node->parent ? g_strcasecmp( xt->handlers[i].parent, node->parent->name ) == 0 :
    188                                                 /* If there's no parent, the handler should mention <root> as a parent. */
    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 ) ) )
    190190                        {
    191191                                st = xt->handlers[i].func( node, xt->data );
     
    260260}
    261261
     262struct 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
    262276static void xt_to_string_real( struct xt_node *node, GString *str )
    263277{
     
    317331        /* Indentation */
    318332        for( c = node; c->parent; c = c->parent )
    319                 printf( "\t" );
     333                printf( "    " );
    320334       
    321335        /* Start the tag */
     
    324338        /* Print the attributes */
    325339        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        }
    327345       
    328346        /* /> in case there's really *nothing* inside this tag, otherwise
     
    344362                for( i = 0; node->text[i] && isspace( node->text[i] ); i ++ );
    345363                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                }
    347369        }
    348370       
     
    355377        if( node->children )
    356378                for( c = node; c->parent; c = c->parent )
    357                         printf( "\t" );
     379                        printf( "    " );
    358380       
    359381        /* Non-empty tag is now finished. */
     
    460482               
    461483                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. */
     492struct 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;
    462524        }
    463525       
     
    550612}
    551613
     614/* Same, but at the beginning. */
     615void 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
    552634void xt_add_attr( struct xt_node *node, const char *key, const char *value )
    553635{
  • lib/xmltree.h

    r3ad8036 r508588a  
    7979struct xt_parser *xt_new( const struct xt_handler_entry *handlers, gpointer data );
    8080void xt_reset( struct xt_parser *xt );
    81 int xt_feed( struct xt_parser *xt, char *text, int text_len );
     81int xt_feed( struct xt_parser *xt, const char *text, int text_len );
    8282int xt_handle( struct xt_parser *xt, struct xt_node *node, int depth );
    8383void xt_cleanup( struct xt_parser *xt, struct xt_node *node, int depth );
     84struct xt_node *xt_from_string( const char *in );
    8485char *xt_to_string( struct xt_node *node );
    8586void xt_print( struct xt_node *node );
     
    8889void xt_free( struct xt_parser *xt );
    8990struct xt_node *xt_find_node( struct xt_node *node, const char *name );
     91struct xt_node *xt_find_path( struct xt_node *node, const char *name );
    9092char *xt_find_attr( struct xt_node *node, const char *key );
    9193
    9294struct xt_node *xt_new_node( char *name, const char *text, struct xt_node *children );
    9395void xt_add_child( struct xt_node *parent, struct xt_node *child );
     96void xt_insert_child( struct xt_node *parent, struct xt_node *child );
    9497void xt_add_attr( struct xt_node *node, const char *key, const char *value );
    9598int xt_remove_attr( struct xt_node *node, const char *key );
  • protocols/bee.h

    r3ad8036 r508588a  
    151151 * - 'state' and 'message' can be NULL */
    152152G_MODULE_EXPORT void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, const char *state, const char *message );
     153G_MODULE_EXPORT void imcb_buddy_status_msg( struct im_connection *ic, const char *handle, const char *message );
    153154G_MODULE_EXPORT void imcb_buddy_times( struct im_connection *ic, const char *handle, time_t login, time_t idle );
    154155/* Call when a handle says something. 'flags' and 'sent_at may be just 0. */
  • protocols/bee_chat.c

    r3ad8036 r508588a  
    196196        }
    197197       
    198         if( bee->ui->chat_remove_user )
     198        if( bee->ui->chat_remove_user && bu )
    199199                bee->ui->chat_remove_user( bee, c, bu );
    200200}
  • protocols/bee_user.c

    r3ad8036 r508588a  
    187187        /* TODO(wilmer): OPT_AWAY, or just state == NULL ? */
    188188        bu->flags = flags;
    189         bu->status = g_strdup( ( flags & OPT_AWAY ) && state == NULL ? "Away" : state );
    190189        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;
    191196       
    192197        if( bu->status == NULL && ( flags & OPT_MOBILE ) &&
     
    205210}
    206211
     212/* Same, but only change the away/status message, not any away/online state info. */
     213void 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
    207234void imcb_buddy_times( struct im_connection *ic, const char *handle, time_t login, time_t idle )
    208235{
  • protocols/jabber/conference.c

    r3ad8036 r508588a  
    312312        char *s;
    313313       
     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       
    314323        if( bud == NULL || ( jc && ~jc->flags & JCFLAG_MESSAGE_SENT && bud == jc->me ) )
    315324        {
     
    366375                return;
    367376        }
    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         }
    377377        if( body && body->text_len > 0 )
    378378        {
  • protocols/msn/Makefile

    r3ad8036 r508588a  
    1313
    1414# [SH] Program variables
    15 objects = msn.o msn_util.o ns.o passport.o sb.o tables.o
     15objects = msn.o msn_util.o ns.o sb.o soap.o tables.o
    1616
    1717LFLAGS += -r
  • protocols/msn/msn.c

    r3ad8036 r508588a  
    22  * BitlBee -- An IRC to other IM-networks gateway                     *
    33  *                                                                    *
    4   * Copyright 2002-2004 Wilmer van der Gaast and others                *
     4  * Copyright 2002-2010 Wilmer van der Gaast and others                *
    55  \********************************************************************/
    66
     
    2525
    2626#include "nogaim.h"
     27#include "soap.h"
    2728#include "msn.h"
    2829
     
    3536static void msn_init( account_t *acc )
    3637{
    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       
    3943        set_add( &acc->set, "mail_notifications", "false", set_eval_bool, acc );
    4044        set_add( &acc->set, "switchboard_keepalives", "false", set_eval_bool, acc );
     45       
     46        acc->flags |= ACC_FLAG_AWAY_MESSAGE | ACC_FLAG_STATUS_MESSAGE;
    4147}
    4248
     
    4753       
    4854        ic->proto_data = md;
    49         md->fd = -1;
    5055       
    5156        if( strchr( acc->user, '@' ) == NULL )
     
    5661        }
    5762       
    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        
    6863        md->ic = ic;
    6964        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 );
    7272}
    7373
     
    7676        struct msn_data *md = ic->proto_data;
    7777        GSList *l;
     78        int i;
    7879       
    7980        if( md )
     
    8586                */
    8687               
    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 );
    9689               
    9790                while( md->switchboards )
     
    9992               
    10093                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;
    105112               
    106113                while( md->grpq )
     
    134141        if( strcmp( who, "raw" ) == 0 )
    135142        {
    136                 msn_write( ic, message, strlen( message ) );
    137                 msn_write( ic, "\r\n", 2 );
     143                msn_ns_write( ic, -1, "%s\r\n", message );
    138144        }
    139145        else
     
    173179static void msn_set_away( struct im_connection *ic, char *state, char *message )
    174180{
    175         char buf[1024];
     181        char *uux;
    176182        struct msn_data *md = ic->proto_data;
    177183       
     
    181187                md->away_state = msn_away_state_list + 1;
    182188       
    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 );
    190196}
    191197
     
    200206        struct bee_user *bu = bee_user_by_handle( ic->bee, ic, who );
    201207       
    202         msn_buddy_list_add( ic, "FL", who, who, group );
     208        msn_buddy_list_add( ic, MSN_BUDDY_FL, who, who, group );
    203209        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 );
    205211}
    206212
    207213static void msn_remove_buddy( struct im_connection *ic, char *who, char *group )
    208214{
    209         msn_buddy_list_remove( ic, "FL", who, NULL );
     215        msn_buddy_list_remove( ic, MSN_BUDDY_FL, who, NULL );
    210216}
    211217
     
    267273static void msn_keepalive( struct im_connection *ic )
    268274{
    269         msn_write( ic, "PNG\r\n", strlen( "PNG\r\n" ) );
     275        msn_ns_write( ic, -1, "PNG\r\n" );
    270276}
    271277
    272278static void msn_add_permit( struct im_connection *ic, char *who )
    273279{
    274         msn_buddy_list_add( ic, "AL", who, who, NULL );
     280        msn_buddy_list_add( ic, MSN_BUDDY_AL, who, who, NULL );
    275281}
    276282
    277283static void msn_rem_permit( struct im_connection *ic, char *who )
    278284{
    279         msn_buddy_list_remove( ic, "AL", who, NULL );
     285        msn_buddy_list_remove( ic, MSN_BUDDY_AL, who, NULL );
    280286}
    281287
     
    284290        struct msn_switchboard *sb;
    285291       
    286         msn_buddy_list_add( ic, "BL", who, who, NULL );
     292        msn_buddy_list_add( ic, MSN_BUDDY_BL, who, who, NULL );
    287293       
    288294        /* If there's still a conversation with this person, close it. */
     
    295301static void msn_rem_deny( struct im_connection *ic, char *who )
    296302{
    297         msn_buddy_list_remove( ic, "BL", who, NULL );
     303        msn_buddy_list_remove( ic, MSN_BUDDY_BL, who, NULL );
    298304}
    299305
     
    314320        account_t *acc = set->data;
    315321        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;
    320323       
    321324        if( strlen( value ) > 129 )
     
    325328        }
    326329       
    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
     338static 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
     345static 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 );
    331350}
    332351
     
    344363        ret->set_away = msn_set_away;
    345364        ret->get_info = msn_get_info;
    346         ret->set_my_name = msn_set_my_name;
    347365        ret->add_buddy = msn_add_buddy;
    348366        ret->remove_buddy = msn_remove_buddy;
     
    358376        ret->send_typing = msn_send_typing;
    359377        ret->handle_cmp = g_strcasecmp;
     378        ret->buddy_data_add = msn_buddy_data_add;
     379        ret->buddy_data_free = msn_buddy_data_free;
     380       
    360381        //ret->transfer_request = msn_ftp_transfer_request;
    361382
  • protocols/msn/msn.h

    r3ad8036 r508588a  
    22  * BitlBee -- An IRC to other IM-networks gateway                     *
    33  *                                                                    *
    4   * Copyright 2002-2004 Wilmer van der Gaast and others                *
     4  * Copyright 2002-2010 Wilmer van der Gaast and others                *
    55  \********************************************************************/
    66
     
    3939#endif
    4040
    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"
    4358
    4459#define MSN_SB_NEW         -24062002
     
    6176#define PROFILE_URL "http://members.msn.com/"
    6277
     78typedef 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
     86struct 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
    63102struct msn_data
    64103{
    65104        struct im_connection *ic;
    66105       
    67         int fd;
    68         struct msn_handler_data *handler;
     106        struct msn_handler_data ns[1];
     107        msn_flags_t flags;
    69108       
    70109        int trId;
    71        
    72         GSList *msgq, *grpq;
     110        char *tokens[4];
     111        char *lock_key, *pp_policy;
     112       
     113        GSList *msgq, *grpq, *soapq;
    73114        GSList *switchboards;
    74115        int sb_failures;
    75116        time_t first_sb_failure;
    76         GSList *filetransfers;
    77117       
    78118        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;
    82126};
    83127
     
    86130        struct im_connection *ic;
    87131       
     132        /* The following two are also in the handler. TODO: Clean up. */
    88133        int fd;
    89134        gint inp;
     
    127172};
    128173
    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 );
     174typedef 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
     184struct msn_buddy_data
     185{
     186        char *cid;
     187        msn_buddy_flags_t flags;
     188};
     189
     190struct msn_group
     191{
     192        char *name;
     193        char *id;
    142194};
    143195
     
    161213
    162214/* ns.c */
    163 gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond );
     215int msn_ns_write( struct im_connection *ic, int fd, const char *fmt, ... );
     216gboolean msn_ns_connect( struct im_connection *ic, struct msn_handler_data *handler, const char *host, int port );
     217void msn_ns_close( struct msn_handler_data *handler );
     218void msn_auth_got_passport_token( struct im_connection *ic, const char *token, const char *error );
     219void msn_auth_got_contact_list( struct im_connection *ic );
     220int msn_ns_finish_login( struct im_connection *ic );
    164221
    165222/* msn_util.c */
    166 int msn_write( struct im_connection *ic, char *s, int len );
    167223int 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 );
     224int msn_buddy_list_add( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *realname_, const char *group );
     225int msn_buddy_list_remove( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group );
     226void msn_buddy_ask( bee_user_t *bu );
    171227char *msn_findheader( char *text, char *header, int len );
    172228char **msn_linesplit( char *line );
    173229int msn_handler( struct msn_handler_data *h );
    174 char *msn_http_encode( const char *input );
    175230void msn_msgq_purge( struct im_connection *ic, GSList **list );
    176 gboolean msn_set_display_name( struct im_connection *ic, const char *rawname );
     231char *msn_p11_challenge( char *challenge );
     232gint msn_domaintree_cmp( gconstpointer a_, gconstpointer b_ );
     233struct msn_group *msn_group_by_name( struct im_connection *ic, const char *name );
     234struct msn_group *msn_group_by_id( struct im_connection *ic, const char *id );
     235int msn_ns_set_display_name( struct im_connection *ic, const char *value );
    177236
    178237/* tables.c */
     
    183242
    184243/* sb.c */
    185 int msn_sb_write( struct msn_switchboard *sb, char *s, int len );
     244int msn_sb_write( struct msn_switchboard *sb, const char *fmt, ... );
    186245struct msn_switchboard *msn_sb_create( struct im_connection *ic, char *host, int port, char *key, int session );
    187246struct msn_switchboard *msn_sb_by_handle( struct im_connection *ic, char *handle );
     
    196255void msn_sb_stop_keepalives( struct msn_switchboard *sb );
    197256
    198 /* invitation.c */
    199 void msn_ftp_transfer_request( struct im_connection *ic, file_transfer_t *ft, char *who );
    200 
    201257#endif //_MSN_H
  • protocols/msn/msn_util.c

    r3ad8036 r508588a  
    22  * BitlBee -- An IRC to other IM-networks gateway                     *
    33  *                                                                    *
    4   * Copyright 2002-2004 Wilmer van der Gaast and others                *
     4  * Copyright 2002-2010 Wilmer van der Gaast and others                *
    55  \********************************************************************/
    66
     
    2626#include "nogaim.h"
    2727#include "msn.h"
     28#include "md5.h"
     29#include "soap.h"
    2830#include <ctype.h>
    2931
    30 int msn_write( struct im_connection *ic, char *s, int len )
     32int msn_logged_in( struct im_connection *ic )
     33{
     34        imcb_connected( ic );
     35       
     36        return( 0 );
     37}
     38
     39static 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
     53int msn_buddy_list_add( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *realname, const char *group )
    3154{
    3255        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;
    5760       
    5861        *groupid = '\0';
     62#if 0
    5963        if( group )
    6064        {
     
    8791                        if( l == NULL )
    8892                        {
    89                                 char *groupname = msn_http_encode( group );
     93                                char groupname[strlen(group)+1];
     94                                strcpy( groupname, group );
     95                                http_encode( groupname );
    9096                                g_snprintf( buf, sizeof( buf ), "ADG %d %s %d\r\n", ++md->trId, groupname, 0 );
    91                                 g_free( groupname );
    9297                                return msn_write( ic, buf, strlen( buf ) );
    9398                        }
     
    101106                }
    102107        }
    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
     134int msn_buddy_list_remove( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group )
    112135{
    113136        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;
    115141       
    116142        *groupid = '\0';
     143#if 0
    117144        if( group )
    118145        {
     
    125152                        }
    126153        }
    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;
    133177}
    134178
     
    144188        struct msn_buddy_ask_data *bla = data;
    145189       
    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 );
    147191       
    148192        imcb_ask_add( bla->ic, bla->handle, NULL );
     
    157201        struct msn_buddy_ask_data *bla = data;
    158202       
    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 );
    160204       
    161205        g_free( bla->handle );
     
    164208}
    165209
    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 );
     210void msn_buddy_ask( bee_user_t *bu )
     211{
     212        struct msn_buddy_ask_data *bla;
     213        struct msn_buddy_data *bd = bu->data;
    169214        char buf[1024];
    170215       
    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 );
    174223       
    175224        g_snprintf( buf, sizeof( buf ),
    176225                    "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 );
    179228}
    180229
     
    279328        if( st <= 0 )
    280329                return( -1 );
     330       
     331        if( getenv( "BITLBEE_DEBUG" ) )
     332        {
     333                write( 2, "->C:", 4 );
     334                write( 2, h->rxq + h->rxlen - st, st );
     335        }
    281336       
    282337        while( st )
     
    296351                                        cmd = msn_linesplit( cmd_text );
    297352                                        for( count = 0; cmd[count]; count ++ );
    298                                         st = h->exec_command( h->data, cmd, count );
     353                                        st = h->exec_command( h, cmd, count );
    299354                                        g_free( cmd_text );
    300355                                       
     
    331386                        for( count = 0; cmd[count]; count ++ );
    332387                       
    333                         st = h->exec_message( h->data, msg, h->msglen, cmd, count );
     388                        st = h->exec_message( h, msg, h->msglen, cmd, count );
    334389                        g_free( msg );
    335390                        g_free( h->cmd_text );
     
    367422}
    368423
    369 /* The difference between this function and the normal http_encode() function
    370    is that this one escapes every 7-bit ASCII character because this is said
    371    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 to
    373    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                 else
    387                 {
    388                         g_snprintf( s, 4, "%%%02X", input[i] );
    389                         s += 3;
    390                 }
    391        
    392         return ret;
    393 }
    394 
    395424void msn_msgq_purge( struct im_connection *ic, GSList **list )
    396425{
     
    433462}
    434463
    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 */
     465char *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
     535gint 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
     547struct msn_group *msn_group_by_name( struct im_connection *ic, const char *name )
     548{
    438549        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
     563struct 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
     579int 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

    r3ad8036 r508588a  
    22  * BitlBee -- An IRC to other IM-networks gateway                     *
    33  *                                                                    *
    4   * Copyright 2002-2004 Wilmer van der Gaast and others                *
     4  * Copyright 2002-2010 Wilmer van der Gaast and others                *
    55  \********************************************************************/
    66
     
    2727#include "nogaim.h"
    2828#include "msn.h"
    29 #include "passport.h"
    3029#include "md5.h"
    31 
     30#include "soap.h"
     31#include "xmltree.h"
     32
     33static gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond );
    3234static 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 )
     35static int msn_ns_command( struct msn_handler_data *handler, char **cmd, int num_parts );
     36static int msn_ns_message( struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts );
     37
     38static void msn_ns_send_adl_start( struct im_connection *ic );
     39static void msn_ns_send_adl( struct im_connection *ic );
     40
     41int 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
     72gboolean 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 )
    4982        {
    5083                imcb_error( ic, "Could not connect to server" );
     
    5386        }
    5487       
     88        return TRUE;
     89}
     90
     91static 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       
    55100        md = ic->proto_data;
    56101       
    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 );
    79116                imcb_log( ic, "Connected to server, waiting for reply" );
    80117        }
     
    83120}
    84121
     122void 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
    85139static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition cond )
    86140{
    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. */
    91145        {
    92146                imcb_error( ic, "Error while reading from server" );
     
    99153}
    100154
    101 static int msn_ns_command( gpointer data, char **cmd, int num_parts )
    102 {
    103         struct im_connection *ic = data;
     155static int msn_ns_command( struct msn_handler_data *handler, char **cmd, int num_parts )
     156{
     157        struct im_connection *ic = handler->data;
    104158        struct msn_data *md = ic->proto_data;
    105         char buf[1024];
    106159       
    107160        if( num_parts == 0 )
     
    113166        if( strcmp( cmd[0], "VER" ) == 0 )
    114167        {
    115                 if( cmd[2] && strncmp( cmd[2], "MSNP8", 5 ) != 0 )
     168                if( cmd[2] && strncmp( cmd[2], MSNP_VER, 5 ) != 0 )
    116169                {
    117170                        imcb_error( ic, "Unsupported protocol" );
     
    120173                }
    121174               
    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 ) );
    125177        }
    126178        else if( strcmp( cmd[0], "CVR" ) == 0 )
    127179        {
    128180                /* 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 );
    131182        }
    132183        else if( strcmp( cmd[0], "XFR" ) == 0 )
     
    135186                int port;
    136187               
    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;
    142192                       
    143193                        server = strchr( cmd[3], ':' );
     
    153203                       
    154204                        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 )
    159208                {
    160209                        struct msn_switchboard *sb;
     
    220269        else if( strcmp( cmd[0], "USR" ) == 0 )
    221270        {
    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                {
    239280                        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 );
    243282                }
    244283                else
     
    251290        else if( strcmp( cmd[0], "MSG" ) == 0 )
    252291        {
    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 );
    372328        }
    373329        else if( strcmp( cmd[0], "CHL" ) == 0 )
    374330        {
    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;
    396348        }
    397349        else if( strcmp( cmd[0], "ILN" ) == 0 )
     
    399351                const struct msn_away_state *st;
    400352               
    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] );
    410362               
    411363                st = msn_away_state_by_code( cmd[2] );
     
    432384        {
    433385                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] );
    444398               
    445399                st = msn_away_state_by_code( cmd[1] );
     
    451405               
    452406                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 ),
    454409                                   st->name, NULL );
    455410               
     
    462417                int session, port;
    463418               
    464                 if( num_parts != 7 )
     419                if( num_parts < 7 )
    465420                {
    466421                        imcb_error( ic, "Syntax error" );
     
    504459                }
    505460        }
    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 this
    522                            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         }
    546461        else if( strcmp( cmd[0], "OUT" ) == 0 )
    547462        {
     
    565480                return( 0 );
    566481        }
     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        }
    567495#if 0
    568         /* Discard this one completely for now since I don't care about the ack
    569            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                 else
    594                 {
    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 #endif
    601         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         }
    614496        else if( strcmp( cmd[0], "ADG" ) == 0 )
    615497        {
     
    656538                }
    657539        }
     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        }
    658560        else if( isdigit( cmd[0][0] ) )
    659561        {
     
    668570                        return( 0 );
    669571                }
     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] );
    670576        }
    671577        else
     
    677583}
    678584
    679 static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts )
    680 {
    681         struct im_connection *ic = data;
     585static 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;
    682588        char *body;
    683589        int blen = 0;
     
    765671                }
    766672        }
     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        }
    767736       
    768737        return( 1 );
    769738}
    770739
    771 static void msn_auth_got_passport_token( struct msn_auth_data *mad )
    772 {
    773         struct im_connection *ic = mad->data;
     740void msn_auth_got_passport_token( struct im_connection *ic, const char *token, const char *error )
     741{
    774742        struct msn_data *md;
    775743       
     
    779747       
    780748        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 );
    787753        }
    788754        else
    789755        {
    790                 imcb_error( ic, "Error during Passport authentication: %s", mad->error );
     756                imcb_error( ic, "Error during Passport authentication: %s", error );
    791757                imc_logout( ic, TRUE );
    792758        }
    793759}
    794760
    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         }
     761void 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
     773static 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
     812static 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
     834static 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
     860int 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" ) );
    818872        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

    r3ad8036 r508588a  
    22  * BitlBee -- An IRC to other IM-networks gateway                     *
    33  *                                                                    *
    4   * Copyright 2002-2005 Wilmer van der Gaast and others                *
     4  * Copyright 2002-2010 Wilmer van der Gaast and others                *
    55  \********************************************************************/
    66
     
    2727#include "nogaim.h"
    2828#include "msn.h"
    29 #include "passport.h"
    3029#include "md5.h"
     30#include "soap.h"
    3131#include "invitation.h"
    3232
    3333static 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 {
     34static int msn_sb_command( struct msn_handler_data *handler, char **cmd, int num_parts );
     35static int msn_sb_message( struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts );
     36
     37int msn_sb_write( struct msn_switchboard *sb, const char *fmt, ... )
     38{
     39        va_list params;
     40        char *out;
     41        size_t len;
    3942        int st;
    4043       
    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 );
    4254        if( st != len )
    4355        {
    4456                msn_sb_destroy( sb );
    45                 return( 0 );
    46         }
    47        
    48         return( 1 );
     57                return 0;
     58        }
     59       
     60        return 1;
    4961}
    5062
     
    5365        struct msn_data *md = ic->proto_data;
    5466        struct msn_switchboard *sb;
    55         char buf[1024];
    5667
    5768        /* FIXME: *CHECK* the reliability of using spare sb's! */
     
    6172               
    6273                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 ) )
    6575                {
    6676                        /* He/She should join the switchboard soon, let's queue the message. */
     
    7383       
    7484        /* 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 ) )
    7786        {
    7887                g_free( m->who );
     
    165174        if( sb->ready )
    166175        {
    167                 char *packet, *buf;
     176                char *buf;
    168177                int i, j;
    169178               
     
    201210               
    202211                /* 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;
    209216                }
    210217                else
    211218                {
    212                         g_free( packet );
    213                         return( 0 );
     219                        g_free( buf );
     220                        return 0;
    214221                }
    215222        }
     
    326333                g_snprintf( buf, sizeof( buf ), "ANS %d %s %s %d\r\n", ++sb->trId, ic->acc->user, sb->key, sb->session );
    327334       
    328         if( msn_sb_write( sb, buf, strlen( buf ) ) )
     335        if( msn_sb_write( sb, "%s", buf ) )
    329336                sb->inp = b_input_add( sb->fd, B_EV_IO_READ, msn_sb_callback, sb );
    330337        else
     
    346353        {
    347354                time_t now = time( NULL );
    348                 char buf[1024];
    349355               
    350356                if( now - md->first_sb_failure > 600 )
     
    378384                debug( "Moved queued messages back to the main queue, "
    379385                       "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 ) )
    382387                        return FALSE;
    383388        }
     
    387392}
    388393
    389 static int msn_sb_command( gpointer data, char **cmd, int num_parts )
    390 {
    391         struct msn_switchboard *sb = data;
     394static int msn_sb_command( struct msn_handler_data *handler, char **cmd, int num_parts )
     395{
     396        struct msn_switchboard *sb = handler->data;
    392397        struct im_connection *ic = sb->ic;
    393         char buf[1024];
    394398       
    395399        if( !num_parts )
     
    407411        else if( strcmp( cmd[0], "USR" ) == 0 )
    408412        {
    409                 if( num_parts != 5 )
     413                if( num_parts < 5 )
    410414                {
    411415                        msn_sb_destroy( sb );
     
    420424               
    421425                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 );
    426427                else
    427                 {
    428428                        debug( "Just created a switchboard, but I don't know what to do with it." );
    429                 }
    430429        }
    431430        else if( strcmp( cmd[0], "IRO" ) == 0 )
     
    433432                int num, tot;
    434433               
    435                 if( num_parts != 6 )
     434                if( num_parts < 6 )
    436435                {
    437436                        msn_sb_destroy( sb );
     
    470469        else if( strcmp( cmd[0], "ANS" ) == 0 )
    471470        {
    472                 if( num_parts != 3 )
     471                if( num_parts < 3 )
    473472                {
    474473                        msn_sb_destroy( sb );
     
    489488        else if( strcmp( cmd[0], "CAL" ) == 0 )
    490489        {
    491                 if( num_parts != 4 || !isdigit( cmd[3][0] ) )
     490                if( num_parts < 4 || !isdigit( cmd[3][0] ) )
    492491                {
    493492                        msn_sb_destroy( sb );
     
    499498        else if( strcmp( cmd[0], "JOI" ) == 0 )
    500499        {
    501                 if( num_parts != 3 )
     500                if( num_parts < 3 )
    502501                {
    503502                        msn_sb_destroy( sb );
     
    560559        else if( strcmp( cmd[0], "MSG" ) == 0 )
    561560        {
    562                 if( num_parts != 4 )
     561                if( num_parts < 4 )
    563562                {
    564563                        msn_sb_destroy( sb );
     
    625624                const struct msn_status_code *err = msn_status_by_number( num );
    626625               
    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 );
    628632               
    629633                if( err->flags & STATUS_SB_FATAL )
     
    661665}
    662666
    663 static int msn_sb_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts )
    664 {
    665         struct msn_switchboard *sb = data;
     667static 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;
    666670        struct im_connection *ic = sb->ic;
    667671        char *body;
     
    741745                else if( g_strncasecmp( ct, "application/x-msnmsgrp2p", 24 ) == 0 )
    742746                {
    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. */
    745749                        g_free( ct );
    746750                }
  • protocols/msn/tables.c

    r3ad8036 r508588a  
    22  * BitlBee -- An IRC to other IM-networks gateway                     *
    33  *                                                                    *
    4   * Copyright 2002-2004 Wilmer van der Gaast and others                *
     4  * Copyright 2002-2010 Wilmer van der Gaast and others                *
    55  \********************************************************************/
    66
     
    8383        { 230, "Cannot remove that group",                              0 },
    8484        { 231, "Invalid group",                                         0 },
     85        { 240, "ADL/RML command with corrupted payload",                STATUS_FATAL },
     86        { 241, "ADL/RML command with invalid modification",             0 },
    8587        { 280, "Switchboard failed",                                    STATUS_SB_FATAL },
    8688        { 281, "Transfer to switchboard failed",                        0 },
  • protocols/nogaim.c

    r3ad8036 r508588a  
    252252                serv_got_crap( ic, "Error: %s", text );
    253253        else
    254                 serv_got_crap( ic, "Couldn't log in: %s", text );
     254                serv_got_crap( ic, "Login error: %s", text );
    255255       
    256256        g_free( text );
     
    325325       
    326326        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;
    335327       
    336328        for( l = bee->users; l; )
     
    344336                l = next;
    345337        }
     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;
    346346       
    347347        query_del_by_conn( (irc_t*) ic->bee->ui_data, ic );
  • protocols/nogaim.h

    r3ad8036 r508588a  
    200200           this info via imcb_log(). Implementing these are optional. */
    201201        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. */
    202204        void (* set_my_name)    (struct im_connection *, char *name);
    203205        void (* set_name)       (struct im_connection *, char *who, char *name);
  • protocols/oscar/ssi.c

    r3ad8036 r508588a  
    415415                if (!parentgroup) {
    416416                        char *newgroup;
    417                         newgroup = (char*)g_malloc(strlen("Unknown")*sizeof(char));
     417                        newgroup = (char*)g_malloc(strlen("Unknown")+1);
    418418                        strcpy(newgroup, "Unknown");
    419419                        aim_ssi_addgroups(sess, conn, &newgroup, 1);
  • protocols/purple/purple.c

    r3ad8036 r508588a  
    8080        char help_title[64];
    8181        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        }
    82104       
    83105        help = g_string_new( "" );
     
    254276        PurpleAccount *pa;
    255277       
    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" ) ) )
    257280        {
    258281                imcb_error( ic,  "Daemon mode detected. Do *not* try to use libpurple in daemon mode! "
     
    351374        account_t *acc = set->data;
    352375        struct im_connection *ic = acc->ic;
     376       
     377        if( ic )
     378                imcb_log( ic, "Changing display_name not currently supported with libpurple!" );
    353379       
    354380        return NULL;
     
    517543}
    518544
    519 struct groupchat *purple_chat_join( struct im_connection *ic, const char *room, const char *nick, const char *password )
     545struct groupchat *purple_chat_join( struct im_connection *ic, const char *room, const char *nick, const char *password, set_t **sets )
    520546{
    521547        PurpleAccount *pa = ic->proto_data;
     
    11321158        GList *prots;
    11331159        GString *help;
     1160        char *dir;
    11341161       
    11351162        if( B_EV_IO_READ != PURPLE_INPUT_READ ||
     
    11401167        }
    11411168       
    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       
    11431173        purple_debug_set_enabled( FALSE );
    11441174        purple_core_set_ui_ops( &bee_core_uiops );
     
    11511181        }
    11521182       
    1153         /* This seems like stateful shit we don't want... */
    11541183        purple_set_blist( purple_blist_new() );
    1155         purple_blist_load();
    1156        
    1157         /* Meh? */
    1158         purple_prefs_load();
    11591184       
    11601185        /* No, really. So far there were ui_ops for everything, but now suddenly
     
    12211246       
    12221247        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!)" );
    12241250       
    12251251        /* Add a simple dynamically-generated help item listing all
  • protocols/twitter/twitter.c

    r3ad8036 r508588a  
    2929#include "url.h"
    3030
     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
    3141/**
    3242 * Main loop function
     
    436446                if( id )
    437447                        twitter_status_destroy( ic, id );
     448                else
     449                        twitter_msg( ic, "Could not undo last action" );
    438450               
    439451                g_free( cmds );
     
    467479                if( id )
    468480                        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] );
    469484               
    470485                g_free( cmds );
  • root_commands.c

    r3ad8036 r508588a  
    12931293{
    12941294        int last = set_getint( &irc->b->set, "last_version" );
    1295         GString *msg = g_string_new( "" );
    1296         char s[16];
     1295        char s[16], *msg;
    12971296       
    12981297        if( last >= BITLBEE_VERSION_CODE )
    12991298                return;
    13001299       
    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 )
    13201303                irc_usermsg( irc, "%s: This seems to be your first time using this "
    13211304                                  "this version of BitlBee. Here's a list of new "
    13221305                                  "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       
    13261310        g_snprintf( s, sizeof( s ), "%d", BITLBEE_VERSION_CODE );
    13271311        set_setstr( &irc->b->set, "last_version", s );
  • sock.h

    r3ad8036 r508588a  
    1111#define sock_make_blocking(fd) fcntl(fd, F_SETFL, 0)
    1212#define sockerr_again() (errno == EINPROGRESS || errno == EINTR)
    13 #ifndef EVENTS_LIBEVENT
    14 #define closesocket(a) close(a)
    15 #else
    1613void closesocket( int fd );
    17 #endif
    1814#else
    1915# include <winsock2.h>
  • storage_xml.c

    r3ad8036 r508588a  
    320320        else if( g_strcasecmp( g_markup_parse_context_get_element( ctx ), "setting" ) == 0 && xd->current_setting )
    321321        {
     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                }
    322332                set_setstr( xd->current_set_head, xd->current_setting, (char*) text );
    323333                g_free( xd->current_setting );
  • unix.c

    r3ad8036 r508588a  
    181181                   doesn't make a copy. Odd. */
    182182               
    183                 chdir( old_cwd );
     183                i = chdir( old_cwd );
    184184                close( global.listen_socket );
    185185               
Note: See TracChangeset for help on using the changeset viewer.