Changes in / [c6ca3ee:fb00989]


Ignore:
Files:
3 added
64 edited

Legend:

Unmodified
Added
Removed
  • Makefile

    rc6ca3ee rfb00989  
    1010
    1111# Program variables
    12 objects = account.o bitlbee.o crypting.o help.o ipc.o irc.o irc_commands.o nick.o query.o root_commands.o set.o storage.o $(STORAGE_OBJS) user.o
     12objects = account.o bitlbee.o chat.o crypting.o help.o ipc.o irc.o irc_commands.o nick.o query.o root_commands.o set.o storage.o $(STORAGE_OBJS) user.o
    1313headers = account.h bitlbee.h commands.h conf.h config.h crypting.h help.h ipc.h irc.h log.h nick.h query.h set.h sock.h storage.h user.h lib/events.h lib/http_client.h lib/ini.h lib/md5.h lib/misc.h lib/proxy.h lib/sha1.h lib/ssl_client.h lib/url.h protocols/nogaim.h
    1414subdirs = lib protocols
     
    4949
    5050clean: $(subdirs)
    51         rm -f *.o $(OUTFILE) core utils/bitlbeed encode decode
     51        rm -f *.o $(OUTFILE) core utils/bitlbeed
    5252        $(MAKE) -C tests clean
    5353
     
    105105        x=$$(basename $$(pwd)); \
    106106        cd ..; \
    107         tar czf $$x.tar.gz --exclude=debian --exclude=.bzr $$x
     107        tar czf $$x.tar.gz --exclude=debian --exclude=.bzr* $$x
    108108
    109109$(subdirs):
     
    124124endif
    125125
    126 encode: crypting.c
    127         $(CC) crypting.c lib/md5.c $(CFLAGS) -o encode -DCRYPTING_MAIN $(CFLAGS) $(EFLAGS) $(LFLAGS)
    128 
    129 decode: encode
    130         cp encode decode
    131 
    132126ctags:
    133127        ctags `find . -name "*.c"` `find . -name "*.h"`
  • account.c

    rc6ca3ee rfb00989  
    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 "bitlbee.h"
    2828#include "account.h"
     29#include "chat.h"
    2930
    3031account_t *account_add( irc_t *irc, struct prpl *prpl, char *user, char *pass )
     
    5455        s = set_add( &a->set, "auto_reconnect", "true", set_eval_bool, a );
    5556       
     57        s = set_add( &a->set, "nick_source", "handle", NULL, a );
     58       
    5659        s = set_add( &a->set, "password", NULL, set_eval_account, a );
    57         s->flags |= ACC_SET_NOSAVE;
     60        s->flags |= ACC_SET_NOSAVE | SET_NULL_OK;
    5861       
    5962        s = set_add( &a->set, "username", NULL, set_eval_account, a );
     
    6871                prpl->init( a );
    6972       
    70         return( a );
     73        s = set_add( &a->set, "away", NULL, set_eval_account, a );
     74        s->flags |= SET_NULL_OK;
     75       
     76        if( a->flags & ACC_FLAG_STATUS_MESSAGE )
     77        {
     78                s = set_add( &a->set, "status", NULL, set_eval_account, a );
     79                s->flags |= SET_NULL_OK;
     80        }
     81       
     82        return a;
    7183}
    7284
     
    7789        /* Double-check: We refuse to edit on-line accounts. */
    7890        if( set->flags & ACC_SET_OFFLINE_ONLY && acc->ic )
    79                 return NULL;
    80        
    81         if( strcmp( set->key, "username" ) == 0 )
     91                return SET_INVALID;
     92       
     93        if( strcmp( set->key, "server" ) == 0 )
     94        {
     95                g_free( acc->server );
     96                if( value && *value )
     97                {
     98                        acc->server = g_strdup( value );
     99                        return value;
     100                }
     101                else
     102                {
     103                        acc->server = g_strdup( set->def );
     104                        return g_strdup( set->def );
     105                }
     106        }
     107        else if( strcmp( set->key, "username" ) == 0 )
    82108        {
    83109                g_free( acc->user );
     
    87113        else if( strcmp( set->key, "password" ) == 0 )
    88114        {
    89                 g_free( acc->pass );
    90                 acc->pass = g_strdup( value );
    91                 return NULL;    /* password shouldn't be visible in plaintext! */
    92         }
    93         else if( strcmp( set->key, "server" ) == 0 )
    94         {
    95                 g_free( acc->server );
    96                 if( *value )
    97                 {
    98                         acc->server = g_strdup( value );
    99                         return value;
     115                if( value )
     116                {
     117                        g_free( acc->pass );
     118                        acc->pass = g_strdup( value );
     119                        return NULL;    /* password shouldn't be visible in plaintext! */
    100120                }
    101121                else
    102122                {
    103                         acc->server = NULL;
    104                         return g_strdup( set->def );
     123                        /* NULL can (should) be stored in the set_t
     124                           variable, but is otherwise not correct. */
     125                        return SET_INVALID;
    105126                }
    106127        }
     
    108129        {
    109130                if( !is_bool( value ) )
    110                         return NULL;
     131                        return SET_INVALID;
    111132               
    112133                acc->auto_connect = bool2int( value );
    113134                return value;
    114135        }
    115        
    116         return NULL;
     136        else if( strcmp( set->key, "away" ) == 0 ||
     137                 strcmp( set->key, "status" ) == 0 )
     138        {
     139                if( acc->ic && acc->ic->flags & OPT_LOGGED_IN )
     140                {
     141                        /* If we're currently on-line, set the var now already
     142                           (bit of a hack) and send an update. */
     143                        g_free( set->value );
     144                        set->value = g_strdup( value );
     145                       
     146                        imc_away_send_update( acc->ic );
     147                }
     148               
     149                return value;
     150        }
     151       
     152        return SET_INVALID;
    117153}
    118154
     
    181217{
    182218        account_t *a, *l = NULL;
     219        struct chat *c, *nc;
    183220       
    184221        if( acc->ic )
     
    193230                        else
    194231                                irc->accounts = a->next;
     232                       
     233                        for( c = irc->chatrooms; c; c = nc )
     234                        {
     235                                nc = c->next;
     236                                if( acc == c->acc )
     237                                        chat_del( irc, c );
     238                        }
    195239                       
    196240                        while( a->set )
     
    234278        }
    235279}
     280
     281struct account_reconnect_delay
     282{
     283        int start;
     284        char op;
     285        int step;
     286        int max;
     287};
     288
     289int account_reconnect_delay_parse( char *value, struct account_reconnect_delay *p )
     290{
     291        memset( p, 0, sizeof( *p ) );
     292        /* A whole day seems like a sane "maximum maximum". */
     293        p->max = 86400;
     294       
     295        /* Format: /[0-9]+([*+][0-9]+(<[0-9+])?)?/ */
     296        while( *value && isdigit( *value ) )
     297                p->start = p->start * 10 + *value++ - '0';
     298       
     299        /* Sure, call me evil for implementing my own fscanf here, but it's
     300           dead simple and I immediately know where to continue parsing. */
     301       
     302        if( *value == 0 )
     303                /* If the string ends now, the delay is constant. */
     304                return 1;
     305        else if( *value != '+' && *value != '*' )
     306                /* Otherwise allow either a + or a * */
     307                return 0;
     308       
     309        p->op = *value++;
     310       
     311        /* + or * the delay by this number every time. */
     312        while( *value && isdigit( *value ) )
     313                p->step = p->step * 10 + *value++ - '0';
     314       
     315        if( *value == 0 )
     316                /* Use the default maximum (one day). */
     317                return 1;
     318        else if( *value != '<' )
     319                return 0;
     320       
     321        p->max = 0;
     322        value ++;
     323        while( *value && isdigit( *value ) )
     324                p->max = p->max * 10 + *value++ - '0';
     325       
     326        return p->max > 0;
     327}
     328
     329char *set_eval_account_reconnect_delay( set_t *set, char *value )
     330{
     331        struct account_reconnect_delay p;
     332       
     333        return account_reconnect_delay_parse( value, &p ) ? value : SET_INVALID;
     334}
     335
     336int account_reconnect_delay( account_t *a )
     337{
     338        char *setting = set_getstr( &a->irc->set, "auto_reconnect_delay" );
     339        struct account_reconnect_delay p;
     340       
     341        if( account_reconnect_delay_parse( setting, &p ) )
     342        {
     343                if( a->auto_reconnect_delay == 0 )
     344                        a->auto_reconnect_delay = p.start;
     345                else if( p.op == '+' )
     346                        a->auto_reconnect_delay += p.step;
     347                else if( p.op == '*' )
     348                        a->auto_reconnect_delay *= p.step;
     349               
     350                if( a->auto_reconnect_delay > p.max )
     351                        a->auto_reconnect_delay = p.max;
     352        }
     353        else
     354        {
     355                a->auto_reconnect_delay = 0;
     356        }
     357       
     358        return a->auto_reconnect_delay;
     359}
  • account.h

    rc6ca3ee rfb00989  
    3535       
    3636        int auto_connect;
     37        int auto_reconnect_delay;
    3738        int reconnect;
     39        int flags;
    3840       
    3941        set_t *set;
     
    5254
    5355char *set_eval_account( set_t *set, char *value );
     56char *set_eval_account_reconnect_delay( set_t *set, char *value );
     57int account_reconnect_delay( account_t *a );
    5458
    55 #define ACC_SET_NOSAVE          1
    56 #define ACC_SET_OFFLINE_ONLY    2
    57 #define ACC_SET_ONLINE_ONLY     4
     59typedef enum
     60{
     61        ACC_SET_NOSAVE = 0x01,          /* Don't save this setting (i.e. stored elsewhere). */
     62        ACC_SET_OFFLINE_ONLY = 0x02,    /* Allow changes only if the acct is offline. */
     63        ACC_SET_ONLINE_ONLY = 0x04,     /* Allow changes only if the acct is online. */
     64} account_set_flag_t;
     65
     66typedef enum
     67{
     68        ACC_FLAG_AWAY_MESSAGE = 0x01,   /* Supports away messages instead of just states. */
     69        ACC_FLAG_STATUS_MESSAGE = 0x02, /* Supports status messages (without being away). */
     70} account_flag_t;
    5871
    5972#endif
  • bitlbee.c

    rc6ca3ee rfb00989  
    109109                chdir( "/" );
    110110               
    111                 /* Sometimes std* are already closed (for example when we're in a RESTARTed
    112                    BitlBee process. So let's only close TTY-fds. */
    113                 if( isatty( 0 ) ) close( 0 );
    114                 if( isatty( 1 ) ) close( 1 );
    115                 if( isatty( 2 ) ) close( 2 );
     111                i = close( 0 ) == 0;
     112                i += close( 1 ) == 0;
     113                i += close( 2 ) == 0;
     114                /* To avoid that something important ends up on one of those
     115                   fd's, open them for something bogus. Otherwise RESTART
     116                   may cause troubles. */
     117                while( i > 0 )
     118                {
     119                        open( "/dev/null", O_WRONLY );
     120                        i --;
     121                }
    116122        }
    117123#endif
  • bitlbee.conf

    rc6ca3ee rfb00989  
    5555##
    5656## Password the user should enter when logging into a closed BitlBee server.
    57 ## You can also have an MD5-encrypted password here. Format: "md5:", followed
    58 ## by a hash as generated for the <user password=""> attribute in a BitlBee
    59 ## XML file (for now there's no easier way to generate the hash).
     57## You can also have a BitlBee-style MD5 hash here. Format: "md5:", followed
     58## by a hash as generated by "bitlbee -x hash <password>".
    6059##
    6160# AuthPassword = ItllBeBitlBee   ## Heh.. Our slogan. ;-)
  • bitlbee.h

    rc6ca3ee rfb00989  
    3535
    3636#define PACKAGE "BitlBee"
    37 #define BITLBEE_VERSION "1.2.1"
     37#define BITLBEE_VERSION "1.2.4"
    3838#define VERSION BITLBEE_VERSION
    3939
  • conf.c

    rc6ca3ee rfb00989  
    7878        }
    7979       
    80         while( argc > 0 && ( opt = getopt( argc, argv, "i:p:P:nvIDFc:d:hu:" ) ) >= 0 )
     80        while( argc > 0 && ( opt = getopt( argc, argv, "i:p:P:nvIDFc:d:hR:u:" ) ) >= 0 )
    8181        /*     ^^^^ Just to make sure we skip this step from the REHASH handler. */
    8282        {
     
    127127                {
    128128                        printf( "Usage: bitlbee [-D/-F [-i <interface>] [-p <port>] [-n] [-v]] [-I]\n"
    129                                 "               [-c <file>] [-d <dir>] [-h]\n"
     129                                "               [-c <file>] [-d <dir>] [-x] [-h]\n"
    130130                                "\n"
    131131                                "An IRC-to-other-chat-networks gateway\n"
     
    143143                                "  -c  Load alternative configuration file\n"
    144144                                "  -d  Specify alternative user configuration directory\n"
     145                                "  -x  Command-line interface to password encryption/hashing\n"
    145146                                "  -h  Show this help page.\n" );
    146147                        return NULL;
     148                }
     149                else if( opt == 'R' )
     150                {
     151                        /* Backward compatibility; older BitlBees passed this
     152                           info using a command-line flag. Allow people to
     153                           upgrade from such a version for now. */
     154                        setenv( "_BITLBEE_RESTART_STATE", optarg, 0 );
    147155                }
    148156                else if( opt == 'u' )
     
    301309                        else
    302310                        {
    303                                 fprintf( stderr, "Error: Unknown setting `%s` in configuration file.\n", ini->key );
     311                                fprintf( stderr, "Error: Unknown setting `%s` in configuration file (line %d).\n", ini->key, ini->line );
    304312                                return 0;
    305313                                /* For now just ignore unknown keys... */
     
    308316                else if( g_strcasecmp( ini->section, "defaults" ) != 0 )
    309317                {
    310                         fprintf( stderr, "Error: Unknown section [%s] in configuration file. "
    311                                          "BitlBee configuration must be put in a [settings] section!\n", ini->section );
     318                        fprintf( stderr, "Error: Unknown section [%s] in configuration file (line %d). "
     319                                         "BitlBee configuration must be put in a [settings] section!\n", ini->section, ini->line );
    312320                        return 0;
    313321                }
  • configure

    rc6ca3ee rfb00989  
    267267detect_ldap()
    268268{
    269         TMPFILE=`mktemp`
     269        TMPFILE=$(mktemp)
    270270        if $CC -o $TMPFILE -shared -lldap 2>/dev/null >/dev/null; then
    271271                cat<<EOF>>Makefile.settings
     
    280280                ret=0
    281281        fi
     282}
     283
     284RESOLV_TESTCODE='
     285#include <arpa/nameser.h>
     286#include <resolv.h>
     287
     288int main()
     289{
     290        ns_initparse( NULL, 0, NULL );
     291        ns_parserr( NULL, ns_s_an, 0, NULL );
     292}
     293'
     294
     295detect_resolv_dynamic()
     296{
     297        echo "$RESOLV_TESTCODE" | $CC -o /dev/null -x c - -lresolv >/dev/null 2>/dev/null
     298        if [ "$?" = "0" ]; then
     299                echo 'EFLAGS+=-lresolv' >> Makefile.settings
     300                return 0
     301        fi
     302
     303        return 1
     304}
     305
     306detect_resolv_static()
     307{
     308        for i in $systemlibdirs; do
     309                if [ -f $i/libresolv.a ]; then
     310                        echo "$RESOLV_TESTCODE" | $CC -o /dev/null -x c - -Wl,$i/libresolv.a >/dev/null 2>/dev/null
     311                        if [ "$?" = "0" ]; then
     312                                echo 'EFLAGS+='$i'/libresolv.a' >> Makefile.settings
     313                                return 0
     314                        fi
     315                fi
     316        done
     317
     318        return 1
    282319}
    283320
     
    323360       
    324361        ## Yes, you, at the console! How can you authenticate if you don't have any SSL!?
    325         if [ "$msn" = "1" ]; then
     362        if [ "$msn" = "1" -o "$yahoo" = "1" ]; then
    326363                echo
    327                 echo 'Real SSL support is necessary for MSN authentication, will build without'
    328                 echo 'MSN protocol support.'
     364                echo 'WARNING: The MSN and Yahoo! modules will not work without SSL. Disabling.'
    329365                msn=0
     366                yahoo=0
    330367        fi
    331368       
     
    349386echo 'SSL_CLIENT=ssl_'$ssl'.o' >> Makefile.settings
    350387
    351 for i in $systemlibdirs; do
    352         if [ -f $i/libresolv.a ]; then
    353                 echo '#define HAVE_RESOLV_A' >> config.h
    354                 echo 'EFLAGS+='$i'/libresolv.a' >> Makefile.settings
    355                 break
    356         fi
    357 done
     388if detect_resolv_dynamic || detect_resolv_static; then
     389        echo '#define HAVE_RESOLV_A' >> config.h
     390fi
    358391
    359392STORAGES="text xml"
     
    496529;;
    497530Darwin )
     531        echo 'STRIP=\# skip strip' >> Makefile.settings
    498532;;
    499533IRIX )
  • crypting.c

    rc6ca3ee rfb00989  
    132132        return (rv);
    133133}
    134 
    135 #ifdef CRYPTING_MAIN
    136 
    137 /* A little main() function for people who want a stand-alone program to
    138    encode/decode BitlCrypted files. */
    139 
    140 int main( int argc, char *argv[] )
    141 {
    142         char *hash, *action, line[256];
    143         char* (*func)( char *, const char * );
    144        
    145         if( argc < 2 )
    146         {
    147                 fprintf( stderr, "Usage: %s <password>\n\n"
    148                                  "Reads from stdin, writes to stdout.\n"
    149                                  "Call as \"encode\" to encode, \"decode\" to decode.\n", argv[0] );
    150                 return( 1 );
    151         }
    152        
    153         hash = hashpass( argv[1] );
    154         action = argv[0] + strlen( argv[0] ) - strlen( "encode" );
    155        
    156         if( strcmp( action, "encode" ) == 0 )
    157         {
    158                 fwrite( hash, 32, 1, stdout );
    159                 func = obfucrypt;
    160         }
    161         else if( strcmp( action, "decode" ) == 0 )
    162         {
    163                 char hash2[32];
    164                
    165                 fread( hash2, 32, 1, stdin );
    166                 if( memcmp( hash, hash2, 32 ) != 0 )
    167                 {
    168                         fprintf( stderr, "Passwords don't match. Can't decode.\n" );
    169                         return( 1 );
    170                 }
    171                 func = deobfucrypt;
    172         }
    173         else
    174         {
    175                 return( main( 0, NULL ) );
    176         }
    177        
    178         while( fscanf( stdin, "%[^\n]255s", line ) > 0 )
    179         {
    180                 char *out;
    181                
    182                 /* Flush the newline */
    183                 fgetc( stdin );
    184                
    185                 out = func( line, argv[1] );
    186                 printf( "%s\n", out );
    187                 g_free( out );
    188         }
    189        
    190         return( 0 );
    191 }
    192 
    193 #endif
  • debian/bitlbee.init

    rc6ca3ee rfb00989  
    3232fi
    3333
    34 [ "$BITLBEE_DISABLED" = "1" ] && exit 0
    35 
    3634
    3735#
     
    4139        # Make sure BitlBee can actually write its PID...
    4240        touch /var/run/bitlbee.pid
    43         chown bitlbee /var/run/bitlbee.pid
     41        chown bitlbee: /var/run/bitlbee.pid
    4442       
    45         start-stop-daemon --start --quiet --pidfile $PIDFILE \
     43        # Clean up after the bug between 1.2-5 and 1.2.1-2 where BitlBee ran
     44        # as root. (#494656 and #495877) Fixing this in the postinst script
     45        # is not enough since the user will restart his BitlBee after up-
     46        # grading the package, and the BitlBee running as root will then
     47        # save its settings, re-setting ownership of the file to root.
     48        # TODO: Remove this after a few revisions.
     49        find /var/lib/bitlbee -uid 0 -name '*.xml' -exec chown bitlbee: {} \;
     50
     51        start-stop-daemon --start --quiet \
    4652                --exec $DAEMON -- -p $BITLBEE_PORT -P $PIDFILE $BITLBEE_OPTS
    4753}
     
    5864case "$1" in
    5965  start)
     66        [ "$BITLBEE_DISABLED" = "1" ] && exit 0
     67
    6068        echo -n "Starting $DESC: $NAME"
    6169        d_start
  • debian/changelog

    rc6ca3ee rfb00989  
    1 bitlbee (1.2-6) UNRELEASED; urgency=low
    2 
    3   * Add Homepage and Vcs-Bzr fields.
    4 
    5  -- Jelmer Vernooij <jelmer@samba.org>  Sun, 11 May 2008 14:18:16 +0200
     1bitlbee (1.2.2-1) unstable; urgency=critical
     2
     3  * New upstream version.
     4  * Fixes a security issue (account hijacking), hence the high priority.
     5  * Using a patch to set the User setting in bitlbee.conf properly to keep
     6    upstream and Debian properly separated in my bzr tree.
     7
     8 -- Wilmer van der Gaast <wilmer@gaast.net>  Wed, 27 Aug 2008 23:59:50 +0100
     9
     10bitlbee (1.2.1-3) unstable; urgency=high
     11
     12  * chown /var/lib/bitlbee/*.xml to bitlbee:bitlbee to clean up after
     13    1.2-5 and the bugfix in 1.2.1-2. (Closes: #495877)
     14  * Moved BITLBEE_DISABLED check to only check when trying to *start*
     15    the daemon. (Closes: #488611)
     16
     17 -- Wilmer van der Gaast <wilmer@gaast.net>  Sat, 23 Aug 2008 18:53:54 +0100
     18
     19bitlbee (1.2.1-2) unstable; urgency=low
     20
     21  * Properly set the User= line to something sensible so BitlBee won't
     22    run as root anymore. 1.2-5 was a bad upload. :-( (Closes: #494656)
     23
     24 -- Wilmer van der Gaast <wilmer@gaast.net>  Tue, 12 Aug 2008 00:36:03 +0100
     25
     26bitlbee (1.2.1-1.1) unstable; urgency=low
     27
     28  * Non-Maintainer Upload
     29  * Use invoke-rc.d as per policy. (Closes: #492637) [Thanks to Matt
     30    Kraai]
     31
     32 -- Don Armstrong <don@debian.org>  Wed, 06 Aug 2008 06:57:18 -0700
     33
     34bitlbee (1.2.1-1) unstable; urgency=low
     35
     36  * New upstream release.
     37  * Add Homepage and Vcs-Bzr fields. (From Jelmer.)
     38
     39 -- Wilmer van der Gaast <wilmer@gaast.net>  Thu, 26 Jun 2008 00:07:50 +0100
    640
    741bitlbee (1.2-5) unstable; urgency=low
  • debian/postinst

    rc6ca3ee rfb00989  
    6464fi
    6565
     66if ! grep -qi '^User *= *' /etc/bitlbee/bitlbee.conf; then
     67        echo 'Updating configuration file, enabling User-setting...'
     68        if ! sed -i -e 's/# *User *= *.*/User = bitlbee/i' /etc/bitlbee/bitlbee.conf; then
     69                echo 'Failed! BitlBee may run as root now, please check your configs.'
     70        fi
     71fi
     72
    6673if [ -n "$2" -a "$BITLBEE_UPGRADE_DONT_RESTART" != "1" ]; then
    67         /etc/init.d/bitlbee restart
     74        if which invoke-rc.d >/dev/null 2>&1; then
     75                invoke-rc.d bitlbee restart
     76        else
     77                /etc/init.d/bitlbee restart
     78        fi
    6879fi
    6980
    7081## If we're upgrading, we'll probably skip this next part
    71 if [ -d $CONFDIR ] && chown -R bitlbee $CONFDIR; then
     82if [ -d $CONFDIR ] && chown -R bitlbee: $CONFDIR; then
    7283        echo 'BitlBee (probably) already installed, skipping user/configdir installation'
    7384        exit 0
     
    91102
    92103if [ -z "$2" ]; then
    93         /etc/init.d/bitlbee start
     104        if which invoke-rc.d >/dev/null 2>&1; then
     105                invoke-rc.d bitlbee start
     106        else
     107                /etc/init.d/bitlbee start
     108        fi
    94109fi
  • debian/prerm

    rc6ca3ee rfb00989  
    1010        fi
    1111else
    12         /etc/init.d/bitlbee stop || exit 0
     12        if which invoke-rc.d >/dev/null 2>&1; then
     13                invoke-rc.d bitblee stop || exit 0
     14        else
     15                /etc/init.d/bitlbee stop || exit 0
     16        fi
    1317fi
  • debian/rules

    rc6ca3ee rfb00989  
    5555        cp utils/* debian/bitlbee/usr/share/doc/bitlbee/examples/
    5656        cp debian/bitlbee.init debian/bitlbee/etc/init.d/bitlbee
     57        patch -p0 < debian/patches/bitlbee.conf.diff
    5758        cd debian/bitlbee/usr/share/; \
    5859                gzip -9 doc/bitlbee/changelog.Debian doc/bitlbee/changelog doc/bitlbee/user-guide.txt \
  • doc/CHANGES

    rc6ca3ee rfb00989  
    33
    44http://bugs.bitlbee.org/bitlbee/timeline?daysback=90&changeset=on
     5
     6Version 1.2.4:
     7- Most important change (and main reason for releasing now): Upgraded Yahoo!
     8  module to a newer version to get it working again.
     9- join_chat command replaced with the much better chat command:
     10  * Similar to how account replaced login/slist/logout. Add a chatroom once,
     11    then just /join it like any other room. Also automatic joining at login
     12    time is now possible.
     13  * Note that the old way of starting groupchats (/join #nickname) is now
     14    also deprecated, use "chat with" instead.
     15  * See "help chat" and "help chat add" for more information.
     16- Rewrote bitlbee.conf parser to be less dumb.
     17- Fixed compatibility (hopefully) with AIM mobile messages, certain kinds
     18  of Google Talk chatrooms.
     19- Fixed numerous stability/reliability bugs over the last year.
     20
     21Finished 17 Oct 2009
     22
     23Version 1.2.3:
     24- Fixed one more flaw similar to the previous hijacking bug, caused by incon-
     25  sistent handling of the USTATUS_IDENTIFIED state. All code touching these
     26  variables was reviewed and should be correct now.
     27
     28Finished 7 Sep 2008
     29
     30Version 1.2.2:
     31- Security bugfix: It was possible to hijack accounts (without gaining access
     32  to the old account, it's simply an overwrite)
     33- Some more stability improvements.
     34- Fixed bug where people with non-lowercase nicks couldn't drop their account.
     35- Easier upgrades of non-forking daemon mode servers (using the DEAF
     36  command).
     37- Can be cross-compiled for Win32 now! (No support for SSL yet though, which
     38  makes it less useful for now.)
     39- Exponential backoff on auto-reconnect.
     40- Changing passwords gives less confusing feedback ("password is empty") now.
     41
     42Finished 26 Aug 2008
    543
    644Version 1.2.1:
  • doc/user-guide/Makefile

    rc6ca3ee rfb00989  
    1313
    1414%.html: %.db.xml
    15         xsltproc --output $@ http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl $<
     15        xsltproc --output $@ http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl $<
    1616
    1717%.pdf: %.db.xml
  • doc/user-guide/commands.xml

    rc6ca3ee rfb00989  
    125125                        <description>
    126126                                <para>
    127                                         This command gives you a list of all the accounts known by BitlBee, including the numbers you'll need for most account commands.
     127                                        This command gives you a list of all the accounts known by BitlBee.
    128128                                </para>
    129129                        </description>
     
    138138                        <description>
    139139                                <para>
    140                                         This account can be used to change various settings for IM accounts. For all protocols, this command can be used to change the handle or the password BitlBee uses to log in and if it should be logged in automatically. Some protocols have additional settings. You can see the settings available for a connection by typing <emphasis>account set &lt;account id&gt;</emphasis>.
     140                                        This command can be used to change various settings for IM accounts. For all protocols, this command can be used to change the handle or the password BitlBee uses to log in and if it should be logged in automatically. Some protocols have additional settings. You can see the settings available for a connection by typing <emphasis>account set &lt;account id&gt;</emphasis>.
    141141                                </para>
    142142                               
    143143                                <para>
    144                                         For more infomation about a setting, see <emphasis>help set &lt;setting&gt;</emphasis>. For details about the syntax of this command, see <emphasis>help set</emphasis>.
     144                                        For more infomation about a setting, see <emphasis>help set &lt;setting&gt;</emphasis>.
    145145                                </para>
    146146                               
    147147                                <para>
    148148                                        The account ID can be a number (see <emphasis>account list</emphasis>), the protocol name or (part of) the screenname, as long as it matches only one connection.
     149                                </para>
     150                        </description>
     151                </bitlbee-command>
     152        </bitlbee-command>
     153
     154        <bitlbee-command name="chat">
     155                <short-description>Chatroom list maintenance</short-description>
     156                <syntax>chat &lt;action&gt; [&lt;arguments&gt;]</syntax>
     157
     158                <description>
     159
     160                        <para>
     161                                Available actions: add, del, list, with and set. See <emphasis>help chat &lt;action&gt;</emphasis> for more information.
     162                        </para>
     163
     164                </description>
     165
     166                <bitlbee-command name="add">
     167                        <syntax>chat add &lt;account&gt; &lt;room&gt; [&lt;channel&gt;]</syntax>
     168
     169                        <description>
     170                                <para>
     171                                        Add a chatroom to the list of chatrooms you're interested in. BitlBee needs this list to map room names to a proper IRC channel name.
     172                                </para>
     173
     174                                <para>
     175                                        After adding a room to your list, you can simply use the IRC /join command to enter the room. Also, you can tell BitlBee to automatically join the room when you log in. (See <emphasis>chat set</emphasis>)
     176                                </para>
     177
     178                                <para>
     179                                        Password-protected rooms work exactly like on IRC, by passing the password as an extra argument to /join.
     180                                </para>
     181                        </description>
     182
     183                </bitlbee-command>
     184
     185                <bitlbee-command name="del">
     186                        <syntax>chat del &lt;chat id&gt;</syntax>
     187
     188                        <description>
     189                                <para>
     190                                        This commands deletes an chatroom from your list.
     191                                </para>
     192
     193                                <para>
     194                                        The room ID can be a number (see <emphasis>chat list</emphasis>), or (part of) the name of the room/channel.
     195                                </para>
     196                        </description>
     197                </bitlbee-command>
     198
     199                <bitlbee-command name="list">
     200                        <syntax>chat list</syntax>
     201
     202                        <description>
     203                                <para>
     204                                        This command gives you a list of all the chatrooms known by BitlBee.
     205                                </para>
     206                        </description>
     207                </bitlbee-command>
     208
     209                <bitlbee-command name="with">
     210                        <syntax>chat with &lt;nickname&gt;</syntax>
     211
     212                        <description>
     213                                <para>
     214                                        While most <emphasis>chat</emphasis> subcommands are about named chatrooms, this command can be used to open an unnamed groupchat with one or more persons. This command is what <emphasis>/join #nickname</emphasis> used to do in older BitlBee versions.
     215                                </para>
     216                        </description>
     217                </bitlbee-command>
     218
     219                <bitlbee-command name="set">
     220                        <syntax>chat set &lt;chat id&gt;</syntax>
     221                        <syntax>chat set &lt;chat id&gt;/&lt;setting&gt;</syntax>
     222                        <syntax>chat set &lt;chat id&gt;/&lt;setting&gt; &lt;value&gt;</syntax>
     223                        <syntax>chat set -del &lt;chat id&gt;/&lt;setting&gt;</syntax>
     224
     225                        <description>
     226                                <para>
     227                                        This command can be used to change various settings for chatrooms.
     228                                </para>
     229                               
     230                                <para>
     231                                        For more infomation about a setting, see <emphasis>help set &lt;setting&gt;</emphasis>.
     232                                </para>
     233                               
     234                                <para>
     235                                        The room ID can be a number (see <emphasis>chat list</emphasis>), or (part of) the name of the room/channel.
    149236                                </para>
    150237                        </description>
     
    303390        </bitlbee-setting>
    304391
     392        <bitlbee-setting name="auto_join" type="boolean" scope="chat">
     393                <default>false</default>
     394
     395                <description>
     396                        <para>
     397                                With this option enabled, BitlBee will automatically join this chatroom when you log in.
     398                        </para>
     399                </description>
     400        </bitlbee-setting>
     401
    305402        <bitlbee-setting name="auto_reconnect" type="boolean" scope="both">
    306403                <default>false</default>
     
    321418        </bitlbee-setting>
    322419
    323         <bitlbee-setting name="auto_reconnect_delay" type="integer" scope="global">
    324                 <default>300</default>
    325 
    326                 <description>
    327                         <para>
    328                                 Tell BitlBee after how many seconds it should attempt to bring an IM-connection back up after a crash. It's not a good idea to set this value very low, it will cause too much useless traffic when an IM-server is down for a few hours.
     420        <bitlbee-setting name="auto_reconnect_delay" type="string" scope="global">
     421                <default>5*3&lt;900</default>
     422
     423                <description>
     424                        <para>
     425                                Tell BitlBee after how many seconds it should attempt to bring a broken IM-connection back up.
     426                        </para>
     427
     428                        <para>
     429                                This can be one integer, for a constant delay. One can also set it to something like &quot;10*10&quot;, which means wait for ten seconds on the first reconnect, multiply it by ten on every failure. Once successfully connected, this delay is re-set to the initial value. With &lt; you can give a maximum delay.
    329430                        </para>
    330431
    331432                        <para>
    332433                                See also the <emphasis>auto_reconnect</emphasis> setting.
     434                        </para>
     435                </description>
     436        </bitlbee-setting>
     437
     438        <bitlbee-setting name="away" type="string" scope="both">
     439                <description>
     440                        <para>
     441                                To mark yourself as away, it is recommended to just use <emphasis>/away</emphasis>, like on normal IRC networks. If you want to mark yourself as away on only one IM network, you can use this per-account setting.
     442                        </para>
     443
     444                        <para>
     445                                You can set it to any value and BitlBee will try to map it to the most appropriate away state for every open IM connection, or set it as a free-form away message where possible.
     446                        </para>
     447
     448                        <para>
     449                                Any per-account away setting will override globally set away states. To un-set the setting, use <emphasis>set -del away</emphasis>.
    333450                        </para>
    334451                </description>
     
    482599        </bitlbee-setting>
    483600
     601        <bitlbee-setting name="nick" type="string" scope="chat">
     602
     603                <description>
     604                        <para>
     605                                You can use this option to set your nickname in a chatroom. You won't see this nickname yourself, but other people in the room will. By default, BitlBee will use your username as the chatroom nickname.
     606                        </para>
     607                </description>
     608        </bitlbee-setting>
     609
     610        <bitlbee-setting name="nick_source" type="string" scope="account">
     611                <default>handle</default>
     612                <possible-values>handle, full_name, first_name</possible-values>
     613
     614                <description>
     615                        <para>
     616                                By default, BitlBee generates a nickname for every contact by taking its handle and chopping off everything after the @. In some cases, this gives very inconvenient nicknames. The Facebook XMPP server is a good example, as all Facebook XMPP handles are numeric.
     617                        </para>
     618
     619                        <para>
     620                                With this setting set to <emphasis>full_name</emphasis>, the person's full name is used to generate a nickname. Or if you don't like long nicknames, set this setting to <emphasis>first_name</emphasis> instead and only the first word will be used. Note that the full name can be full of non-ASCII characters which will be stripped off.
     621                        </para>
     622                </description>
     623        </bitlbee-setting>
     624
    484625        <bitlbee-setting name="ops" type="string" scope="global">
    485626                <default>both</default>
     
    576717        <bitlbee-setting name="resource_select" type="string" scope="account">
    577718                <default>priority</default>
    578                 <possible-values>priority, time</possible-values>
     719                <possible-values>priority, activity</possible-values>
    579720
    580721                <description>
     
    584725
    585726                        <para>
    586                                 Normally it's set to <emphasis>priority</emphasis> which means messages will always be delivered to the buddy's resource with the highest priority. If the setting is set to <emphasis>time</emphasis>, messages will be delivered to the resource that was last used to send you a message (or the resource that most recently connected).
     727                                Normally it's set to <emphasis>priority</emphasis> which means messages will always be delivered to the buddy's resource with the highest priority. If the setting is set to <emphasis>activity</emphasis>, messages will be delivered to the resource that was last used to send you a message (or the resource that most recently connected).
    587728                        </para>
    588729                </description>
     
    633774                        <para>
    634775                                Currently only available for Jabber connections. Set this to true if the server accepts SSL connections.
     776                        </para>
     777                </description>
     778        </bitlbee-setting>
     779
     780        <bitlbee-setting name="status" type="string" scope="both">
     781                <description>
     782                        <para>
     783                                Certain protocols (like Jabber/XMPP) support status messages, similar to away messages. They can be used to indicate things like your location or activity, without showing up as away/busy.
     784                        </para>
     785
     786                        <para>
     787                                This setting can be used to set such a message. It will be available as a per-account setting for protocols that support it, and also as a global setting (which will then automatically be used for all protocols that support it).
     788                        </para>
     789
     790                        <para>
     791                                Away states set using <emphasis>/away</emphasis> or the <emphasis>away</emphasis> setting will override this setting. To un-set the setting, use <emphasis>set -del status</emphasis>.
    635792                        </para>
    636793                </description>
     
    8501007
    8511008        </bitlbee-command>
    852 
    853         <bitlbee-command name="join_chat">
    854                 <short-description>Join a named groupchat/conference room</short-description>
    855                 <syntax>join_chat &lt;connection&gt; &lt;room name&gt; [&lt;channel name&gt;] [&lt;room nickname&gt;] [&lt;password&gt;]</syntax>
    856 
    857                 <description>
    858                         <para>
    859                                 On most IM-networks groupchats can be started using the /join command. (<emphasis>/join #foo</emphasis> to start a chatroom with you and <emphasis>foo</emphasis>) This doesn't work with names groupchats though (which exist on Jabber networks and AIM, for example), instead you can use this command.
    860                         </para>
    861 
    862                         <para>
    863                                 The first two arguments are required. <emphasis>room name</emphasis> is the name of the chatroom on the IM-network. <emphasis>channel name</emphasis> is the IRC channel name BitlBee should map this to. <emphasis>room nickname</emphasis> is the nickname you want to have in this channel. If you don't give these options, BitlBee will do the right guesses.
    864                         </para>
    865 
    866                         <para>
    867                                 The following command will join you to the chatroom called <emphasis>bitlbee@conference.bitlbee.org</emphasis>. The channel will be called <emphasis>&amp;bitlbee-help</emphasis> because <emphasis>&amp;bitlbee</emphasis> will already be in use. Your nickname will be <emphasis>help-me</emphasis>.
    868                         </para>
    869                 </description>
    870 
    871                 <ircexample>
    872                         <ircline nick="wilmer">join_chat jabber bitlbee@conference.bitlbee.org &amp;bitlbee-help help-me</ircline>
    873                 </ircexample>
    874 
    875         </bitlbee-command>
    8761009</chapter>
  • doc/user-guide/help.xml

    rc6ca3ee rfb00989  
    1 <?xml version="1.0" encoding="iso-8859-1"?>
     1<?xml version="1.0" encoding="utf-8"?>
    22<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
    33
  • doc/user-guide/misc.xml

    rc6ca3ee rfb00989  
    6969
    7070<para>
    71 If you want to start a groupchat with the person <emphasis>lisa_msn</emphasis> in it, just join the channel <emphasis>#lisa_msn</emphasis>. BitlBee will refuse to join you to the channel with that name, but it will create a new virtual channel with root, you and lisa_msn in it.
     71To open a groupchat, use the <emphasis>chat with</emphasis> command. For example,  to start a groupchat with the person <emphasis>lisa_msn</emphasis> in it, just type <emphasis>chat with lisa_msn</emphasis>. BitlBee will create a new virtual channel with root, you and lisa_msn in it.
    7272</para>
    7373
    7474<para>
    75 Of course a channel with only two people isn't really exciting yet. So the next step is to invite some other people to the channel. For this, you can use the <emphasis>/invite</emphasis> command of your IRC client. Please do keep in mind that all the people have to be on the same network and contact list! You can't invite Yahoo! buddies into an MSN groupchat.
     75Then, just use the ordinary IRC <emphasis>/invite</emphasis> command to invite more people. Please do keep in mind that all the people have to be on the same network and contact list! You can't invite Yahoo! buddies into an MSN groupchat.
    7676</para>
    7777
    7878<para>
    79 Some protocols (like Jabber) also support named groupchats. BitlBee now supports these too. You can use the <emphasis>join_chat</emphasis> command to join them. See <emphasis>help join_chat</emphasis> for more information.
     79Some protocols (like Jabber) also support named groupchats. BitlBee now supports these too. You can use the <emphasis>chat add</emphasis> command to join them. See <emphasis>help chat add</emphasis> for more information.
    8080</para>
    8181
     
    8686
    8787<para>
    88 As you might've expected, you can just use the <emphasis>/away</emphasis> command in your IRC client to set an away-state. BitlBee supports most away-states supported by the protocols.
     88To mark yourself as away, you can just use the <emphasis>/away</emphasis> command in your IRC client. BitlBee supports most away-states supported by the protocols.
    8989</para>
    9090
    9191<para>
    92 Not all away states are supported by all protocols, and some protocols have different names for them. BitlBee will try to pick the best available alias from this list for every connection:
     92Away states have different names accross different protocols. BitlBee will try to pick the best available option for every connection:
    9393</para>
    9494
    9595<simplelist>
    96         <member>Away from computer, Away, Extended away</member>
    97         <member>NA, N/A, Not available</member>
    98         <member>Busy, Do not disturb, DND, Occupied</member>
    99         <member>Be right back, BRB</member>
    100         <member>On the phone, Phone, On phone</member>
    101         <member>Out to lunch, Lunch, Food</member>
     96        <member>Away</member>
     97        <member>NA</member>
     98        <member>Busy, DND</member>
     99        <member>BRB</member>
     100        <member>Phone</member>
     101        <member>Lunch, Food</member>
    102102        <member>Invisible, Hidden</member>
    103103</simplelist>
    104104
    105105<para>
    106 So <emphasis>/away Food</emphasis> will set your state to "Out to lunch" on your MSN connection, and for most other connections the default, "Away" or "Away from computer" will be chosen.
     106So <emphasis>/away Food</emphasis> will set your state to "Out to lunch" on your MSN connection, and for most other connections the default, "Away" will be chosen.
    107107</para>
    108108
     
    111111</para>
    112112
     113<para>
     114If you want to set an away state for only one of your connections, you can use the per-account <emphasis>away</emphasis> setting. See <emphasis>help set away</emphasis>.
     115</para>
     116
    113117</sect1>
    114118
  • doc/user-guide/user-guide.xml

    rc6ca3ee rfb00989  
    1 <?xml version="1.0" encoding="iso-8859-1"?>
     1<?xml version="1.0" encoding="utf-8"?>
    22<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
    33
  • irc.c

    rc6ca3ee rfb00989  
    3434GSList *irc_connection_list = NULL;
    3535
    36 static char *passchange( set_t *set, char *value )
     36static char *set_eval_password( set_t *set, char *value )
    3737{
    3838        irc_t *irc = set->data;
    3939       
    40         irc_setpass( irc, value );
    41         irc_usermsg( irc, "Password successfully changed" );
    42         return NULL;
     40        if( irc->status & USTATUS_IDENTIFIED && value )
     41        {
     42                irc_setpass( irc, value );
     43                return NULL;
     44        }
     45        else
     46        {
     47                return SET_INVALID;
     48        }
    4349}
    4450
     
    7278}
    7379
     80static char *set_eval_away_status( set_t *set, char *value )
     81{
     82        irc_t *irc = set->data;
     83        account_t *a;
     84       
     85        g_free( set->value );
     86        set->value = g_strdup( value );
     87       
     88        for( a = irc->accounts; a; a = a->next )
     89        {
     90                struct im_connection *ic = a->ic;
     91               
     92                if( ic && ic->flags & OPT_LOGGED_IN )
     93                        imc_away_send_update( ic );
     94        }
     95       
     96        return value;
     97}
     98
    7499irc_t *irc_new( int fd )
    75100{
     
    77102        struct sockaddr_storage sock;
    78103        socklen_t socklen = sizeof( sock );
     104        set_t *s;
    79105       
    80106        irc = g_new0( irc_t, 1 );
     
    136162        irc_connection_list = g_slist_append( irc_connection_list, irc );
    137163       
    138         set_add( &irc->set, "away_devoice", "true",  set_eval_away_devoice, irc );
    139         set_add( &irc->set, "auto_connect", "true", set_eval_bool, irc );
    140         set_add( &irc->set, "auto_reconnect", "false", set_eval_bool, irc );
    141         set_add( &irc->set, "auto_reconnect_delay", "300", set_eval_int, irc );
    142         set_add( &irc->set, "buddy_sendbuffer", "false", set_eval_bool, irc );
    143         set_add( &irc->set, "buddy_sendbuffer_delay", "200", set_eval_int, irc );
    144         set_add( &irc->set, "charset", "utf-8", set_eval_charset, irc );
    145         set_add( &irc->set, "debug", "false", set_eval_bool, irc );
    146         set_add( &irc->set, "default_target", "root", NULL, irc );
    147         set_add( &irc->set, "display_namechanges", "false", set_eval_bool, irc );
    148         set_add( &irc->set, "handle_unknown", "root", NULL, irc );
    149         set_add( &irc->set, "lcnicks", "true", set_eval_bool, irc );
    150         set_add( &irc->set, "ops", "both", set_eval_ops, irc );
    151         set_add( &irc->set, "password", NULL, passchange, irc );
    152         set_add( &irc->set, "private", "true", set_eval_bool, irc );
    153         set_add( &irc->set, "query_order", "lifo", NULL, irc );
    154         set_add( &irc->set, "root_nick", irc->mynick, set_eval_root_nick, irc );
    155         set_add( &irc->set, "save_on_quit", "true", set_eval_bool, irc );
    156         set_add( &irc->set, "simulate_netsplit", "true", set_eval_bool, irc );
    157         set_add( &irc->set, "strip_html", "true", NULL, irc );
    158         set_add( &irc->set, "to_char", ": ", set_eval_to_char, irc );
    159         set_add( &irc->set, "typing_notice", "false", set_eval_bool, irc );
     164        s = set_add( &irc->set, "away", NULL,  set_eval_away_status, irc );
     165        s->flags |= SET_NULL_OK;
     166        s = set_add( &irc->set, "away_devoice", "true",  set_eval_away_devoice, irc );
     167        s = set_add( &irc->set, "auto_connect", "true", set_eval_bool, irc );
     168        s = set_add( &irc->set, "auto_reconnect", "true", set_eval_bool, irc );
     169        s = set_add( &irc->set, "auto_reconnect_delay", "5*3<900", set_eval_account_reconnect_delay, irc );
     170        s = set_add( &irc->set, "buddy_sendbuffer", "false", set_eval_bool, irc );
     171        s = set_add( &irc->set, "buddy_sendbuffer_delay", "200", set_eval_int, irc );
     172        s = set_add( &irc->set, "charset", "utf-8", set_eval_charset, irc );
     173        s = set_add( &irc->set, "debug", "false", set_eval_bool, irc );
     174        s = set_add( &irc->set, "default_target", "root", NULL, irc );
     175        s = set_add( &irc->set, "display_namechanges", "false", set_eval_bool, irc );
     176        s = set_add( &irc->set, "handle_unknown", "root", NULL, irc );
     177        s = set_add( &irc->set, "lcnicks", "true", set_eval_bool, irc );
     178        s = set_add( &irc->set, "ops", "both", set_eval_ops, irc );
     179        s = set_add( &irc->set, "password", NULL, set_eval_password, irc );
     180        s->flags |= SET_NULL_OK;
     181        s = set_add( &irc->set, "private", "true", set_eval_bool, irc );
     182        s = set_add( &irc->set, "query_order", "lifo", NULL, irc );
     183        s = set_add( &irc->set, "root_nick", irc->mynick, set_eval_root_nick, irc );
     184        s = set_add( &irc->set, "save_on_quit", "true", set_eval_bool, irc );
     185        s = set_add( &irc->set, "simulate_netsplit", "true", set_eval_bool, irc );
     186        s = set_add( &irc->set, "status", NULL,  set_eval_away_status, irc );
     187        s->flags |= SET_NULL_OK;
     188        s = set_add( &irc->set, "strip_html", "true", NULL, irc );
     189        s = set_add( &irc->set, "to_char", ": ", set_eval_to_char, irc );
     190        s = set_add( &irc->set, "typing_notice", "false", set_eval_bool, irc );
    160191       
    161192        conf_loaddefaults( irc );
     
    231262       
    232263        if( irc->status & USTATUS_IDENTIFIED && set_getbool( &irc->set, "save_on_quit" ) )
    233                 if( storage_save( irc, TRUE ) != STORAGE_OK )
     264                if( storage_save( irc, NULL, TRUE ) != STORAGE_OK )
    234265                        irc_usermsg( irc, "Error while saving settings!" );
    235266       
     
    399430                        }
    400431                       
    401                         if( lines[i] )
    402                         {
    403                                 if( ( cmd = irc_parse_line( lines[i] ) ) == NULL )
    404                                         continue;
     432                        if( lines[i] && ( cmd = irc_parse_line( lines[i] ) ) )
     433                        {
    405434                                irc_exec( irc, cmd );
    406435                                g_free( cmd );
     
    477506        if( line[0] == ':' )
    478507        {
    479                 for( i = 0; line[i] != ' '; i ++ );
     508                for( i = 0; line[i] && line[i] != ' '; i ++ );
    480509                line = line + i;
    481510        }
     
    773802        irc_reply( irc,   3, ":%s", IRCD_INFO );
    774803        irc_reply( irc,   4, "%s %s %s %s", irc->myhost, BITLBEE_VERSION, UMODES UMODES_PRIV, CMODES );
    775         irc_reply( irc,   5, "PREFIX=(ov)@+ CHANTYPES=#& CHANMODES=,,,%s NICKLEN=%d NETWORK=BitlBee CASEMAPPING=rfc1459 MAXTARGETS=1 WATCH=128 :are supported by this server", CMODES, MAX_NICK_LENGTH - 1 );
     804        irc_reply( irc,   5, "PREFIX=(ov)@+ CHANTYPES=%s CHANMODES=,,,%s NICKLEN=%d NETWORK=BitlBee "
     805                             "CASEMAPPING=rfc1459 MAXTARGETS=1 WATCH=128 :are supported by this server",
     806                             CTYPES, CMODES, MAX_NICK_LENGTH - 1 );
    776807        irc_motd( irc );
    777808        irc->umode[0] = '\0';
     
    10141045        user_t *u = NULL;
    10151046       
    1016         if( *nick == '#' || *nick == '&' )
     1047        if( strchr( CTYPES, *nick ) )
    10171048        {
    10181049                if( !( c = irc_chat_by_channel( irc, nick ) ) )
  • irc.h

    rc6ca3ee rfb00989  
    3838#define CMODE "t"
    3939#define UMODE "s"
     40#define CTYPES "&#"
    4041
    4142typedef enum
     
    4748        USTATUS_SHUTDOWN = 8
    4849} irc_status_t;
    49 
    50 typedef struct channel
    51 {
    52         char *name;
    53 } channel_t;
    5450
    5551typedef struct irc
     
    8783        struct query *queries;
    8884        struct account *accounts;
     85        struct chat *chatrooms;
    8986       
    9087        struct __USER *users;
     
    10097
    10198#include "user.h"
    102 // #include "nick.h"
    10399
    104100extern GSList *irc_connection_list;
  • irc_commands.c

    rc6ca3ee rfb00989  
    2727#include "bitlbee.h"
    2828#include "ipc.h"
     29#include "chat.h"
    2930
    3031static void irc_cmd_pass( irc_t *irc, char **cmd )
     
    125126static void irc_cmd_mode( irc_t *irc, char **cmd )
    126127{
    127         if( *cmd[1] == '#' || *cmd[1] == '&' )
     128        if( strchr( CTYPES, *cmd[1] ) )
    128129        {
    129130                if( cmd[2] )
     
    193194        else if( cmd[1] )
    194195        {
    195                 if( ( cmd[1][0] == '#' || cmd[1][0] == '&' ) && cmd[1][1] )
    196                 {
    197                         user_t *u = user_find( irc, cmd[1] + 1 );
    198                        
    199                         if( u && u->ic && u->ic->acc->prpl->chat_with )
    200                         {
    201                                 irc_reply( irc, 403, "%s :Initializing groupchat in a different channel", cmd[1] );
    202                                
    203                                 if( !u->ic->acc->prpl->chat_with( u->ic, u->handle ) )
    204                                 {
    205                                         irc_usermsg( irc, "Could not open a groupchat with %s.", u->nick );
    206                                 }
    207                         }
    208                         else if( u )
    209                         {
    210                                 irc_reply( irc, 403, "%s :Groupchats are not possible with %s", cmd[1], cmd[1]+1 );
    211                         }
    212                         else
    213                         {
    214                                 irc_reply( irc, 403, "%s :No such nick", cmd[1] );
    215                         }
    216                 }
     196                struct chat *c;
     197               
     198                if( strchr( CTYPES, cmd[1][0] ) == NULL || cmd[1][1] == 0 )
     199                        irc_reply( irc, 479, "%s :Invalid channel name", cmd[1] );
     200                else if( ( c = chat_bychannel( irc, cmd[1] ) ) && c->acc && c->acc->ic )
     201                        chat_join( irc, c, cmd[2] );
    217202                else
    218                 {
    219203                        irc_reply( irc, 403, "%s :No such channel", cmd[1] );
    220                 }
    221204        }
    222205}
     
    433416                        if( g_hash_table_lookup_extended( irc->watches, nick, &okey, &ovalue ) )
    434417                        {
     418                                g_hash_table_remove( irc->watches, okey );
    435419                                g_free( okey );
    436                                 g_hash_table_remove( irc->watches, okey );
    437420                               
    438421                                irc_reply( irc, 602, "%s %s %s %d :%s", nick, "*", "*", 0, "Stopped watching" );
     
    465448        user_t *u = user_find( irc, irc->nick );
    466449        char *away = cmd[1];
    467         account_t *a;
    468450       
    469451        if( !u ) return;
     
    492474        }
    493475       
    494         for( a = irc->accounts; a; a = a->next )
    495         {
    496                 struct im_connection *ic = a->ic;
    497                
    498                 if( ic && ic->flags & OPT_LOGGED_IN )
    499                         imc_set_away( ic, u->away );
    500         }
     476        set_setstr( &irc->set, "away", u->away );
    501477}
    502478
  • lib/events_libevent.c

    rc6ca3ee rfb00989  
    3737
    3838static void b_main_restart();
    39 static guint id_next = 1;
     39static guint id_next = 1; /* Next ID to be allocated to an event handler. */
     40static guint id_cur = 0; /* Event ID that we're currently handling. */
     41static guint id_dead; /* Set to 1 if b_event_remove removes id_cur. */
    4042static GHashTable *id_hash;
    41 static int quitting = 0;
     43static int quitting = 0; /* Prepare to quit, stop handling events. */
    4244
    4345/* Since libevent doesn't handle two event handlers for one fd-condition
     
    119121        struct b_event_data *b_ev = data;
    120122        b_input_condition cond = 0;
    121         int id;
     123        gboolean st;
    122124       
    123125        if( fd >= 0 )
     
    133135        /* Since the called function might cancel this handler already
    134136           (which free()s b_ev), we have to remember the ID here. */
    135         id = b_ev->id;
     137        id_cur = b_ev->id;
     138        id_dead = 0;
    136139       
    137140        if( quitting )
    138141        {
    139                 b_event_remove( id );
     142                b_event_remove( id_cur );
    140143                return;
    141144        }
    142145       
    143         if( !b_ev->function( b_ev->data, fd, cond ) )
     146        st = b_ev->function( b_ev->data, fd, cond );
     147        if( id_dead )
     148        {
     149                /* This event was killed already, don't touch it! */
     150                return;
     151        }
     152        else if( !st )
    144153        {
    145154                event_debug( "Handler returned FALSE: " );
    146                 b_event_remove( id );
     155                b_event_remove( id_cur );
    147156        }
    148157        else if( fd == -1 )
    149158        {
     159                /* fd == -1 means it was a timer. These can't be auto-repeated
     160                   so it has to be recreated every time. */
    150161                struct timeval tv;
    151162               
     
    236247        if( b_ev )
    237248        {
     249                if( id == id_cur )
     250                        id_dead = TRUE;
     251               
    238252                g_hash_table_remove( id_hash, &b_ev->id );
    239253                if( b_ev->evinfo.ev_fd >= 0 )
  • lib/http_client.c

    rc6ca3ee rfb00989  
    5959        if( error )
    6060        {
    61                 g_free( req );
    62                 return( NULL );
     61                http_free( req );
     62                return NULL;
    6363        }
    6464       
     
    160160       
    161161        req->func( req );
    162        
    163         g_free( req->request );
    164         g_free( req );
    165        
     162        http_free( req );
    166163        return FALSE;
    167164}
     
    444441       
    445442        req->func( req );
    446        
     443        http_free( req );
     444        return FALSE;
     445}
     446
     447void http_free( struct http_request *req )
     448{
    447449        g_free( req->request );
    448450        g_free( req->reply_headers );
    449451        g_free( req->status_string );
    450452        g_free( req );
    451        
    452         return FALSE;
    453 }
     453}
     454
  • lib/http_client.h

    rc6ca3ee rfb00989  
    8181void *http_dorequest( char *host, int port, int ssl, char *request, http_input_function func, gpointer data );
    8282void *http_dorequest_url( char *url_string, http_input_function func, gpointer data );
     83
     84void http_free( struct http_request *req );
  • lib/ini.c

    rc6ca3ee rfb00989  
    22  * BitlBee -- An IRC to other IM-networks gateway                     *
    33  *                                                                    *
    4   * Copyright 2002-2005 Wilmer van der Gaast and others                *
     4  * Copyright 2002-2008 Wilmer van der Gaast and others                *
    55  \********************************************************************/
    66
     
    2828ini_t *ini_open( char *file )
    2929{
    30         ini_t *ini = g_new0( ini_t, 1 );
     30        int fd;
     31        ini_t *ini = NULL;
     32        struct stat fi;
    3133       
    32         if( ( ini->fp = fopen( file, "r" ) ) == NULL )
     34        if( ( fd = open( file, O_RDONLY ) ) != -1 &&
     35            fstat( fd, &fi ) == 0 &&
     36            fi.st_size <= 16384 &&
     37            ( ini = g_malloc( sizeof( ini_t ) + fi.st_size + 1 ) ) &&
     38            read( fd, ini->file, fi.st_size ) == fi.st_size )
    3339        {
    34                 g_free( ini );
    35                 return( NULL );
     40                memset( ini, 0, sizeof( ini_t ) );
     41                ini->size = fi.st_size;
     42                ini->file[ini->size] = 0;
     43                ini->cur = ini->file;
     44                ini->c_section = "";
     45               
     46                close( fd );
     47               
     48                return ini;
    3649        }
     50
     51        if( fd >= 0 )
     52                close( fd );
    3753       
    38         return( ini );
     54        ini_close( ini );
     55
     56        return NULL;
     57}
     58
     59/* Strips leading and trailing whitespace and returns a pointer to the first
     60   non-ws character of the given string. */
     61static char *ini_strip_whitespace( char *in )
     62{
     63        char *e;
     64
     65        while( isspace( *in ) )
     66                in++;
     67
     68        e = in + strlen( in ) - 1;
     69        while( e > in && isspace( *e ) )
     70                e--;
     71        e[1] = 0;
     72       
     73        return in;
    3974}
    4075
    4176int ini_read( ini_t *file )
    4277{
    43         char key[MAX_STRING], s[MAX_STRING], *t;
    44         int i;
     78        char *s;
    4579       
    46         while( !feof( file->fp ) )
     80        while( file->cur && file->cur < file->file + file->size )
    4781        {
    48                 *s = 0;
    49                 fscanf( file->fp, "%127[^\n#]s", s );
    50                 fscanf( file->fp, "%*[^\n]s" );
    51                 fgetc( file->fp );              /* Skip newline         */
    52                 file->line ++;
    53                 if( strchr( s, '=' ) )
     82                char *e, *next;
     83               
     84                file->line++;
     85
     86                /* Find the end of line */
     87                if( ( e = strchr( file->cur, '\n' ) ) != NULL )
    5488                {
    55                         sscanf( s, "%[^ =]s", key );
    56                         if( ( t = strchr( key, '.' ) ) )
     89                        *e = 0;
     90                        next = e + 1;
     91                }
     92                else
     93                {
     94                        /* No more lines. */
     95                        e = file->cur + strlen( file->cur );
     96                        next = NULL;
     97                }
     98               
     99                /* Comment? */
     100                if( ( s = strchr( file->cur, '#' ) ) != NULL )
     101                        *s = 0;
     102               
     103                file->cur = ini_strip_whitespace( file->cur );
     104               
     105                if( *file->cur == '[' )
     106                {
     107                        file->cur++;
     108                        if( ( s = strchr( file->cur, ']' ) ) != NULL )
    57109                        {
    58                                 *t = 0;
    59                                 strcpy( file->section, key );
    60                                 t ++;
     110                                *s = 0;
     111                                file->c_section = file->cur;
     112                        }
     113                }
     114                else if( ( s = strchr( file->cur, '=' ) ) != NULL )
     115                {
     116                        *s = 0;
     117                        file->key = ini_strip_whitespace( file->cur );
     118                        file->value = ini_strip_whitespace( s + 1 );
     119                       
     120                        if( ( s = strchr( file->key, '.' ) ) != NULL )
     121                        {
     122                                *s = 0;
     123                                file->section = file->key;
     124                                file->key = s + 1;
    61125                        }
    62126                        else
    63127                        {
    64                                 strcpy( file->section, file->c_section );
    65                                 t = key;
     128                                file->section = file->c_section;
    66129                        }
    67                         sscanf( t, "%s", file->key );
    68                         t = strchr( s, '=' ) + 1;
    69                         for( i = 0; t[i] == ' '; i ++ );
    70                         strcpy( file->value, &t[i] );
    71                         for( i = strlen( file->value ) - 1; file->value[i] == 32; i -- )
    72                                 file->value[i] = 0;
    73130                       
    74                         return( 1 );
     131                        file->cur = next;
     132                        return 1;
    75133                }
    76                 else if( ( t = strchr( s, '[' ) ) )
    77                 {
    78                         strcpy( file->c_section, t + 1 );
    79                         t = strchr( file->c_section, ']' );
    80                         *t = 0;
    81                 }
     134                /* else: noise/comment/etc, let's just ignore it. */
     135
     136                file->cur = next;
    82137        }
    83         return( 0 );
     138       
     139        return 0;
    84140}
    85141
    86142void ini_close( ini_t *file )
    87143{
    88         fclose( file->fp );
    89144        g_free( file );
    90145}
  • lib/ini.h

    rc6ca3ee rfb00989  
    2929typedef struct
    3030{
    31         FILE *fp;
    3231        int line;
    33         char c_section[MAX_STRING];
    34         char section[MAX_STRING];
    35         char key[MAX_STRING];
    36         char value[MAX_STRING];
     32        char *c_section;
     33        char *section;
     34        char *key;
     35        char *value;
     36        int size;
     37        char *cur, *tok;
     38        char file[];
    3739} ini_t;
    3840
  • lib/misc.c

    rc6ca3ee rfb00989  
    4747#endif
    4848
     49#include "md5.h"
    4950#include "ssl_client.h"
    5051
     
    8990        { "gt",     ">" },
    9091        { "amp",    "&" },
     92        { "apos",   "'" },
    9193        { "quot",   "\"" },
    9294        { "aacute", "á" },
  • lib/proxy.c

    rc6ca3ee rfb00989  
    558558                return proxy_connect_socks5(host, port, phb);
    559559       
    560         if (phb->host) g_free(phb);
    561560        g_free(phb);
    562561        return -1;
  • lib/xmltree.c

    rc6ca3ee rfb00989  
    472472}
    473473
    474 struct xt_node *xt_new_node( char *name, char *text, struct xt_node *children )
     474struct xt_node *xt_new_node( char *name, const char *text, struct xt_node *children )
    475475{
    476476        struct xt_node *node, *c;
  • lib/xmltree.h

    rc6ca3ee rfb00989  
    9090char *xt_find_attr( struct xt_node *node, const char *key );
    9191
    92 struct xt_node *xt_new_node( char *name, char *text, struct xt_node *children );
     92struct xt_node *xt_new_node( char *name, const char *text, struct xt_node *children );
    9393void xt_add_child( struct xt_node *parent, struct xt_node *child );
    9494void xt_add_attr( struct xt_node *node, const char *key, const char *value );
  • protocols/jabber/conference.c

    rc6ca3ee rfb00989  
    2626static xt_status jabber_chat_join_failed( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
    2727
    28 struct groupchat *jabber_chat_join( struct im_connection *ic, char *room, char *nick, char *password )
     28struct groupchat *jabber_chat_join( struct im_connection *ic, const char *room, const char *nick, const char *password )
    2929{
    3030        struct jabber_chat *jc;
     
    3636        node = xt_new_node( "x", NULL, NULL );
    3737        xt_add_attr( node, "xmlns", XMLNS_MUC );
    38         node = jabber_make_packet( "presence", NULL, roomjid, node );
    3938        if( password )
    4039                xt_add_child( node, xt_new_node( "password", password, NULL ) );
     40        node = jabber_make_packet( "presence", NULL, roomjid, node );
    4141        jabber_cache_add( ic, node, jabber_chat_join_failed );
    4242       
     
    234234                            ( strcmp( s, XMLNS_MUC_USER ) == 0 ) )
    235235                        {
    236                                 c = xt_find_node( c->children, "item" );
    237                                 if( ( s = xt_find_attr( c, "jid" ) ) )
     236                                struct xt_node *item;
     237                               
     238                                item = xt_find_node( c->children, "item" );
     239                                if( ( s = xt_find_attr( item, "jid" ) ) )
    238240                                {
    239241                                        /* Yay, found what we need. :-) */
     
    283285        else if( type ) /* type can only be NULL or "unavailable" in this function */
    284286        {
    285                 s = strchr( bud->ext_jid, '/' );
    286                 if( s ) *s = 0;
    287                 imcb_chat_remove_buddy( chat, bud->ext_jid, NULL );
    288                 if( bud != jc->me && bud->flags & JBFLAG_IS_ANONYMOUS )
    289                         imcb_remove_buddy( ic, bud->ext_jid, NULL );
    290                 if( s ) *s = '/';
     287                if( ( bud->flags & JBFLAG_IS_CHATROOM ) && bud->ext_jid )
     288                {
     289                        s = strchr( bud->ext_jid, '/' );
     290                        if( s ) *s = 0;
     291                        imcb_chat_remove_buddy( chat, bud->ext_jid, NULL );
     292                        if( bud != jc->me && bud->flags & JBFLAG_IS_ANONYMOUS )
     293                                imcb_remove_buddy( ic, bud->ext_jid, NULL );
     294                        if( s ) *s = '/';
     295                }
    291296               
    292297                if( bud == jc->me )
  • protocols/jabber/io.c

    rc6ca3ee rfb00989  
    375375       
    376376        if( ( c = xt_find_node( node->children, "bind" ) ) )
    377         {
    378                 reply = xt_new_node( "bind", NULL, xt_new_node( "resource", set_getstr( &ic->acc->set, "resource" ), NULL ) );
    379                 xt_add_attr( reply, "xmlns", XMLNS_BIND );
    380                 reply = jabber_make_packet( "iq", "set", NULL, reply );
    381                 jabber_cache_add( ic, reply, jabber_pkt_bind_sess );
    382                
    383                 if( !jabber_write_packet( ic, reply ) )
    384                         return XT_ABORT;
    385                
    386                 jd->flags |= JFLAG_WAIT_BIND;
    387         }
     377                jd->flags |= JFLAG_WANT_BIND;
    388378       
    389379        if( ( c = xt_find_node( node->children, "session" ) ) )
    390         {
    391                 reply = xt_new_node( "session", NULL, NULL );
    392                 xt_add_attr( reply, "xmlns", XMLNS_SESSION );
    393                 reply = jabber_make_packet( "iq", "set", NULL, reply );
    394                 jabber_cache_add( ic, reply, jabber_pkt_bind_sess );
    395                
    396                 if( !jabber_write_packet( ic, reply ) )
    397                         return XT_ABORT;
    398                
    399                 jd->flags |= JFLAG_WAIT_SESSION;
    400         }
     380                jd->flags |= JFLAG_WANT_SESSION;
    401381       
    402382        /* This flag is already set if we authenticated via SASL, so now
    403383           we can resume the session in the new stream, if we don't have
    404384           to bind/initialize the session. */
    405         if( jd->flags & JFLAG_AUTHENTICATED && ( jd->flags & ( JFLAG_WAIT_BIND | JFLAG_WAIT_SESSION ) ) == 0 )
     385        if( jd->flags & JFLAG_AUTHENTICATED && ( jd->flags & ( JFLAG_WANT_BIND | JFLAG_WANT_SESSION ) ) == 0 )
    406386        {
    407387                if( !jabber_get_roster( ic ) )
    408388                        return XT_ABORT;
     389        }
     390        else if( jd->flags & JFLAG_AUTHENTICATED )
     391        {
     392                return jabber_pkt_bind_sess( ic, NULL, NULL );
    409393        }
    410394       
     
    441425        imcb_log( ic, "Converting stream to TLS" );
    442426       
     427        jd->flags |= JFLAG_STARTTLS_DONE;
    443428        jd->ssl = ssl_starttls( jd->fd, jabber_connected_ssl, ic );
    444429       
     
    531516                jd->r_inpa = b_input_add( jd->fd, GAIM_INPUT_READ, jabber_read_callback, ic );
    532517       
    533         greet = g_strdup_printf( "<?xml version='1.0' ?>"
    534                                  "<stream:stream to=\"%s\" xmlns=\"jabber:client\" "
    535                                   "xmlns:stream=\"http://etherx.jabber.org/streams\" version=\"1.0\">", jd->server );
     518        greet = g_strdup_printf( "%s<stream:stream to=\"%s\" xmlns=\"jabber:client\" "
     519                                  "xmlns:stream=\"http://etherx.jabber.org/streams\" version=\"1.0\">",
     520                                  ( jd->flags & JFLAG_STARTTLS_DONE ) ? "" : "<?xml version='1.0' ?>",
     521                                  jd->server );
    536522       
    537523        st = jabber_write( ic, greet, strlen( greet ) );
  • protocols/jabber/iq.c

    rc6ca3ee rfb00989  
    5151        {
    5252                if( !( ( c = xt_find_node( node->children, "query" ) ) ||
    53                        ( c = xt_find_node( node->children, "ping" ) ) ) || /* O_o WHAT is wrong with just <query/> ????? */
     53                       ( c = xt_find_node( node->children, "ping" ) ) ) ||
    5454                    !( s = xt_find_attr( c, "xmlns" ) ) )
    5555                {
    56                         imcb_log( ic, "Warning: Received incomplete IQ-%s packet", type );
     56                        /* Sigh. Who decided to suddenly invent new elements
     57                           instead of just sticking with <query/>? */
    5758                        return XT_HANDLED;
    5859                }
     
    297298{
    298299        struct jabber_data *jd = ic->proto_data;
    299         struct xt_node *c;
     300        struct xt_node *c, *reply = NULL;
    300301        char *s;
    301302       
    302         if( ( c = xt_find_node( node->children, "bind" ) ) )
     303        if( node && ( c = xt_find_node( node->children, "bind" ) ) )
    303304        {
    304305                c = xt_find_node( c->children, "jid" );
     
    307308                        imcb_log( ic, "Server changed session resource string to `%s'", s + 1 );
    308309               
    309                 jd->flags &= ~JFLAG_WAIT_BIND;
    310         }
    311         else
    312         {
    313                 jd->flags &= ~JFLAG_WAIT_SESSION;
    314         }
    315        
    316         if( ( jd->flags & ( JFLAG_WAIT_BIND | JFLAG_WAIT_SESSION ) ) == 0 )
     310                jd->flags &= ~JFLAG_WANT_BIND;
     311        }
     312        else if( node && ( c = xt_find_node( node->children, "session" ) ) )
     313        {
     314                jd->flags &= ~JFLAG_WANT_SESSION;
     315        }
     316       
     317        if( jd->flags & JFLAG_WANT_BIND )
     318        {
     319                reply = xt_new_node( "bind", NULL, xt_new_node( "resource", set_getstr( &ic->acc->set, "resource" ), NULL ) );
     320                xt_add_attr( reply, "xmlns", XMLNS_BIND );
     321        }
     322        else if( jd->flags & JFLAG_WANT_SESSION )
     323        {
     324                reply = xt_new_node( "session", NULL, NULL );
     325                xt_add_attr( reply, "xmlns", XMLNS_SESSION );
     326        }
     327       
     328        if( reply != NULL )
     329        {
     330                reply = jabber_make_packet( "iq", "set", NULL, reply );
     331                jabber_cache_add( ic, reply, jabber_pkt_bind_sess );
     332               
     333                if( !jabber_write_packet( ic, reply ) )
     334                        return XT_ABORT;
     335        }
     336        else if( ( jd->flags & ( JFLAG_WANT_BIND | JFLAG_WANT_SESSION ) ) == 0 )
    317337        {
    318338                if( !jabber_get_roster( ic ) )
  • protocols/jabber/jabber.c

    rc6ca3ee rfb00989  
    7070       
    7171        s = set_add( &acc->set, "server", NULL, set_eval_account, acc );
    72         s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY;
     72        s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY | SET_NULL_OK;
    7373       
    7474        s = set_add( &acc->set, "ssl", "false", set_eval_bool, acc );
     
    8080        s = set_add( &acc->set, "xmlconsole", "false", set_eval_bool, acc );
    8181        s->flags |= ACC_SET_OFFLINE_ONLY;
     82       
     83        acc->flags |= ACC_FLAG_AWAY_MESSAGE | ACC_FLAG_STATUS_MESSAGE;
    8284}
    8385
     
    364366        while( bud )
    365367        {
    366                 imcb_log( ic, "Buddy %s (%d) information:\nAway state: %s\nAway message: %s",
    367                                    bud->full_jid, bud->priority,
    368                                    bud->away_state ? bud->away_state->full_name : "(none)",
    369                                    bud->away_message ? : "(none)" );
     368                imcb_log( ic, "Buddy %s (%d) information:", bud->full_jid, bud->priority );
     369                if( bud->away_state )
     370                        imcb_log( ic, "Away state: %s", bud->away_state->full_name );
     371                imcb_log( ic, "Status message: %s", bud->away_message ? : "(none)" );
     372               
    370373                bud = bud->next;
    371374        }
     
    377380{
    378381        struct jabber_data *jd = ic->proto_data;
    379         struct jabber_away_state *state;
    380        
    381         /* Save all this info. We need it, for example, when changing the priority setting. */
    382         state = (void *) jabber_away_state_by_name( state_txt );
    383         jd->away_state = state ? state : (void *) jabber_away_state_list; /* Fall back to "Away" if necessary. */
     382       
     383        /* state_txt == NULL -> Not away.
     384           Unknown state -> fall back to the first defined away state. */
     385        jd->away_state = state_txt ? jabber_away_state_by_name( state_txt )
     386                         ? : jabber_away_state_list : NULL;
     387       
    384388        g_free( jd->away_message );
    385389        jd->away_message = ( message && *message ) ? g_strdup( message ) : NULL;
     
    425429}
    426430
    427 static struct groupchat *jabber_chat_join_( struct im_connection *ic, char *room, char *nick, char *password )
     431static struct groupchat *jabber_chat_join_( struct im_connection *ic, const char *room, const char *nick, const char *password )
    428432{
    429433        if( strchr( room, '@' ) == NULL )
  • protocols/jabber/jabber.h

    rc6ca3ee rfb00989  
    2727#include <glib.h>
    2828
    29 #include "xmltree.h"
    3029#include "bitlbee.h"
    3130#include "md5.h"
     31#include "xmltree.h"
    3232
    3333extern GSList *jabber_connections;
     
    4040        JFLAG_STREAM_RESTART = 4,       /* Set when we want to restart the stream (after
    4141                                           SASL or TLS). */
    42         JFLAG_WAIT_SESSION = 8,         /* Set if we sent a <session> tag and need a reply
     42        JFLAG_WANT_SESSION = 8,         /* Set if the server wants a <session/> tag
    4343                                           before we continue. */
    44         JFLAG_WAIT_BIND = 16,           /* ... for <bind> tag. */
     44        JFLAG_WANT_BIND = 16,           /* ... for <bind> tag. */
    4545        JFLAG_WANT_TYPING = 32,         /* Set if we ever sent a typing notification, this
    4646                                           activates all XEP-85 related code. */
    4747        JFLAG_XMLCONSOLE = 64,          /* If the user added an xmlconsole buddy. */
     48        JFLAG_STARTTLS_DONE = 128,      /* If a plaintext session was converted to TLS. */
    4849} jabber_flags_t;
    4950
     
    8485        /* After changing one of these two (or the priority setting), call
    8586           presence_send_update() to inform the server about the changes. */
    86         struct jabber_away_state *away_state;
     87        const struct jabber_away_state *away_state;
    8788        char *away_message;
    8889       
     
    241242
    242243/* conference.c */
    243 struct groupchat *jabber_chat_join( struct im_connection *ic, char *room, char *nick, char *password );
     244struct groupchat *jabber_chat_join( struct im_connection *ic, const char *room, const char *nick, const char *password );
    244245struct groupchat *jabber_chat_by_jid( struct im_connection *ic, const char *name );
    245246void jabber_chat_free( struct groupchat *c );
  • protocols/jabber/jabber_util.c

    rc6ca3ee rfb00989  
    3737                /* Priority is a signed 8-bit integer, according to RFC 3921. */
    3838                if( i < -128 || i > 127 )
    39                         return NULL;
     39                        return SET_INVALID;
    4040        }
    4141        else
    42                 return NULL;
     42                return SET_INVALID;
    4343       
    4444        /* Only run this stuff if the account is online ATM,
     
    228228{
    229229        { "away",  "Away" },
    230         { "chat",  "Free for Chat" },
     230        { "chat",  "Free for Chat" },   /* WTF actually uses this? */
    231231        { "dnd",   "Do not Disturb" },
    232232        { "xa",    "Extended Away" },
    233         { "",      "Online" },
    234233        { "",      NULL }
    235234};
     
    238237{
    239238        int i;
     239       
     240        if( code == NULL )
     241                return NULL;
    240242       
    241243        for( i = 0; jabber_away_state_list[i].full_name; i ++ )
     
    249251{
    250252        int i;
     253       
     254        if( name == NULL )
     255                return NULL;
    251256       
    252257        for( i = 0; jabber_away_state_list[i].full_name; i ++ )
  • protocols/jabber/presence.c

    rc6ca3ee rfb00989  
    4949                if( !( bud = jabber_buddy_by_jid( ic, from, GET_BUDDY_EXACT | GET_BUDDY_CREAT ) ) )
    5050                {
    51                         if( set_getbool( &ic->irc->set, "debug" ) )
    52                                 imcb_log( ic, "Warning: Could not handle presence information from JID: %s", from );
     51                        /*
     52                        imcb_log( ic, "Warning: Could not handle presence information from JID: %s", from );
     53                        */
    5354                        return XT_HANDLED;
    5455                }
     
    106107                if( ( bud = jabber_buddy_by_jid( ic, from, 0 ) ) == NULL )
    107108                {
    108                         if( set_getbool( &ic->irc->set, "debug" ) )
    109                                 imcb_log( ic, "Warning: Received presence information from unknown JID: %s", from );
     109                        /*
     110                        imcb_log( ic, "Warning: Received presence information from unknown JID: %s", from );
     111                        */
    110112                        return XT_HANDLED;
    111113                }
     
    188190                int is_away = 0;
    189191
    190                 if( send_presence->away_state && !( *send_presence->away_state->code == 0 ||
    191                     strcmp( send_presence->away_state->code, "chat" ) == 0 ) )
     192                if( send_presence->away_state &&
     193                    strcmp( send_presence->away_state->code, "chat" ) != 0 )
    192194                        is_away = OPT_AWAY;
    193195
    194196                imcb_buddy_status( ic, send_presence->bare_jid, OPT_LOGGED_IN | is_away,
    195                                    ( is_away && send_presence->away_state ) ?
    196                                    send_presence->away_state->full_name : NULL,
     197                                   is_away ? send_presence->away_state->full_name : NULL,
    197198                                   send_presence->away_message );
    198199        }
     
    207208        struct jabber_data *jd = ic->proto_data;
    208209        struct xt_node *node, *cap;
    209         char *show = jd->away_state->code;
    210         char *status = jd->away_message;
    211210        struct groupchat *c;
    212211        int st;
     
    214213        node = jabber_make_packet( "presence", NULL, NULL, NULL );
    215214        xt_add_child( node, xt_new_node( "priority", set_getstr( &ic->acc->set, "priority" ), NULL ) );
    216         if( show && *show )
    217                 xt_add_child( node, xt_new_node( "show", show, NULL ) );
    218         if( status )
    219                 xt_add_child( node, xt_new_node( "status", status, NULL ) );
     215        if( jd->away_state )
     216                xt_add_child( node, xt_new_node( "show", jd->away_state->code, NULL ) );
     217        if( jd->away_message )
     218                xt_add_child( node, xt_new_node( "status", jd->away_message, NULL ) );
    220219       
    221220        /* This makes the packet slightly bigger, but clients interested in
  • protocols/msn/msn.c

    rc6ca3ee rfb00989  
    117117{
    118118        struct msn_switchboard *sb;
    119         struct msn_data *md = ic->proto_data;
    120119       
    121120        if( ( sb = msn_sb_by_handle( ic, who ) ) )
     
    126125        {
    127126                struct msn_message *m;
    128                 char buf[1024];
    129127               
    130128                /* Create a message. We have to arrange a usable switchboard, and send the message later. */
     
    133131                m->text = g_strdup( message );
    134132               
    135                 /* FIXME: *CHECK* the reliability of using spare sb's! */
    136                 if( ( sb = msn_sb_spare( ic ) ) )
    137                 {
    138                         debug( "Trying to use a spare switchboard to message %s", who );
    139                        
    140                         sb->who = g_strdup( who );
    141                         g_snprintf( buf, sizeof( buf ), "CAL %d %s\r\n", ++sb->trId, who );
    142                         if( msn_sb_write( sb, buf, strlen( buf ) ) )
    143                         {
    144                                 /* He/She should join the switchboard soon, let's queue the message. */
    145                                 sb->msgq = g_slist_append( sb->msgq, m );
    146                                 return( 1 );
    147                         }
    148                 }
    149                
    150                 debug( "Creating a new switchboard to message %s", who );
    151                
    152                 /* If we reach this line, there was no spare switchboard, so let's make one. */
    153                 g_snprintf( buf, sizeof( buf ), "XFR %d SB\r\n", ++md->trId );
    154                 if( !msn_write( ic, buf, strlen( buf ) ) )
    155                 {
    156                         g_free( m->who );
    157                         g_free( m->text );
    158                         g_free( m );
    159                        
    160                         return( 0 );
    161                 }
    162                
    163                 /* And queue the message to md. We'll pick it up when the switchboard comes up. */
    164                 md->msgq = g_slist_append( md->msgq, m );
    165                
    166                 /* FIXME: If the switchboard creation fails, the message will not be sent. */
    167                
    168                 return( 1 );
     133                return msn_sb_write_msg( ic, m );
    169134        }
    170135       
     
    178143       
    179144        if( l == NULL )
    180                 for( i = 0; msn_away_state_list[i].number > -1; i ++ )
    181                         l = g_list_append( l, (void*) msn_away_state_list[i].name );
     145                for( i = 0; *msn_away_state_list[i].code; i ++ )
     146                        if( *msn_away_state_list[i].name )
     147                                l = g_list_append( l, (void*) msn_away_state_list[i].name );
    182148       
    183149        return l;
     
    188154        char buf[1024];
    189155        struct msn_data *md = ic->proto_data;
    190         const struct msn_away_state *st;
    191        
    192         if( strcmp( state, GAIM_AWAY_CUSTOM ) == 0 )
    193                 st = msn_away_state_by_name( "Away" );
     156       
     157        if( state )
     158                md->away_state = msn_away_state_by_name( state ) ? :
     159                                 msn_away_state_list + 1;
    194160        else
    195                 st = msn_away_state_by_name( state );
    196        
    197         if( !st ) st = msn_away_state_list;
    198         md->away_state = st;
    199        
    200         g_snprintf( buf, sizeof( buf ), "CHG %d %s\r\n", ++md->trId, st->code );
     161                md->away_state = msn_away_state_list;
     162       
     163        g_snprintf( buf, sizeof( buf ), "CHG %d %s\r\n", ++md->trId, md->away_state->code );
    201164        msn_write( ic, buf, strlen( buf ) );
    202165}
     
    256219{
    257220        struct msn_switchboard *sb;
    258         struct msn_data *md = ic->proto_data;
    259         char buf[1024];
    260221       
    261222        if( ( sb = msn_sb_by_handle( ic, who ) ) )
     
    267228        {
    268229                struct msn_message *m;
    269                
    270                 if( ( sb = msn_sb_spare( ic ) ) )
    271                 {
    272                         debug( "Trying to reuse an existing switchboard as a groupchat with %s", who );
    273                         g_snprintf( buf, sizeof( buf ), "CAL %d %s\r\n", ++sb->trId, who );
    274                         if( msn_sb_write( sb, buf, strlen( buf ) ) )
    275                                 return msn_sb_to_chat( sb );
    276                 }
    277                
    278                 /* If the stuff above failed for some reason: */
    279                 debug( "Creating a new switchboard to groupchat with %s", who );
    280                
    281                 /* Request a new switchboard. */
    282                 g_snprintf( buf, sizeof( buf ), "XFR %d SB\r\n", ++md->trId );
    283                 if( !msn_write( ic, buf, strlen( buf ) ) )
    284                         return( 0 );
    285230               
    286231                /* Create a magic message. This is quite hackish, but who cares? :-P */
     
    289234                m->text = g_strdup( GROUPCHAT_SWITCHBOARD_MESSAGE );
    290235               
    291                 /* Queue the magic message and cross your fingers. */
    292                 md->msgq = g_slist_append( md->msgq, m );
    293                
    294                 /* FIXME: Can I try to return something here already? */
     236                msn_sb_write_msg( ic, m );
     237
    295238                return NULL;
    296239        }
  • protocols/msn/msn.h

    rc6ca3ee rfb00989  
    2323  Suite 330, Boston, MA  02111-1307  USA
    2424*/
     25
     26#ifndef _MSN_H
     27#define _MSN_H
    2528
    2629/* Some hackish magicstrings to make special-purpose messages/switchboards.
     
    9497struct msn_away_state
    9598{
    96         int number;
    9799        char code[4];
    98100        char name[16];
     
    176178void msn_sb_destroy( struct msn_switchboard *sb );
    177179gboolean msn_sb_connected( gpointer data, gint source, b_input_condition cond );
     180int msn_sb_write_msg( struct im_connection *ic, struct msn_message *m );
     181
     182#endif //_MSN_H
  • protocols/msn/msn_util.c

    rc6ca3ee rfb00989  
    171171               
    172172                /* End of headers? */
    173                 if( strncmp( text + i - 2, "\n\n", 2 ) == 0 ||
    174                     strncmp( text + i - 4, "\r\n\r\n", 4 ) == 0 ||
    175                     strncmp( text + i - 2, "\r\r", 2 ) == 0 )
     173                if( ( i >= 4 && strncmp( text + i - 4, "\r\n\r\n", 4 ) == 0 ) ||
     174                    ( i >= 2 && ( strncmp( text + i - 2, "\n\n", 2 ) == 0 ||   
     175                                  strncmp( text + i - 2, "\r\r", 2 ) == 0 ) ) )
    176176                {
    177177                        break;
     
    374374        *list = NULL;
    375375       
    376         imcb_log( ic, ret->str );
     376        imcb_log( ic, "%s", ret->str );
    377377        g_string_free( ret, TRUE );
    378378}
  • protocols/msn/ns.c

    rc6ca3ee rfb00989  
    420420                {
    421421                        /* FIXME: Warn/Bomb about unknown away state? */
    422                         st = msn_away_state_list;
    423                 }
    424                
    425                 imcb_buddy_status( ic, cmd[3], OPT_LOGGED_IN |
    426                                    ( st->number ? OPT_AWAY : 0 ), st->name, NULL );
     422                        st = msn_away_state_list + 1;
     423                }
     424               
     425                imcb_buddy_status( ic, cmd[3], OPT_LOGGED_IN |
     426                                   ( st != msn_away_state_list ? OPT_AWAY : 0 ),
     427                                   st->name, NULL );
    427428        }
    428429        else if( strcmp( cmd[0], "FLN" ) == 0 )
     
    449450                {
    450451                        /* FIXME: Warn/Bomb about unknown away state? */
    451                         st = msn_away_state_list;
    452                 }
    453                
    454                 imcb_buddy_status( ic, cmd[2], OPT_LOGGED_IN |
    455                                    ( st->number ? OPT_AWAY : 0 ), st->name, NULL );
     452                        st = msn_away_state_list + 1;
     453                }
     454               
     455                imcb_buddy_status( ic, cmd[2], OPT_LOGGED_IN |
     456                                   ( st != msn_away_state_list ? OPT_AWAY : 0 ),
     457                                   st->name, NULL );
    456458        }
    457459        else if( strcmp( cmd[0], "RNG" ) == 0 )
     
    663665                                }
    664666                               
    665                                 if( arg1 ) g_free( arg1 );
    666                                 if( mtype ) g_free( mtype );
     667                                g_free( arg1 );
     668                                g_free( mtype );
    667669                        }
    668670                        else if( g_strncasecmp( ct, "text/x-msmsgsprofile", 20 ) == 0 )
     
    672674                        else if( g_strncasecmp( ct, "text/x-msmsgsinitialemailnotification", 37 ) == 0 )
    673675                        {
    674                                 char *inbox = msn_findheader( body, "Inbox-Unread:", blen );
    675                                 char *folders = msn_findheader( body, "Folders-Unread:", blen );
    676                                
    677                                 if( inbox && folders && set_getbool( &ic->acc->set, "mail_notifications" ) )
     676                                if( set_getbool( &ic->acc->set, "mail_notifications" ) )
    678677                                {
    679                                         imcb_log( ic, "INBOX contains %s new messages, plus %s messages in other folders.", inbox, folders );
     678                                        char *inbox = msn_findheader( body, "Inbox-Unread:", blen );
     679                                        char *folders = msn_findheader( body, "Folders-Unread:", blen );
     680
     681                                        if( inbox && folders )
     682                                                imcb_log( ic, "INBOX contains %s new messages, plus %s messages in other folders.", inbox, folders );
     683                                       
     684                                        g_free( inbox );
     685                                        g_free( folders );
    680686                                }
    681                                
    682                                 g_free( inbox );
    683                                 g_free( folders );
    684687                        }
    685688                        else if( g_strncasecmp( ct, "text/x-msmsgsemailnotification", 30 ) == 0 )
    686689                        {
    687                                 char *from = msn_findheader( body, "From-Addr:", blen );
    688                                 char *fromname = msn_findheader( body, "From:", blen );
    689                                
    690                                 if( from && fromname && set_getbool( &ic->acc->set, "mail_notifications" ) )
     690                                if( set_getbool( &ic->acc->set, "mail_notifications" ) )
    691691                                {
    692                                         imcb_log( ic, "Received an e-mail message from %s <%s>.", fromname, from );
     692                                        char *from = msn_findheader( body, "From-Addr:", blen );
     693                                        char *fromname = msn_findheader( body, "From:", blen );
     694                                       
     695                                        if( from && fromname )
     696                                                imcb_log( ic, "Received an e-mail message from %s <%s>.", fromname, from );
     697
     698                                        g_free( from );
     699                                        g_free( fromname );
    693700                                }
    694701                        }
  • protocols/msn/sb.c

    rc6ca3ee rfb00989  
    4444                return( 0 );
    4545        }
     46       
     47        return( 1 );
     48}
     49
     50int msn_sb_write_msg( struct im_connection *ic, struct msn_message *m )
     51{
     52        struct msn_data *md = ic->proto_data;
     53        struct msn_switchboard *sb;
     54        char buf[1024];
     55
     56        /* FIXME: *CHECK* the reliability of using spare sb's! */
     57        if( ( sb = msn_sb_spare( ic ) ) )
     58        {
     59                debug( "Trying to use a spare switchboard to message %s", m->who );
     60               
     61                sb->who = g_strdup( m->who );
     62                g_snprintf( buf, sizeof( buf ), "CAL %d %s\r\n", ++sb->trId, m->who );
     63                if( msn_sb_write( sb, buf, strlen( buf ) ) )
     64                {
     65                        /* He/She should join the switchboard soon, let's queue the message. */
     66                        sb->msgq = g_slist_append( sb->msgq, m );
     67                        return( 1 );
     68                }
     69        }
     70       
     71        debug( "Creating a new switchboard to message %s", m->who );
     72       
     73        /* If we reach this line, there was no spare switchboard, so let's make one. */
     74        g_snprintf( buf, sizeof( buf ), "XFR %d SB\r\n", ++md->trId );
     75        if( !msn_write( ic, buf, strlen( buf ) ) )
     76        {
     77                g_free( m->who );
     78                g_free( m->text );
     79                g_free( m );
     80               
     81                return( 0 );
     82        }
     83       
     84        /* And queue the message to md. We'll pick it up when the switchboard comes up. */
     85        md->msgq = g_slist_append( md->msgq, m );
     86       
     87        /* FIXME: If the switchboard creation fails, the message will not be sent. */
    4688       
    4789        return( 1 );
  • protocols/msn/tables.c

    rc6ca3ee rfb00989  
    2929const struct msn_away_state msn_away_state_list[] =
    3030{
    31         {  0, "NLN", "Available" },
    32         {  1, "BSY", "Busy" },
    33         {  3, "IDL", "Idle" },
    34         {  5, "BRB", "Be Right Back" },
    35         {  7, "AWY", "Away" },
    36         {  9, "PHN", "On the Phone" },
    37         { 11, "LUN", "Out to Lunch" },
    38         { 13, "HDN", "Hidden" },
    39         { -1, "",    "" }
     31        { "NLN", "" },
     32        { "AWY", "Away" },
     33        { "BSY", "Busy" },
     34        { "IDL", "Idle" },
     35        { "BRB", "Be Right Back" },
     36        { "PHN", "On the Phone" },
     37        { "LUN", "Out to Lunch" },
     38        { "HDN", "Hidden" },
     39        { "",    "" }
    4040};
    41 
    42 const struct msn_away_state *msn_away_state_by_number( int number )
    43 {
    44         int i;
    45        
    46         for( i = 0; msn_away_state_list[i].number > -1; i ++ )
    47                 if( msn_away_state_list[i].number == number )
    48                         return( msn_away_state_list + i );
    49        
    50         return( NULL );
    51 }
    5241
    5342const struct msn_away_state *msn_away_state_by_code( char *code )
     
    5544        int i;
    5645       
    57         for( i = 0; msn_away_state_list[i].number > -1; i ++ )
     46        for( i = 0; *msn_away_state_list[i].code; i ++ )
    5847                if( g_strcasecmp( msn_away_state_list[i].code, code ) == 0 )
    5948                        return( msn_away_state_list + i );
    6049       
    61         return( NULL );
     50        return NULL;
    6251}
    6352
     
    6655        int i;
    6756       
    68         for( i = 0; msn_away_state_list[i].number > -1; i ++ )
     57        for( i = 0; *msn_away_state_list[i].code; i ++ )
    6958                if( g_strcasecmp( msn_away_state_list[i].name, name ) == 0 )
    7059                        return( msn_away_state_list + i );
    7160       
    72         return( NULL );
     61        return NULL;
    7362}
    7463
  • protocols/nogaim.c

    rc6ca3ee rfb00989  
    22  * BitlBee -- An IRC to other IM-networks gateway                     *
    33  *                                                                    *
    4   * Copyright 2002-2006 Wilmer van der Gaast and others                *
     4  * Copyright 2002-2010 Wilmer van der Gaast and others                *
    55  \********************************************************************/
    66
     
    3333
    3434#define BITLBEE_CORE
     35#include <ctype.h>
     36
    3537#include "nogaim.h"
    36 #include <ctype.h>
     38#include "chat.h"
    3739
    3840static int remove_chat_buddy_silent( struct groupchat *b, const char *handle );
     
    249251void imcb_connected( struct im_connection *ic )
    250252{
     253        irc_t *irc = ic->irc;
     254        struct chat *c;
    251255        user_t *u;
    252256       
     
    264268        ic->flags |= OPT_LOGGED_IN;
    265269       
    266         /* Also necessary when we're not away, at least for some of the
    267            protocols. */
    268         imc_set_away( ic, u->away );
     270        /* Necessary to send initial presence status, even if we're not away. */
     271        imc_away_send_update( ic );
     272       
     273        /* Apparently we're connected successfully, so reset the
     274           exponential backoff timer. */
     275        ic->acc->auto_reconnect_delay = 0;
     276       
     277        for( c = irc->chatrooms; c; c = c->next )
     278        {
     279                if( c->acc != ic->acc )
     280                        continue;
     281               
     282                if( set_getbool( &c->set, "auto_join" ) )
     283                        chat_join( irc, c, NULL );
     284        }
    269285}
    270286
     
    290306        user_t *t, *u;
    291307        account_t *a;
     308        int delay;
    292309       
    293310        /* Nested calls might happen sometimes, this is probably the best
     
    305322        b_event_remove( ic->inpa );
    306323       
     324        g_free( ic->away );
     325        ic->away = NULL;
     326       
    307327        u = irc->users;
    308328        while( u )
     
    329349        }
    330350        else if( allow_reconnect && set_getbool( &irc->set, "auto_reconnect" ) &&
    331                  set_getbool( &a->set, "auto_reconnect" ) )
    332         {
    333                 int delay = set_getint( &irc->set, "auto_reconnect_delay" );
    334                
     351                 set_getbool( &a->set, "auto_reconnect" ) &&
     352                 ( delay = account_reconnect_delay( a ) ) > 0 )
     353        {
    335354                imcb_log( ic, "Reconnecting in %d seconds..", delay );
    336355                a->reconnect = b_timeout_add( delay * 1000, auto_reconnect, a );
     
    429448{
    430449        user_t *u = user_findhandle( ic, handle );
     450        char *set;
    431451       
    432452        if( !u || !realname ) return;
     
    441461                        imcb_log( ic, "User `%s' changed name to `%s'", u->nick, u->realname );
    442462        }
     463       
     464        set = set_getstr( &ic->acc->set, "nick_source" );
     465        if( strcmp( set, "handle" ) != 0 )
     466        {
     467                char *name = g_strdup( realname );
     468               
     469                if( strcmp( set, "first_name" ) == 0 )
     470                {
     471                        int i;
     472                        for( i = 0; name[i] && !isspace( name[i] ); i ++ ) {}
     473                        name[i] = '\0';
     474                }
     475               
     476                imcb_buddy_nick_hint( ic, handle, name );
     477               
     478                g_free( name );
     479        }
    443480}
    444481
     
    453490/* Mainly meant for ICQ (and now also for Jabber conferences) to allow IM
    454491   modules to suggest a nickname for a handle. */
    455 void imcb_buddy_nick_hint( struct im_connection *ic, char *handle, char *nick )
     492void imcb_buddy_nick_hint( struct im_connection *ic, const char *handle, const char *nick )
    456493{
    457494        user_t *u = user_findhandle( ic, handle );
     
    488525}
    489526
    490 /* prpl.c */
    491 
    492 struct show_got_added_data
     527
     528struct imcb_ask_cb_data
    493529{
    494530        struct im_connection *ic;
     
    496532};
    497533
    498 void show_got_added_no( void *data )
    499 {
    500         g_free( ((struct show_got_added_data*)data)->handle );
     534static void imcb_ask_auth_cb_no( void *data )
     535{
     536        struct imcb_ask_cb_data *cbd = data;
     537       
     538        cbd->ic->acc->prpl->auth_deny( cbd->ic, cbd->handle );
     539       
     540        g_free( cbd->handle );
     541        g_free( cbd );
     542}
     543
     544static void imcb_ask_auth_cb_yes( void *data )
     545{
     546        struct imcb_ask_cb_data *cbd = data;
     547       
     548        cbd->ic->acc->prpl->auth_allow( cbd->ic, cbd->handle );
     549       
     550        g_free( cbd->handle );
     551        g_free( cbd );
     552}
     553
     554void imcb_ask_auth( struct im_connection *ic, const char *handle, const char *realname )
     555{
     556        struct imcb_ask_cb_data *data = g_new0( struct imcb_ask_cb_data, 1 );
     557        char *s, *realname_ = NULL;
     558       
     559        if( realname != NULL )
     560                realname_ = g_strdup_printf( " (%s)", realname );
     561       
     562        s = g_strdup_printf( "The user %s%s wants to add you to his/her buddy list.",
     563                             handle, realname_ ?: "" );
     564       
     565        g_free( realname_ );
     566       
     567        data->ic = ic;
     568        data->handle = g_strdup( handle );
     569        query_add( ic->irc, ic, s, imcb_ask_auth_cb_yes, imcb_ask_auth_cb_no, data );
     570}
     571
     572
     573static void imcb_ask_add_cb_no( void *data )
     574{
     575        g_free( ((struct imcb_ask_cb_data*)data)->handle );
    501576        g_free( data );
    502577}
    503578
    504 void show_got_added_yes( void *data )
    505 {
    506         struct show_got_added_data *sga = data;
    507        
    508         sga->ic->acc->prpl->add_buddy( sga->ic, sga->handle, NULL );
    509         /* imcb_add_buddy( sga->ic, NULL, sga->handle, sga->handle ); */
    510        
    511         return show_got_added_no( data );
    512 }
    513 
    514 void imcb_ask_add( struct im_connection *ic, char *handle, const char *realname )
    515 {
    516         struct show_got_added_data *data = g_new0( struct show_got_added_data, 1 );
     579static void imcb_ask_add_cb_yes( void *data )
     580{
     581        struct imcb_ask_cb_data *cbd = data;
     582       
     583        cbd->ic->acc->prpl->add_buddy( cbd->ic, cbd->handle, NULL );
     584       
     585        return imcb_ask_add_cb_no( data );
     586}
     587
     588void imcb_ask_add( struct im_connection *ic, const char *handle, const char *realname )
     589{
     590        struct imcb_ask_cb_data *data = g_new0( struct imcb_ask_cb_data, 1 );
    517591        char *s;
    518592       
     
    525599        data->ic = ic;
    526600        data->handle = g_strdup( handle );
    527         query_add( ic->irc, ic, s, show_got_added_yes, show_got_added_no, data );
     601        query_add( ic->irc, ic, s, imcb_ask_add_cb_yes, imcb_ask_add_cb_no, data );
    528602}
    529603
     
    924998        int st;
    925999       
    926         if( ( g_strcasecmp( value, "true" ) == 0 ) || ( g_strcasecmp( value, "yes" ) == 0 ) || ( g_strcasecmp( value, "on" ) == 0 ) )
    927                 st = 1;
    928         else if( ( g_strcasecmp( value, "false" ) == 0 ) || ( g_strcasecmp( value, "no" ) == 0 ) || ( g_strcasecmp( value, "off" ) == 0 ) )
    929                 st = 0;
    930         else if( sscanf( value, "%d", &st ) != 1 )
    931                 return( NULL );
    932        
    933         st = st != 0;
     1000        if( !is_bool( value ) )
     1001                return SET_INVALID;
     1002       
     1003        st = bool2int( value );
    9341004       
    9351005        /* Horror.... */
     
    9751045        }
    9761046       
    977         return( set_eval_bool( set, value ) );
     1047        return value;
    9781048}
    9791049
     
    10171087}
    10181088
    1019 static char *imc_away_alias_find( GList *gcm, char *away );
    1020 
    1021 int imc_set_away( struct im_connection *ic, char *away )
    1022 {
    1023         GList *m, *ms;
    1024         char *s;
    1025        
    1026         if( !away ) away = "";
    1027         ms = m = ic->acc->prpl->away_states( ic );
    1028        
    1029         while( m )
    1030         {
    1031                 if( *away )
    1032                 {
    1033                         if( g_strncasecmp( m->data, away, strlen( m->data ) ) == 0 )
    1034                                 break;
    1035                 }
    1036                 else
    1037                 {
    1038                         if( g_strcasecmp( m->data, "Available" ) == 0 )
    1039                                 break;
    1040                         if( g_strcasecmp( m->data, "Online" ) == 0 )
    1041                                 break;
    1042                 }
    1043                 m = m->next;
    1044         }
    1045        
    1046         if( m )
    1047         {
    1048                 ic->acc->prpl->set_away( ic, m->data, *away ? away : NULL );
    1049         }
    1050         else
    1051         {
    1052                 s = imc_away_alias_find( ms, away );
    1053                 if( s )
    1054                 {
    1055                         ic->acc->prpl->set_away( ic, s, away );
    1056                         if( set_getbool( &ic->irc->set, "debug" ) )
    1057                                 imcb_log( ic, "Setting away state to %s", s );
    1058                 }
    1059                 else
    1060                         ic->acc->prpl->set_away( ic, GAIM_AWAY_CUSTOM, away );
    1061         }
    1062        
    1063         return( 1 );
     1089static char *imc_away_state_find( GList *gcm, char *away, char **message );
     1090
     1091int imc_away_send_update( struct im_connection *ic )
     1092{
     1093        char *away, *msg = NULL;
     1094       
     1095        away = set_getstr( &ic->acc->set, "away" ) ?
     1096             : set_getstr( &ic->irc->set, "away" );
     1097        if( away && *away )
     1098        {
     1099                GList *m = ic->acc->prpl->away_states( ic );
     1100                msg = ic->acc->flags & ACC_FLAG_AWAY_MESSAGE ? away : NULL;
     1101                away = imc_away_state_find( m, away, &msg ) ? : m->data;
     1102        }
     1103        else if( ic->acc->flags & ACC_FLAG_STATUS_MESSAGE )
     1104        {
     1105                away = NULL;
     1106                msg = set_getstr( &ic->acc->set, "status" ) ?
     1107                    : set_getstr( &ic->irc->set, "status" );
     1108        }
     1109       
     1110        ic->acc->prpl->set_away( ic, away, msg );
     1111       
     1112        return 1;
    10641113}
    10651114
     
    10761125};
    10771126
    1078 static char *imc_away_alias_find( GList *gcm, char *away )
     1127static char *imc_away_state_find( GList *gcm, char *away, char **message )
    10791128{
    10801129        GList *m;
    10811130        int i, j;
    10821131       
     1132        for( m = gcm; m; m = m->next )
     1133                if( g_strncasecmp( m->data, away, strlen( m->data ) ) == 0 )
     1134                {
     1135                        /* At least the Yahoo! module works better if message
     1136                           contains no data unless it adds something to what
     1137                           we have in state already. */
     1138                        if( strlen( m->data ) == strlen( away ) )
     1139                                *message = NULL;
     1140                       
     1141                        return m->data;
     1142                }
     1143       
    10831144        for( i = 0; *imc_away_alias_list[i]; i ++ )
    10841145        {
     1146                int keep_message;
     1147               
    10851148                for( j = 0; imc_away_alias_list[i][j]; j ++ )
    10861149                        if( g_strncasecmp( away, imc_away_alias_list[i][j], strlen( imc_away_alias_list[i][j] ) ) == 0 )
     1150                        {
     1151                                keep_message = strlen( away ) != strlen( imc_away_alias_list[i][j] );
    10871152                                break;
     1153                        }
    10881154               
    10891155                if( !imc_away_alias_list[i][j] )        /* If we reach the end, this row */
     
    10931159                for( j = 0; imc_away_alias_list[i][j]; j ++ )
    10941160                {
    1095                         m = gcm;
    1096                         while( m )
    1097                         {
     1161                        for( m = gcm; m; m = m->next )
    10981162                                if( g_strcasecmp( imc_away_alias_list[i][j], m->data ) == 0 )
    1099                                         return( imc_away_alias_list[i][j] );
    1100                                 m = m->next;
    1101                         }
    1102                 }
    1103         }
    1104        
    1105         return( NULL );
     1163                                {
     1164                                        if( !keep_message )
     1165                                                *message = NULL;
     1166                                       
     1167                                        return imc_away_alias_list[i][j];
     1168                                }
     1169                }
     1170               
     1171                /* No need to look further, apparently this state doesn't
     1172                   have any good alias for this protocol. */
     1173                break;
     1174        }
     1175       
     1176        return NULL;
    11061177}
    11071178
  • protocols/nogaim.h

    rc6ca3ee rfb00989  
    3939#define _NOGAIM_H
    4040
     41#include <stdint.h>
     42
    4143#include "bitlbee.h"
    4244#include "account.h"
     
    4749
    4850#define WEBSITE "http://www.bitlbee.org/"
    49 #define GAIM_AWAY_CUSTOM "Custom"
    5051
    5152/* Sharing flags between all kinds of things. I just hope I won't hit any
     
    208209         * not implement this. */
    209210        struct groupchat *
    210              (* chat_join)      (struct im_connection *, char *room, char *nick, char *password);
     211             (* chat_join)      (struct im_connection *, const char *room, const char *nick, const char *password);
    211212        /* Change the topic, if supported. Note that BitlBee expects the IM
    212213           server to confirm the topic change with a regular topic change
     
    216217       
    217218        /* You can tell what away states your protocol supports, so that
    218          * BitlBee will try to map the IRC away reasons to them, or use
    219          * GAIM_AWAY_CUSTOM when calling skype_set_away(). */
     219         * BitlBee will try to map the IRC away reasons to them. If your
     220         * protocol doesn't have any, just return one generic "Away". */
    220221        GList *(* away_states)(struct im_connection *ic);
    221222       
     
    223224         * - Most protocols will just want to set this to g_strcasecmp().*/
    224225        int (* handle_cmp) (const char *who1, const char *who2);
     226
     227        /* Implement these callbacks if you want to use imcb_ask_auth() */
     228        void (* auth_allow)     (struct im_connection *, const char *who);
     229        void (* auth_deny)      (struct im_connection *, const char *who);
    225230};
    226231
     
    238243 * the account_t parameter. */
    239244G_MODULE_EXPORT struct im_connection *imcb_new( account_t *acc );
    240 G_MODULE_EXPORT void imcb_free( struct im_connection *ic );
     245G_MODULE_EXPORT void imc_free( struct im_connection *ic );
    241246/* Once you're connected, you should call this function, so that the user will
    242247 * see the success. */
     
    251256/* To tell the user an error, ie. before logging out when an error occurs. */
    252257G_MODULE_EXPORT void imcb_error( struct im_connection *ic, char *format, ... ) G_GNUC_PRINTF( 2, 3 );
     258
    253259/* To ask a your about something.
    254260 * - 'msg' is the question.
     
    257263 */
    258264G_MODULE_EXPORT void imcb_ask( struct im_connection *ic, char *msg, void *data, query_callback doit, query_callback dont );
    259 G_MODULE_EXPORT void imcb_ask_add( struct im_connection *ic, char *handle, const char *realname );
     265
     266/* Two common questions you may want to ask:
     267 * - X added you to his contact list, allow?
     268 * - X is not in your contact list, want to add?
     269 */
     270G_MODULE_EXPORT void imcb_ask_auth( struct im_connection *ic, const char *handle, const char *realname );
     271G_MODULE_EXPORT void imcb_ask_add( struct im_connection *ic, const char *handle, const char *realname );
    260272
    261273/* Buddy management */
     
    267279G_MODULE_EXPORT struct buddy *imcb_find_buddy( struct im_connection *ic, char *handle );
    268280G_MODULE_EXPORT void imcb_rename_buddy( struct im_connection *ic, const char *handle, const char *realname );
    269 G_MODULE_EXPORT void imcb_buddy_nick_hint( struct im_connection *ic, char *handle, char *nick );
     281G_MODULE_EXPORT void imcb_buddy_nick_hint( struct im_connection *ic, const char *handle, const char *nick );
    270282
    271283/* Buddy activity */
     
    302314
    303315/* Actions, or whatever. */
    304 int imc_set_away( struct im_connection *ic, char *away );
     316int imc_away_send_update( struct im_connection *ic );
    305317int imc_buddy_msg( struct im_connection *ic, char *handle, char *msg, int flags );
    306318int imc_chat_msg( struct groupchat *c, char *msg, int flags );
  • protocols/oscar/aim.h

    rc6ca3ee rfb00989  
    144144}
    145145
     146#define AIM_CLIENTINFO_KNOWNGOOD_5_1_3036 { \
     147        "AOL Instant Messenger, version 5.1.3036/WIN32", \
     148        0x0109, \
     149        0x0005, \
     150        0x0001, \
     151        0x0000, \
     152        0x0bdc, \
     153        "us", \
     154        "en", \
     155}
     156
    146157/*
    147158 * I would make 4.1.2010 the default, but they seem to have found
     
    152163 * around. (see login.c::memrequest())
    153164 */
    154 #define AIM_CLIENTINFO_KNOWNGOOD AIM_CLIENTINFO_KNOWNGOOD_3_5_1670
     165#define AIM_CLIENTINFO_KNOWNGOOD AIM_CLIENTINFO_KNOWNGOOD_5_1_3036
    155166
    156167#ifndef TRUE
  • protocols/oscar/oscar.c

    rc6ca3ee rfb00989  
    9191        GSList *oscar_chats;
    9292
    93         gboolean killme;
     93        gboolean killme, no_reconnect;
    9494        gboolean icq;
    9595        GSList *evilhack;
     
    181181static int gaim_parse_auth_resp  (aim_session_t *, aim_frame_t *, ...);
    182182static int gaim_parse_login      (aim_session_t *, aim_frame_t *, ...);
     183static int gaim_parse_logout     (aim_session_t *, aim_frame_t *, ...);
    183184static int gaim_handle_redirect  (aim_session_t *, aim_frame_t *, ...);
    184185static int gaim_parse_oncoming   (aim_session_t *, aim_frame_t *, ...);
     
    294295                        aim_rxdispatch(odata->sess);
    295296                               if (odata->killme)
    296                                        imc_logout(ic, TRUE);
     297                                       imc_logout(ic, !odata->no_reconnect);
    297298                } else {
    298299                        if ((conn->type == AIM_CONN_TYPE_BOS) ||
     
    379380                s->flags |= ACC_SET_OFFLINE_ONLY;
    380381        }
     382       
     383        acc->flags |= ACC_FLAG_AWAY_MESSAGE;
    381384}
    382385
     
    520523                case 0x18:
    521524                        /* connecting too frequently */
     525                        od->no_reconnect = TRUE;
    522526                        imcb_error(ic, _("You have been connecting and disconnecting too frequently. Wait ten minutes and try again. If you continue to try, you will need to wait even longer."));
    523527                        break;
     
    572576        aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO, gaim_parseaiminfo, 0);
    573577        aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_MTN, gaim_parsemtn, 0);
     578        aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, gaim_parse_logout, 0);
    574579
    575580        ((struct oscar_data *)ic->proto_data)->conn = bosconn;
     
    747752
    748753        aim_send_login(sess, fr->conn, ic->acc->user, ic->acc->pass, &info, key);
     754
     755        return 1;
     756}
     757
     758static int gaim_parse_logout(aim_session_t *sess, aim_frame_t *fr, ...) {
     759        struct im_connection *ic = sess->aux_data;
     760        struct oscar_data *odata = ic->proto_data;
     761        int code;
     762        va_list ap;
     763
     764        va_start(ap, fr);
     765        code = va_arg(ap, int);
     766        va_end(ap);
     767       
     768        imcb_error( ic, "Connection aborted by server: %s", code == 1 ?
     769                        "someone else logged in with your account" :
     770                        "unknown reason" );
     771       
     772        /* Tell BitlBee to disable auto_reconnect if code == 1, since that
     773           means a concurrent login somewhere else. */
     774        odata->no_reconnect = code == 1;
     775       
     776        /* DO NOT log out here! Just tell the callback to do it. */
     777        odata->killme = TRUE;
    749778
    750779        return 1;
     
    19251954static void oscar_set_away_aim(struct im_connection *ic, struct oscar_data *od, const char *state, const char *message)
    19261955{
     1956        if (state == NULL)
     1957                state = "";
    19271958
    19281959        if (!g_strcasecmp(state, _("Visible"))) {
     
    19321963                aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_INVISIBLE);
    19331964                return;
    1934         } /* else... */
     1965        } else if (message == NULL) {
     1966                message = state;
     1967        }
    19351968
    19361969        if (od->rights.maxawaymsglen == 0)
     
    19391972        aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_NORMAL);
    19401973
    1941         if (ic->away)
    1942                 g_free(ic->away);
     1974        g_free(ic->away);
    19431975        ic->away = NULL;
    19441976
     
    19601992static void oscar_set_away_icq(struct im_connection *ic, struct oscar_data *od, const char *state, const char *message)
    19611993{
    1962     const char *msg = NULL;
     1994        const char *msg = NULL;
    19631995        gboolean no_message = FALSE;
    19641996
    19651997        /* clean old states */
    1966     if (ic->away) {
    1967                 g_free(ic->away);
    1968                 ic->away = NULL;
    1969     }
     1998        g_free(ic->away);
     1999        ic->away = NULL;
    19702000        od->sess->aim_icq_state = 0;
    19712001
    19722002        /* if no message, then use an empty message */
    1973     if (message) {
    1974         msg = message;
    1975     } else {
    1976         msg = "";
     2003        if (message) {
     2004                msg = message;
     2005        } else {
     2006                msg = "";
    19772007                no_message = TRUE;
    1978     }
    1979 
    1980         if (!g_strcasecmp(state, "Online")) {
     2008        }
     2009
     2010        if (state == NULL) {
    19812011                aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_NORMAL);
    19822012        } else if (!g_strcasecmp(state, "Away")) {
    19832013                aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_AWAY);
    1984         ic->away = g_strdup(msg);
     2014                ic->away = g_strdup(msg);
    19852015                od->sess->aim_icq_state = AIM_MTYPE_AUTOAWAY;
    19862016        } else if (!g_strcasecmp(state, "Do Not Disturb")) {
    19872017                aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_DND | AIM_ICQ_STATE_BUSY);
    1988         ic->away = g_strdup(msg);
     2018                ic->away = g_strdup(msg);
    19892019                od->sess->aim_icq_state = AIM_MTYPE_AUTODND;
    19902020        } else if (!g_strcasecmp(state, "Not Available")) {
    19912021                aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_OUT | AIM_ICQ_STATE_AWAY);
    1992         ic->away = g_strdup(msg);
     2022                ic->away = g_strdup(msg);
    19932023                od->sess->aim_icq_state = AIM_MTYPE_AUTONA;
    19942024        } else if (!g_strcasecmp(state, "Occupied")) {
    19952025                aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_BUSY);
    1996         ic->away = g_strdup(msg);
     2026                ic->away = g_strdup(msg);
    19972027                od->sess->aim_icq_state = AIM_MTYPE_AUTOBUSY;
    19982028        } else if (!g_strcasecmp(state, "Free For Chat")) {
    19992029                aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_CHAT);
    2000         ic->away = g_strdup(msg);
     2030                ic->away = g_strdup(msg);
    20012031                od->sess->aim_icq_state = AIM_MTYPE_AUTOFFC;
    20022032        } else if (!g_strcasecmp(state, "Invisible")) {
    20032033                aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_INVISIBLE);
    2004         ic->away = g_strdup(msg);
    2005         } else if (!g_strcasecmp(state, GAIM_AWAY_CUSTOM)) {
     2034                ic->away = g_strdup(msg);
     2035        } else {
    20062036                if (no_message) {
    20072037                        aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_NORMAL);
    20082038                } else {
    20092039                        aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_AWAY);
    2010             ic->away = g_strdup(msg);
     2040                        ic->away = g_strdup(msg);
    20112041                        od->sess->aim_icq_state = AIM_MTYPE_AUTOAWAY;
    20122042                }
     
    20202050        struct oscar_data *od = (struct oscar_data *)ic->proto_data;
    20212051
    2022     oscar_set_away_aim(ic, od, state, message);
     2052        oscar_set_away_aim(ic, od, state, message);
    20232053        if (od->icq)
    20242054                oscar_set_away_icq(ic, od, state, message);
     
    22522282{
    22532283        struct oscar_data *od = ic->proto_data;
    2254         GList *m = NULL;
    2255 
    2256         if (!od->icq)
    2257                 return g_list_append(m, GAIM_AWAY_CUSTOM);
    2258 
    2259         m = g_list_append(m, "Online");
    2260         m = g_list_append(m, "Away");
    2261         m = g_list_append(m, "Do Not Disturb");
    2262         m = g_list_append(m, "Not Available");
    2263         m = g_list_append(m, "Occupied");
    2264         m = g_list_append(m, "Free For Chat");
    2265         m = g_list_append(m, "Invisible");
    2266 
    2267         return m;
     2284
     2285        if (od->icq) {
     2286                static GList *m = NULL;
     2287                m = g_list_append(m, "Away");
     2288                m = g_list_append(m, "Do Not Disturb");
     2289                m = g_list_append(m, "Not Available");
     2290                m = g_list_append(m, "Occupied");
     2291                m = g_list_append(m, "Free For Chat");
     2292                m = g_list_append(m, "Invisible");
     2293                return m;
     2294        } else {
     2295                static GList *m = NULL;
     2296                m = g_list_append(m, "Away");
     2297                return m;
     2298        }
    22682299}
    22692300
     
    25812612}
    25822613
    2583 struct groupchat *oscar_chat_join(struct im_connection * ic, char * room, char * nick, char * password )
     2614struct groupchat *oscar_chat_join(struct im_connection * ic, const char * room, const char * nick, const char * password )
    25842615{
    25852616        struct oscar_data * od = (struct oscar_data *)ic->proto_data;
  • protocols/yahoo/libyahoo2.c

    rc6ca3ee rfb00989  
    8989
    9090#include "base64.h"
     91#include "http_client.h"
    9192
    9293#ifdef USE_STRUCT_CALLBACKS
     
    169170        YAHOO_SERVICE_GOTGROUPRENAME, /* < 1, 36(old), 37(new) */
    170171        YAHOO_SERVICE_SYSMESSAGE = 0x14,
     172        YAHOO_SERVICE_SKINNAME = 0x15,
    171173        YAHOO_SERVICE_PASSTHROUGH2 = 0x16,
    172174        YAHOO_SERVICE_CONFINVITE = 0x18,
     
    192194        YAHOO_SERVICE_LIST,
    193195        YAHOO_SERVICE_AUTH = 0x57,
     196        YAHOO_SERVICE_AUTHBUDDY = 0x6d,
    194197        YAHOO_SERVICE_ADDBUDDY = 0x83,
    195198        YAHOO_SERVICE_REMBUDDY,
     
    197200        YAHOO_SERVICE_REJECTCONTACT,
    198201        YAHOO_SERVICE_GROUPRENAME = 0x89, /* > 1, 65(new), 66(0), 67(old) */
     202        YAHOO_SERVICE_Y7_PING = 0x8A, /* 0 - id and that's it?? */
    199203        YAHOO_SERVICE_CHATONLINE = 0x96, /* > 109(id), 1, 6(abcde) < 0,1*/
    200204        YAHOO_SERVICE_CHATGOTO,
     
    202206        YAHOO_SERVICE_CHATLEAVE,
    203207        YAHOO_SERVICE_CHATEXIT = 0x9b,
     208        YAHOO_SERVICE_CHATADDINVITE = 0x9d,
    204209        YAHOO_SERVICE_CHATLOGOUT = 0xa0,
    205210        YAHOO_SERVICE_CHATPING,
     
    209214        YAHOO_SERVICE_PICTURE = 0xbe,
    210215        YAHOO_SERVICE_PICTURE_UPDATE = 0xc1,
    211         YAHOO_SERVICE_PICTURE_UPLOAD = 0xc2
     216        YAHOO_SERVICE_PICTURE_UPLOAD = 0xc2,
     217        YAHOO_SERVICE_Y6_VISIBILITY=0xc5,
     218        YAHOO_SERVICE_Y6_STATUS_UPDATE=0xc6,
     219        YAHOO_PHOTOSHARE_INIT=0xd2,     
     220        YAHOO_SERVICE_CONTACT_YMSG13=0xd6,
     221        YAHOO_PHOTOSHARE_PREV=0xd7,
     222        YAHOO_PHOTOSHARE_KEY=0xd8,
     223        YAHOO_PHOTOSHARE_TRANS=0xda,
     224        YAHOO_FILE_TRANSFER_INIT_YMSG13=0xdc,
     225        YAHOO_FILE_TRANSFER_GET_YMSG13=0xdd,
     226        YAHOO_FILE_TRANSFER_PUT_YMSG13=0xde,
     227        YAHOO_SERVICE_YMSG15_STATUS=0xf0,
     228        YAHOO_SERVICE_YMSG15_BUDDY_LIST=0xf1,
    212229};
    213230
     
    733750
    734751        memcpy(data + pos, "YMSG", 4); pos += 4;
    735         pos += yahoo_put16(data + pos, 0x000c);
     752        pos += yahoo_put16(data + pos, YAHOO_PROTO_VER);
    736753        pos += yahoo_put16(data + pos, 0x0000);
    737754        pos += yahoo_put16(data + pos, pktlen + extra_pad);
     
    747764                yahoo_send_data(yid->fd, data, len);
    748765        else
    749         yahoo_add_to_send_queue(yid, data, len);
     766                yahoo_add_to_send_queue(yid, data, len);
    750767        FREE(data);
    751768}
     
    836853
    837854        return strcmp(subject->id, object->id);
    838 }
    839 
    840 static YList * bud_str2list(char *rawlist)
    841 {
    842         YList * l = NULL;
    843 
    844         char **lines;
    845         char **split;
    846         char **buddies;
    847         char **tmp, **bud;
    848 
    849         lines = y_strsplit(rawlist, "\n", -1);
    850         for (tmp = lines; *tmp; tmp++) {
    851                 struct yahoo_buddy *newbud;
    852 
    853                 split = y_strsplit(*tmp, ":", 2);
    854                 if (!split)
    855                         continue;
    856                 if (!split[0] || !split[1]) {
    857                         y_strfreev(split);
    858                         continue;
    859                 }
    860                 buddies = y_strsplit(split[1], ",", -1);
    861 
    862                 for (bud = buddies; bud && *bud; bud++) {
    863                         newbud = y_new0(struct yahoo_buddy, 1);
    864                         newbud->id = strdup(*bud);
    865                         newbud->group = strdup(split[0]);
    866 
    867                         if(y_list_find_custom(l, newbud, is_same_bud)) {
    868                                 FREE(newbud->id);
    869                                 FREE(newbud->group);
    870                                 FREE(newbud);
    871                                 continue;
    872                         }
    873 
    874                         newbud->real_name = NULL;
    875 
    876                         l = y_list_append(l, newbud);
    877 
    878                         NOTICE(("Added buddy %s to group %s", newbud->id, newbud->group));
    879                 }
    880 
    881                 y_strfreev(buddies);
    882                 y_strfreev(split);
    883         }
    884         y_strfreev(lines);
    885 
    886         return l;
    887855}
    888856
     
    13431311}
    13441312
    1345 
    1346 static void yahoo_process_status(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
     1313static void yahoo_process_status(struct yahoo_input_data *yid,
     1314        struct yahoo_packet *pkt)
    13471315{
    13481316        YList *l;
    13491317        struct yahoo_data *yd = yid->yd;
    13501318
    1351         struct user
    1352         {
    1353                 char *name;     /* 7    name */
    1354                 int   state;    /* 10   state */
    1355                 int   flags;    /* 13   flags, bit 0 = pager, bit 1 = chat, bit 2 = game */
    1356                 int   mobile;   /* 60   mobile */
    1357                 char *msg;      /* 19   custom status message */
    1358                 int   away;     /* 47   away (or invisible)*/
    1359                 int   buddy_session;    /* 11   state */
    1360                 int   f17;      /* 17   in chat? then what about flags? */
    1361                 int   idle;     /* 137  seconds idle */
    1362                 int   f138;     /* 138  state */
    1363                 char *f184;     /* 184  state */
    1364                 int   f192;     /* 192  state */
    1365                 int   f10001;   /* 10001        state */
    1366                 int   f10002;   /* 10002        state */
    1367                 int   f198;     /* 198  state */
    1368                 char *f197;     /* 197  state */
    1369                 char *f205;     /* 205  state */
    1370                 int   f213;     /* 213  state */
    1371         } *u;
     1319        struct yahoo_process_status_entry *u;
    13721320
    13731321        YList *users = 0;
    1374        
     1322
    13751323        if (pkt->service == YAHOO_SERVICE_LOGOFF && pkt->status == -1) {
    1376                 YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_DUPL, NULL);
    1377                 return;
    1378         }
     1324                YAHOO_CALLBACK(ext_yahoo_login_response) (yd->client_id,
     1325                        YAHOO_LOGIN_DUPL, NULL);
     1326                return;
     1327        }
     1328
     1329        /* Status updates may be spread accross multiple packets and not
     1330           even on buddy boundaries, so keeping some state is important.
     1331           So, continue where we left off, and only add a user entry to
     1332           the list once it's complete (301-315 End buddy). */
     1333        u = yd->half_user;
    13791334
    13801335        for (l = pkt->hash; l; l = l->next) {
     
    13821337
    13831338                switch (pair->key) {
    1384                 case 0: /* we won't actually do anything with this */
     1339                case 300:       /* Begin buddy */
     1340                        if (!strcmp(pair->value, "315") && !u) {
     1341                                u = yd->half_user = y_new0(struct yahoo_process_status_entry, 1);
     1342                        }
     1343                        break;
     1344                case 301:       /* End buddy */
     1345                        if (!strcmp(pair->value, "315") && u) {
     1346                                users = y_list_prepend(users, u);
     1347                                u = yd->half_user = NULL;
     1348                        }
     1349                        break;
     1350                case 0: /* we won't actually do anything with this */
    13851351                        NOTICE(("key %d:%s", pair->key, pair->value));
    13861352                        break;
    1387                 case 1: /* we don't get the full buddy list here. */
     1353                case 1: /* we don't get the full buddy list here. */
    13881354                        if (!yd->logged_in) {
    1389                                 yd->logged_in = TRUE;
    1390                                 if(yd->current_status < 0)
     1355                                yd->logged_in = 1;
     1356                                if (yd->current_status < 0)
    13911357                                        yd->current_status = yd->initial_status;
    1392                                 YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_OK, NULL);
     1358                                YAHOO_CALLBACK(ext_yahoo_login_response) (yd->
     1359                                        client_id, YAHOO_LOGIN_OK, NULL);
    13931360                        }
    13941361                        break;
    1395                 case 8: /* how many online buddies we have */
     1362                case 8: /* how many online buddies we have */
    13961363                        NOTICE(("key %d:%s", pair->key, pair->value));
    13971364                        break;
    1398                 case 7: /* the current buddy */
    1399                         u = y_new0(struct user, 1);
     1365                case 7: /* the current buddy */
     1366                        if (!u) {
     1367                                /* This will only happen in case of a single level message */
     1368                                u = y_new0(struct yahoo_process_status_entry, 1);
     1369                                users = y_list_prepend(users, u);
     1370                        }
    14001371                        u->name = pair->value;
    1401                         users = y_list_prepend(users, u);
    1402                         break;
    1403                 case 10: /* state */
    1404                         ((struct user*)users->data)->state = strtol(pair->value, NULL, 10);
    1405                         break;
    1406                 case 19: /* custom status message */
    1407                         ((struct user*)users->data)->msg = pair->value;
    1408                         break;
    1409                 case 47: /* is it an away message or not */
    1410                         ((struct user*)users->data)->away = atoi(pair->value);
    1411                         break;
    1412                 case 137: /* seconds idle */
    1413                         ((struct user*)users->data)->idle = atoi(pair->value);
    1414                         break;
    1415                 case 11: /* this is the buddy's session id */
    1416                         ((struct user*)users->data)->buddy_session = atoi(pair->value);
    1417                         break;
    1418                 case 17: /* in chat? */
    1419                         ((struct user*)users->data)->f17 = atoi(pair->value);
    1420                         break;
    1421                 case 13: /* bitmask, bit 0 = pager, bit 1 = chat, bit 2 = game */
    1422                         ((struct user*)users->data)->flags = atoi(pair->value);
    1423                         break;
    1424                 case 60: /* SMS -> 1 MOBILE USER */
     1372                        break;
     1373                case 10:        /* state */
     1374                        u->state = strtol(pair->value, NULL, 10);
     1375                        break;
     1376                case 19:        /* custom status message */
     1377                        u->msg = pair->value;
     1378                        break;
     1379                case 47:        /* is it an away message or not. Not applicable for YMSG16 anymore */
     1380                        u->away = atoi(pair->value);
     1381                        break;
     1382                case 137:       /* seconds idle */
     1383                        u->idle = atoi(pair->value);
     1384                        break;
     1385                case 11:        /* this is the buddy's session id */
     1386                        u->buddy_session = atoi(pair->value);
     1387                        break;
     1388                case 17:        /* in chat? */
     1389                        u->f17 = atoi(pair->value);
     1390                        break;
     1391                case 13:        /* bitmask, bit 0 = pager, bit 1 = chat, bit 2 = game */
     1392                        u->flags = atoi(pair->value);
     1393                        break;
     1394                case 60:        /* SMS -> 1 MOBILE USER */
    14251395                        /* sometimes going offline makes this 2, but invisible never sends it */
    1426                         ((struct user*)users->data)->mobile = atoi(pair->value);
     1396                        u->mobile = atoi(pair->value);
    14271397                        break;
    14281398                case 138:
    1429                         ((struct user*)users->data)->f138 = atoi(pair->value);
     1399                        u->f138 = atoi(pair->value);
    14301400                        break;
    14311401                case 184:
    1432                         ((struct user*)users->data)->f184 = pair->value;
     1402                        u->f184 = pair->value;
    14331403                        break;
    14341404                case 192:
    1435                         ((struct user*)users->data)->f192 = atoi(pair->value);
     1405                        u->f192 = atoi(pair->value);
    14361406                        break;
    14371407                case 10001:
    1438                         ((struct user*)users->data)->f10001 = atoi(pair->value);
     1408                        u->f10001 = atoi(pair->value);
    14391409                        break;
    14401410                case 10002:
    1441                         ((struct user*)users->data)->f10002 = atoi(pair->value);
     1411                        u->f10002 = atoi(pair->value);
    14421412                        break;
    14431413                case 198:
    1444                         ((struct user*)users->data)->f198 = atoi(pair->value);
     1414                        u->f198 = atoi(pair->value);
    14451415                        break;
    14461416                case 197:
    1447                         ((struct user*)users->data)->f197 = pair->value;
     1417                        u->f197 = pair->value;
    14481418                        break;
    14491419                case 205:
    1450                         ((struct user*)users->data)->f205 = pair->value;
     1420                        u->f205 = pair->value;
    14511421                        break;
    14521422                case 213:
    1453                         ((struct user*)users->data)->f213 = atoi(pair->value);
    1454                         break;
    1455                 case 16: /* Custom error message */
    1456                         YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, pair->value, 0, E_CUSTOM);
     1423                        u->f213 = atoi(pair->value);
     1424                        break;
     1425                case 16:        /* Custom error message */
     1426                        YAHOO_CALLBACK(ext_yahoo_error) (yd->client_id,
     1427                                pair->value, 0, E_CUSTOM);
    14571428                        break;
    14581429                default:
    1459                         WARNING(("unknown status key %d:%s", pair->key, pair->value));
    1460                         break;
    1461                 }
    1462         }
    1463        
     1430                        WARNING(("unknown status key %d:%s", pair->key,
     1431                                        pair->value));
     1432                        break;
     1433                }
     1434        }
     1435
    14641436        while (users) {
    14651437                YList *t = users;
    1466                 struct user *u = users->data;
     1438                struct yahoo_process_status_entry *u = users->data;
    14671439
    14681440                if (u->name != NULL) {
    1469                         if (pkt->service == YAHOO_SERVICE_LOGOFF || u->flags == 0) {
    1470                                 YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, u->name, YAHOO_STATUS_OFFLINE, NULL, 1, 0, 0);
     1441                        if (pkt->service ==
     1442                                YAHOO_SERVICE_LOGOFF
     1443                                /*|| u->flags == 0 No flags for YMSG16 */ ) {
     1444                                YAHOO_CALLBACK(ext_yahoo_status_changed) (yd->
     1445                                        client_id, u->name,
     1446                                        YAHOO_STATUS_OFFLINE, NULL, 1, 0, 0);
    14711447                        } else {
    1472                                 YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, u->name, u->state, u->msg, u->away, u->idle, u->mobile);
     1448                                /* Key 47 always seems to be 1 for YMSG16 */
     1449                                if (!u->state)
     1450                                        u->away = 0;
     1451                                else
     1452                                        u->away = 1;
     1453
     1454                                YAHOO_CALLBACK(ext_yahoo_status_changed) (yd->
     1455                                        client_id, u->name, u->state, u->msg,
     1456                                        u->away, u->idle, u->mobile);
    14731457                        }
    14741458                }
     
    14801464}
    14811465
    1482 static void yahoo_process_list(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
     1466static void yahoo_process_buddy_list(struct yahoo_input_data *yid,
     1467        struct yahoo_packet *pkt)
    14831468{
    14841469        struct yahoo_data *yd = yid->yd;
    14851470        YList *l;
    1486 
    1487         if (!yd->logged_in) {
    1488                 yd->logged_in = TRUE;
    1489                 if(yd->current_status < 0)
    1490                         yd->current_status = yd->initial_status;
    1491                 YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_OK, NULL);
    1492         }
    1493 
     1471        int last_packet = 0;
     1472        char *cur_group = NULL;
     1473        struct yahoo_buddy *newbud = NULL;
     1474
     1475        /* we could be getting multiple packets here */
    14941476        for (l = pkt->hash; l; l = l->next) {
    14951477                struct yahoo_pair *pair = l->data;
    14961478
    1497                 switch(pair->key) {
    1498                 case 87: /* buddies */
    1499                         if(!yd->rawbuddylist)
    1500                                 yd->rawbuddylist = strdup(pair->value);
    1501                         else {
    1502                                 yd->rawbuddylist = y_string_append(yd->rawbuddylist, pair->value);
     1479                switch (pair->key) {
     1480                case 300:
     1481                case 301:
     1482                case 302:
     1483                        break;  /* Separators. Our logic does not need them */
     1484                case 303:
     1485                        if (318 == atoi(pair->value))
     1486                                last_packet = 1;
     1487                        break;
     1488                case 65:
     1489                        cur_group = strdup(pair->value);
     1490                        break;
     1491                case 7:
     1492                        newbud = y_new0(struct yahoo_buddy, 1);
     1493                        newbud->id = strdup(pair->value);
     1494                        if (cur_group)
     1495                                newbud->group = strdup(cur_group);
     1496                        else if (yd->buddies) {
     1497                                struct yahoo_buddy *lastbud =
     1498                                        (struct yahoo_buddy *)y_list_nth(yd->
     1499                                        buddies,
     1500                                        y_list_length(yd->buddies) - 1)->data;
     1501                                newbud->group = strdup(lastbud->group);
     1502                        } else
     1503                                newbud->group = strdup("Buddies");
     1504
     1505                        yd->buddies = y_list_append(yd->buddies, newbud);
     1506
     1507                        break;
     1508                }
     1509        }
     1510
     1511        /* we could be getting multiple packets here */
     1512        if (pkt->hash && !last_packet)
     1513                return;
     1514
     1515        YAHOO_CALLBACK(ext_yahoo_got_buddies) (yd->client_id, yd->buddies);
     1516
     1517        /* Logged in */
     1518        if (!yd->logged_in) {
     1519                yd->logged_in = 1;
     1520                if (yd->current_status < 0)
     1521                        yd->current_status = yd->initial_status;
     1522                YAHOO_CALLBACK(ext_yahoo_login_response) (yd->client_id,
     1523                        YAHOO_LOGIN_OK, NULL);
     1524
     1525                /*
     1526                yahoo_set_away(yd->client_id, yd->initial_status, NULL,
     1527                        (yd->initial_status == YAHOO_STATUS_AVAILABLE) ? 0 : 1);
     1528
     1529                yahoo_get_yab(yd->client_id);
     1530                */
     1531        }
     1532
     1533}
     1534
     1535static void yahoo_process_list(struct yahoo_input_data *yid,
     1536        struct yahoo_packet *pkt)
     1537{
     1538        struct yahoo_data *yd = yid->yd;
     1539        YList *l;
     1540
     1541        /* we could be getting multiple packets here */
     1542        for (l = pkt->hash; l; l = l->next) {
     1543                struct yahoo_pair *pair = l->data;
     1544
     1545                switch (pair->key) {
     1546                case 89:        /* identities */
     1547                        {
     1548                                char **identities =
     1549                                        y_strsplit(pair->value, ",", -1);
     1550                                int i;
     1551                                for (i = 0; identities[i]; i++)
     1552                                        yd->identities =
     1553                                                y_list_append(yd->identities,
     1554                                                strdup(identities[i]));
     1555                                y_strfreev(identities);
    15031556                        }
    1504                         break;
    1505 
    1506                 case 88: /* ignore list */
    1507                         if(!yd->ignorelist)
    1508                                 yd->ignorelist = strdup("Ignore:");
    1509                         yd->ignorelist = y_string_append(yd->ignorelist, pair->value);
    1510                         break;
    1511 
    1512                 case 89: /* identities */
    1513                         {
    1514                         char **identities = y_strsplit(pair->value, ",", -1);
    1515                         int i;
    1516                         for(i=0; identities[i]; i++)
    1517                                 yd->identities = y_list_append(yd->identities,
    1518                                                 strdup(identities[i]));
    1519                         y_strfreev(identities);
    1520                         }
    1521                         YAHOO_CALLBACK(ext_yahoo_got_identities)(yd->client_id, yd->identities);
    1522                         break;
    1523                 case 59: /* cookies */
    1524                         if(yd->ignorelist) {
    1525                                 yd->ignore = bud_str2list(yd->ignorelist);
    1526                                 FREE(yd->ignorelist);
    1527                                 YAHOO_CALLBACK(ext_yahoo_got_ignore)(yd->client_id, yd->ignore);
    1528                         }
    1529                         if(yd->rawbuddylist) {
    1530                                 yd->buddies = bud_str2list(yd->rawbuddylist);
    1531                                 FREE(yd->rawbuddylist);
    1532                                 YAHOO_CALLBACK(ext_yahoo_got_buddies)(yd->client_id, yd->buddies);
    1533                         }
    1534 
    1535                         if(pair->value[0]=='Y') {
     1557                        YAHOO_CALLBACK(ext_yahoo_got_identities) (yd->client_id,
     1558                                yd->identities);
     1559                        break;
     1560                case 59:        /* cookies */
     1561                        if (pair->value[0] == 'Y') {
    15361562                                FREE(yd->cookie_y);
    15371563                                FREE(yd->login_cookie);
     
    15401566                                yd->login_cookie = getlcookie(yd->cookie_y);
    15411567
    1542                         } else if(pair->value[0]=='T') {
     1568                        } else if (pair->value[0] == 'T') {
    15431569                                FREE(yd->cookie_t);
    15441570                                yd->cookie_t = getcookie(pair->value);
    15451571
    1546                         } else if(pair->value[0]=='C') {
     1572                        } else if (pair->value[0] == 'C') {
    15471573                                FREE(yd->cookie_c);
    15481574                                yd->cookie_c = getcookie(pair->value);
    1549                         } 
    1550 
    1551                         if(yd->cookie_y && yd->cookie_t && yd->cookie_c)
    1552                                 YAHOO_CALLBACK(ext_yahoo_got_cookies)(yd->client_id);
    1553 
    1554                         break;
    1555                 case 3: /* my id */
    1556                 case 90: /* 1 */
    1557                 case 100: /* 0 */
    1558                 case 101: /* NULL */
    1559                 case 102: /* NULL */
    1560                 case 93: /* 86400/1440 */
    1561                         break;
    1562                 }
    1563         }
     1575                        }
     1576
     1577                        break;
     1578                case 3: /* my id */
     1579                case 90:        /* 1 */
     1580                case 100:       /* 0 */
     1581                case 101:       /* NULL */
     1582                case 102:       /* NULL */
     1583                case 93:        /* 86400/1440 */
     1584                        break;
     1585                }
     1586        }
     1587
     1588        if (yd->cookie_y && yd->cookie_t)       /* We don't get cookie_c anymore */
     1589                YAHOO_CALLBACK(ext_yahoo_got_cookies) (yd->client_id);
    15641590}
    15651591
     
    22262252}
    22272253
     2254struct yahoo_https_auth_data
     2255{
     2256        struct yahoo_input_data *yid;
     2257        char *token;
     2258        char *chal;
     2259};
     2260
     2261static void yahoo_https_auth_token_init(struct yahoo_https_auth_data *had);
     2262static void yahoo_https_auth_token_finish(struct http_request *req);
     2263static void yahoo_https_auth_init(struct yahoo_https_auth_data *had);
     2264static void yahoo_https_auth_finish(struct http_request *req);
     2265
     2266/* Extract a value from a login.yahoo.com response. Assume CRLF-linebreaks
     2267   and FAIL miserably if they're not there... */
     2268static char *yahoo_ha_find_key(char *response, char *key)
     2269{
     2270        char *s, *end;
     2271        int len = strlen(key);
     2272       
     2273        s = response;
     2274        do {
     2275                if (strncmp(s, key, len) == 0 && s[len] == '=') {
     2276                        s += len + 1;
     2277                        if ((end = strchr(s, '\r')))
     2278                                return g_strndup(s, end - s);
     2279                        else
     2280                                return g_strdup(s);
     2281                }
     2282               
     2283                if ((s = strchr(s, '\n')))
     2284                        s ++;
     2285        } while (s && *s);
     2286       
     2287        return NULL;
     2288}
     2289
     2290static enum yahoo_status yahoo_https_status_parse(int code)
     2291{
     2292        switch (code)
     2293        {
     2294                case 1212: return YAHOO_LOGIN_PASSWD;
     2295                case 1213: return YAHOO_LOGIN_LOCK;
     2296                case 1235: return YAHOO_LOGIN_UNAME;
     2297                default: return (enum yahoo_status) code;
     2298        }
     2299}
     2300
     2301static void yahoo_process_auth_0x10(struct yahoo_input_data *yid, const char *seed, const char *sn)
     2302{
     2303        struct yahoo_https_auth_data *had = g_new0(struct yahoo_https_auth_data, 1);
     2304       
     2305        had->yid = yid;
     2306        had->chal = g_strdup(seed);
     2307       
     2308        yahoo_https_auth_token_init(had);
     2309}
     2310
     2311static void yahoo_https_auth_token_init(struct yahoo_https_auth_data *had)
     2312{
     2313        struct yahoo_input_data *yid = had->yid;
     2314        struct yahoo_data *yd = yid->yd;
     2315        struct http_request *req;
     2316        char *login, *passwd, *chal;
     2317        char *url;
     2318       
     2319        login = g_strndup(yd->user, 3 * strlen(yd->user));
     2320        http_encode(login);
     2321        passwd = g_strndup(yd->password, 3 * strlen(yd->password));
     2322        http_encode(passwd);
     2323        chal = g_strndup(had->chal, 3 * strlen(had->chal));
     2324        http_encode(chal);
     2325       
     2326        url = g_strdup_printf("https://login.yahoo.com/config/pwtoken_get?src=ymsgr&ts=%d&login=%s&passwd=%s&chal=%s",
     2327                               (int) time(NULL), login, passwd, chal);
     2328       
     2329        req = http_dorequest_url(url, yahoo_https_auth_token_finish, had);
     2330       
     2331        g_free(url);
     2332        g_free(chal);
     2333        g_free(passwd);
     2334        g_free(login);
     2335}
     2336
     2337static void yahoo_https_auth_token_finish(struct http_request *req)
     2338{
     2339        struct yahoo_https_auth_data *had = req->data;
     2340        struct yahoo_input_data *yid;
     2341        struct yahoo_data *yd;
     2342        int st;
     2343       
     2344        if (y_list_find(inputs, had->yid) == NULL)
     2345                return;
     2346       
     2347        yid = had->yid;
     2348        yd = yid->yd;
     2349       
     2350        if (req->status_code != 200) {
     2351                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, 2000 + req->status_code, NULL);
     2352                goto fail;
     2353        }
     2354       
     2355        if (sscanf(req->reply_body, "%d", &st) != 1 || st != 0) {
     2356                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, yahoo_https_status_parse(st), NULL);
     2357                goto fail;
     2358        }
     2359       
     2360        if ((had->token = yahoo_ha_find_key(req->reply_body, "ymsgr")) == NULL) {
     2361                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, 3001, NULL);
     2362                goto fail;
     2363        }
     2364       
     2365        return yahoo_https_auth_init(had);
     2366       
     2367fail:
     2368        g_free(had->token);
     2369        g_free(had->chal);
     2370        g_free(had);
     2371}
     2372
     2373static void yahoo_https_auth_init(struct yahoo_https_auth_data *had)
     2374{
     2375        struct http_request *req;
     2376        char *url;
     2377       
     2378        url = g_strdup_printf("https://login.yahoo.com/config/pwtoken_login?src=ymsgr&ts=%d&token=%s",
     2379                              (int) time(NULL), had->token);
     2380       
     2381        req = http_dorequest_url(url, yahoo_https_auth_finish, had);
     2382       
     2383        g_free(url);
     2384}
     2385
     2386static void yahoo_https_auth_finish(struct http_request *req)
     2387{
     2388        struct yahoo_https_auth_data *had = req->data;
     2389        struct yahoo_input_data *yid;
     2390        struct yahoo_data *yd;
     2391        struct yahoo_packet *pack;
     2392        char *crumb = NULL;
     2393        int st;
     2394       
     2395        if (y_list_find(inputs, had->yid) == NULL)
     2396                return;
     2397       
     2398        yid = had->yid;
     2399        yd = yid->yd;
     2400       
     2401        md5_byte_t result[16];
     2402        md5_state_t ctx;
     2403       
     2404        unsigned char yhash[32];
     2405
     2406        if (req->status_code != 200) {
     2407                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, 2000 + req->status_code, NULL);
     2408                goto fail;
     2409        }
     2410       
     2411        if (sscanf(req->reply_body, "%d", &st) != 1 || st != 0) {
     2412                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, yahoo_https_status_parse(st), NULL);
     2413                goto fail;
     2414        }
     2415       
     2416        if ((yd->cookie_y = yahoo_ha_find_key(req->reply_body, "Y")) == NULL ||
     2417            (yd->cookie_t = yahoo_ha_find_key(req->reply_body, "T")) == NULL ||
     2418            (crumb = yahoo_ha_find_key(req->reply_body, "crumb")) == NULL) {
     2419                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, 3002, NULL);
     2420                goto fail;
     2421        }
     2422       
     2423        md5_init(&ctx); 
     2424        md5_append(&ctx, (unsigned char*) crumb, 11);
     2425        md5_append(&ctx, (unsigned char*) had->chal, strlen(had->chal));
     2426        md5_finish(&ctx, result);
     2427        to_y64(yhash, result, 16);
     2428
     2429        pack = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP, yd->initial_status, yd->session_id);
     2430        yahoo_packet_hash(pack, 1, yd->user);
     2431        yahoo_packet_hash(pack, 0, yd->user);
     2432        yahoo_packet_hash(pack, 277, yd->cookie_y);
     2433        yahoo_packet_hash(pack, 278, yd->cookie_t);
     2434        yahoo_packet_hash(pack, 307, (char*) yhash);
     2435        yahoo_packet_hash(pack, 244, "524223");
     2436        yahoo_packet_hash(pack, 2, yd->user);
     2437        yahoo_packet_hash(pack, 2, "1");
     2438        yahoo_packet_hash(pack, 98, "us");
     2439        yahoo_packet_hash(pack, 135, "7.5.0.647");
     2440       
     2441        yahoo_send_packet(yid, pack, 0);
     2442               
     2443        yahoo_packet_free(pack);
     2444       
     2445fail:
     2446        g_free(crumb);
     2447        g_free(had->token);
     2448        g_free(had->chal);
     2449        g_free(had);
     2450}
     2451
    22282452static void yahoo_process_auth(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
    22292453{
     
    22532477                case 1:
    22542478                        yahoo_process_auth_0x0b(yid, seed, sn);
     2479                        break;
     2480                case 2:
     2481                        yahoo_process_auth_0x10(yid, seed, sn);
    22552482                        break;
    22562483                default:
     
    24082635               
    24092636                yd->buddies = y_list_append(yd->buddies, bud);
    2410                
     2637       
    24112638                /* Possibly called already, but at least the call above doesn't
    24122639                   seem to happen every time (not anytime I tried). */
     
    24152642
    24162643/*      YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, who, status, NULL, (status==YAHOO_STATUS_AVAILABLE?0:1)); */
     2644}
     2645
     2646static void yahoo_process_contact_ymsg13(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
     2647{
     2648        char* who=NULL;
     2649        char* me=NULL; 
     2650        char* msg=NULL;
     2651        YList *l;
     2652        for (l = pkt->hash; l; l = l->next) {
     2653                struct yahoo_pair *pair = l->data;
     2654                if (pair->key == 4)
     2655                        who = pair->value;
     2656                else if (pair->key == 5)
     2657                        me = pair->value;
     2658                else
     2659                        DEBUG_MSG(("unknown key: %d = %s", pair->key, pair->value));
     2660        }
     2661
     2662        if(pkt->status==3)
     2663                YAHOO_CALLBACK(ext_yahoo_contact_auth_request)(yid->yd->client_id, me, who, msg);
    24172664}
    24182665
     
    26282875
    26292876        YList *l;
    2630         yahoo_dump_unhandled(pkt);
     2877        // yahoo_dump_unhandled(pkt);
    26312878        for (l = pkt->hash; l; l = l->next) {
    26322879                struct yahoo_pair *pair = l->data;
     
    26502897{
    26512898        DEBUG_MSG(("yahoo_packet_process: 0x%02x", pkt->service));
     2899        yahoo_dump_unhandled(pkt);
    26522900        switch (pkt->service)
    26532901        {
     
    26612909        case YAHOO_SERVICE_IDACT:
    26622910        case YAHOO_SERVICE_IDDEACT:
     2911        case YAHOO_SERVICE_Y6_STATUS_UPDATE:
     2912        case YAHOO_SERVICE_YMSG15_STATUS:
    26632913                yahoo_process_status(yid, pkt);
    26642914                break;
     
    26742924                yahoo_process_mail(yid, pkt);
    26752925                break;
     2926        case YAHOO_SERVICE_REJECTCONTACT:
    26762927        case YAHOO_SERVICE_NEWCONTACT:
    26772928                yahoo_process_contact(yid, pkt);
     
    27142965                yahoo_process_buddyadd(yid, pkt);
    27152966                break;
     2967        case YAHOO_SERVICE_CONTACT_YMSG13:
     2968                yahoo_process_contact_ymsg13(yid,pkt);
     2969                break;
    27162970        case YAHOO_SERVICE_REMBUDDY:
    27172971                yahoo_process_buddydel(yid, pkt);
     
    27422996        case YAHOO_SERVICE_CHATLOGOFF:
    27432997        case YAHOO_SERVICE_CHATMSG:
    2744         case YAHOO_SERVICE_REJECTCONTACT:
    27452998        case YAHOO_SERVICE_PEERTOPEER:
    27462999                WARNING(("unhandled service 0x%02x", pkt->service));
     
    27563009                yahoo_process_picture_upload(yid, pkt);
    27573010                break; 
     3011        case YAHOO_SERVICE_YMSG15_BUDDY_LIST:   /* Buddy List */
     3012                yahoo_process_buddy_list(yid, pkt);
    27583013        default:
    27593014                WARNING(("unknown service 0x%02x", pkt->service));
     
    35393794        yahoo_process_webcam_connection,
    35403795        yahoo_process_chatcat_connection,
    3541         yahoo_process_search_connection
     3796        yahoo_process_search_connection,
    35423797};
    35433798
     
    35573812        } while(len == -1 && errno == EINTR);
    35583813
    3559         if(len == -1 && errno == EAGAIN)        /* we'll try again later */
     3814        if(len == -1 && (errno == EAGAIN||errno == EINTR))      /* we'll try again later */
    35603815                return 1;
    35613816
     
    37604015
    37614016        yahoo_packet_hash(pkt, 5, who);
    3762         yahoo_packet_hash(pkt, 4, from?from:yd->user);
     4017        yahoo_packet_hash(pkt, 1, from?from:yd->user);
    37634018        yahoo_packet_hash(pkt, 14, " ");
    37644019        yahoo_packet_hash(pkt, 13, typ ? "1" : "0");
     
    37754030        struct yahoo_data *yd;
    37764031        struct yahoo_packet *pkt = NULL;
    3777         int service;
     4032        int old_status;
    37784033        char s[4];
    37794034
     
    37824037
    37834038        yd = yid->yd;
    3784 
    3785         if (msg) {
    3786                 yd->current_status = YAHOO_STATUS_CUSTOM;
    3787         } else {
    3788                 yd->current_status = state;
    3789         }
    3790 
    3791         if (yd->current_status == YAHOO_STATUS_AVAILABLE)
    3792                 service = YAHOO_SERVICE_ISBACK;
    3793         else
    3794                 service = YAHOO_SERVICE_ISAWAY;
    3795          
    3796         if ((away == 2) && (yd->current_status == YAHOO_STATUS_AVAILABLE)) {
    3797                 pkt = yahoo_packet_new(YAHOO_SERVICE_ISAWAY, YAHOO_STATUS_BRB, yd->session_id);
    3798                 yahoo_packet_hash(pkt, 10, "999");
    3799                 yahoo_packet_hash(pkt, 47, "2");
    3800         }else {
    3801                 pkt = yahoo_packet_new(service, YAHOO_STATUS_AVAILABLE, yd->session_id);
    3802                 snprintf(s, sizeof(s), "%d", yd->current_status);
    3803                 yahoo_packet_hash(pkt, 10, s);
    3804                 if (yd->current_status == YAHOO_STATUS_CUSTOM) {
    3805                         yahoo_packet_hash(pkt, 19, msg);
    3806                         yahoo_packet_hash(pkt, 47, (away == 2)? "2": (away) ?"1":"0");
    3807                 } else {
    3808                         yahoo_packet_hash(pkt, 47, (away == 2)? "2": (away) ?"1":"0");
    3809                 }
    3810                
    3811                
    3812                
    3813         }
    3814 
     4039        old_status = yd->current_status;
     4040        yd->current_status = state;
     4041
     4042        /* Thank you libpurple :) */
     4043        if (yd->current_status == YAHOO_STATUS_INVISIBLE) {
     4044                pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_VISIBILITY, YAHOO_STATUS_AVAILABLE, 0);
     4045                yahoo_packet_hash(pkt, 13, "2");
     4046                yahoo_send_packet(yid, pkt, 0);
     4047                yahoo_packet_free(pkt);
     4048
     4049                return;
     4050        }
     4051
     4052        pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_STATUS_UPDATE, yd->current_status, yd->session_id);
     4053        snprintf(s, sizeof(s), "%d", yd->current_status);
     4054        yahoo_packet_hash(pkt, 10, s);
     4055        yahoo_packet_hash(pkt, 19, msg && state == YAHOO_STATUS_CUSTOM ? msg : "");
     4056        yahoo_packet_hash(pkt, 47, (away == 2)? "2": (away) ?"1":"0");
    38154057        yahoo_send_packet(yid, pkt, 0);
    38164058        yahoo_packet_free(pkt);
     4059
     4060        if(old_status == YAHOO_STATUS_INVISIBLE) {
     4061                pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_VISIBILITY, YAHOO_STATUS_AVAILABLE, 0);
     4062                yahoo_packet_hash(pkt, 13, "1");
     4063                yahoo_send_packet(yid, pkt, 0);
     4064                yahoo_packet_free(pkt);
     4065        }
    38174066}
    38184067
     
    38294078        LOG(("yahoo_logoff: current status: %d", yd->current_status));
    38304079
    3831         if(yd->current_status != -1) {
     4080        if(yd->current_status != -1 && 0) {
     4081                /* Meh. Don't send this. The event handlers are not going to
     4082                   get to do this so it'll just leak memory. And the TCP
     4083                   connection reset will hopefully be clear enough. */
    38324084                pkt = yahoo_packet_new(YAHOO_SERVICE_LOGOFF, YAHOO_STATUS_AVAILABLE, yd->session_id);
    38334085                yd->current_status = -1;
     
    40624314                return;
    40634315
    4064         pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YAHOO_STATUS_AVAILABLE, yd->session_id);
    4065         yahoo_packet_hash(pkt, 1, yd->user);
    4066         yahoo_packet_hash(pkt, 7, who);
    4067         yahoo_packet_hash(pkt, 65, group);
     4316        pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YPACKET_STATUS_DEFAULT, yd->session_id);
     4317
    40684318        if (msg != NULL) /* add message/request "it's me add me" */
    40694319                yahoo_packet_hash(pkt, 14, msg);
     4320        else
     4321                yahoo_packet_hash(pkt,14,"");
     4322
     4323        yahoo_packet_hash(pkt, 65, group);
     4324        yahoo_packet_hash(pkt, 97, "1");
     4325        yahoo_packet_hash(pkt, 1, yd->user);
     4326        yahoo_packet_hash(pkt, 302, "319");
     4327        yahoo_packet_hash(pkt, 300, "319");
     4328        yahoo_packet_hash(pkt, 7, who);
     4329        yahoo_packet_hash(pkt, 334, "0");
     4330        yahoo_packet_hash(pkt, 301, "319");
     4331        yahoo_packet_hash(pkt, 303, "319");
     4332
     4333
    40704334        yahoo_send_packet(yid, pkt, 0);
    40714335        yahoo_packet_free(pkt);
     
    40894353        yahoo_send_packet(yid, pkt, 0);
    40904354        yahoo_packet_free(pkt);
     4355}
     4356
     4357void yahoo_accept_buddy_ymsg13(int id,const char* me,const char* who){
     4358        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
     4359        struct yahoo_data *yd;
     4360
     4361        if(!yid)
     4362                return;
     4363        yd = yid->yd;
     4364
     4365        struct yahoo_packet* pkt=NULL;
     4366        pkt= yahoo_packet_new(YAHOO_SERVICE_CONTACT_YMSG13,YAHOO_STATUS_AVAILABLE,0);
     4367
     4368        yahoo_packet_hash(pkt,1,me ?: yd->user);       
     4369        yahoo_packet_hash(pkt,5,who);
     4370        yahoo_packet_hash(pkt,13,"1");
     4371        yahoo_packet_hash(pkt,334,"0");
     4372        yahoo_send_packet(yid, pkt, 0);
     4373        yahoo_packet_free(pkt);
     4374}
     4375
     4376void yahoo_reject_buddy_ymsg13(int id,const char* me,const char* who,const char* msg){
     4377        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
     4378        struct yahoo_data *yd;
     4379
     4380        if(!yid)
     4381                return;
     4382        yd = yid->yd;
     4383
     4384        struct yahoo_packet* pkt=NULL;
     4385        pkt= yahoo_packet_new(YAHOO_SERVICE_CONTACT_YMSG13,YAHOO_STATUS_AVAILABLE,0);
     4386
     4387        yahoo_packet_hash(pkt,1,me ?: yd->user);       
     4388        yahoo_packet_hash(pkt,5,who);
     4389//      yahoo_packet_hash(pkt,241,YAHOO_PROTO_VER);
     4390        yahoo_packet_hash(pkt,13,"2");
     4391        yahoo_packet_hash(pkt,334,"0");
     4392        yahoo_packet_hash(pkt,97,"1");
     4393        yahoo_packet_hash(pkt,14,msg?:"");
     4394
     4395        yahoo_send_packet(yid, pkt, 0);
     4396        yahoo_packet_free(pkt);
     4397
    40914398}
    40924399
  • protocols/yahoo/yahoo.c

    rc6ca3ee rfb00989  
    130130{
    131131        set_add( &acc->set, "mail_notifications", "false", set_eval_bool, acc );
     132       
     133        acc->flags |= ACC_FLAG_AWAY_MESSAGE | ACC_FLAG_STATUS_MESSAGE;
    132134}
    133135
     
    198200        struct byahoo_data *yd = (struct byahoo_data *) ic->proto_data;
    199201       
    200         ic->away = NULL;
    201        
    202         if( state && msg && g_strcasecmp( state, msg ) != 0 )
    203         {
    204                 yd->current_status = YAHOO_STATUS_CUSTOM;
    205                 ic->away = "";
    206         }
    207         else if( state )
    208         {
    209                 /* Set msg to NULL since (if it isn't NULL already) it's equal
    210                    to state. msg must be empty if we want to use an existing
    211                    away state. */
    212                 msg = NULL;
    213                
    214                 ic->away = "";
    215                 if( g_strcasecmp( state, "Available" ) == 0 )
    216                 {
    217                         yd->current_status = YAHOO_STATUS_AVAILABLE;
    218                         ic->away = NULL;
    219                 }
    220                 else if( g_strcasecmp( state, "Be Right Back" ) == 0 )
     202        if( state && msg == NULL )
     203        {
     204                /* Use these states only if msg doesn't contain additional
     205                   info since away messages are only supported with CUSTOM. */
     206                if( g_strcasecmp( state, "Be Right Back" ) == 0 )
    221207                        yd->current_status = YAHOO_STATUS_BRB;
    222208                else if( g_strcasecmp( state, "Busy" ) == 0 )
     
    238224                else if( g_strcasecmp( state, "Invisible" ) == 0 )
    239225                        yd->current_status = YAHOO_STATUS_INVISIBLE;
    240                 else if( g_strcasecmp( state, GAIM_AWAY_CUSTOM ) == 0 )
    241                 {
    242                         yd->current_status = YAHOO_STATUS_AVAILABLE;
    243                        
    244                         ic->away = NULL;
    245                 }
    246         }
     226                else
     227                        yd->current_status = YAHOO_STATUS_CUSTOM;
     228        }
     229        else if( state )
     230                yd->current_status = YAHOO_STATUS_CUSTOM;
    247231        else
    248232                yd->current_status = YAHOO_STATUS_AVAILABLE;
    249233       
    250         yahoo_set_away( yd->y2_id, yd->current_status, msg, ic->away != NULL ? 2 : 0 );
     234        yahoo_set_away( yd->y2_id, yd->current_status, msg, state ? 2 : 0 );
    251235}
    252236
    253237static GList *byahoo_away_states( struct im_connection *ic )
    254238{
    255         GList *m = NULL;
    256 
    257         m = g_list_append( m, "Available" );
    258         m = g_list_append( m, "Be Right Back" );
    259         m = g_list_append( m, "Busy" );
    260         m = g_list_append( m, "Not At Home" );
    261         m = g_list_append( m, "Not At Desk" );
    262         m = g_list_append( m, "Not In Office" );
    263         m = g_list_append( m, "On Phone" );
    264         m = g_list_append( m, "On Vacation" );
    265         m = g_list_append( m, "Out To Lunch" );
    266         m = g_list_append( m, "Stepped Out" );
    267         m = g_list_append( m, "Invisible" );
    268         m = g_list_append( m, GAIM_AWAY_CUSTOM );
     239        static GList *m = NULL;
     240
     241        if( m == NULL )
     242        {
     243                m = g_list_append( m, "Be Right Back" );
     244                m = g_list_append( m, "Busy" );
     245                m = g_list_append( m, "Not At Home" );
     246                m = g_list_append( m, "Not At Desk" );
     247                m = g_list_append( m, "Not In Office" );
     248                m = g_list_append( m, "On Phone" );
     249                m = g_list_append( m, "On Vacation" );
     250                m = g_list_append( m, "Out To Lunch" );
     251                m = g_list_append( m, "Stepped Out" );
     252                m = g_list_append( m, "Invisible" );
     253        }
    269254       
    270255        return m;
     
    345330       
    346331        return c;
     332}
     333
     334static void byahoo_auth_allow( struct im_connection *ic, const char *who )
     335{
     336        struct byahoo_data *yd = (struct byahoo_data *) ic->proto_data;
     337       
     338        yahoo_accept_buddy_ymsg13( yd->y2_id, NULL, who );
     339}
     340
     341static void byahoo_auth_deny( struct im_connection *ic, const char *who )
     342{
     343        struct byahoo_data *yd = (struct byahoo_data *) ic->proto_data;
     344       
     345        yahoo_reject_buddy_ymsg13( yd->y2_id, NULL, who, NULL );
    347346}
    348347
     
    372371        ret->handle_cmp = g_strcasecmp;
    373372       
     373        ret->auth_allow = byahoo_auth_allow;
     374        ret->auth_deny = byahoo_auth_deny;
     375       
    374376        register_protocol(ret);
    375377}
     
    451453        struct byahoo_write_ready_data *d = data;
    452454       
    453         yahoo_write_ready( d->id, d->fd, d->data );
    454        
    455         return FALSE;
     455        return yahoo_write_ready( d->id, d->fd, d->data );
    456456}
    457457
     
    665665       
    666666        imcb_error( ic, "%s", err );
    667        
    668         if( fatal )
    669                 imc_logout( ic, TRUE );
    670667}
    671668
     
    793790{
    794791        struct byahoo_conf_invitation *inv = data;
    795        
    796         yahoo_conference_logon( inv->yid, NULL, inv->members, inv->name );
    797         imcb_chat_add_buddy( inv->c, inv->ic->acc->user );
     792        struct groupchat *b;
     793       
     794        for( b = inv->ic->groupchats; b; b = b->next )
     795                if( b == inv->c )
     796                        break;
     797       
     798        if( b != NULL )
     799        {
     800                yahoo_conference_logon( inv->yid, NULL, inv->members, inv->name );
     801                imcb_chat_add_buddy( inv->c, inv->ic->acc->user );
     802        }
     803        else
     804        {
     805                imcb_log( inv->ic, "Duplicate/corrupted invitation to `%s'.", inv->name );
     806        }
     807       
    798808        g_free( inv->name );
    799809        g_free( inv );
     
    911921}
    912922
     923void ext_yahoo_contact_auth_request( int id, const char *myid, const char *who, const char *msg )
     924{
     925        struct im_connection *ic = byahoo_get_ic_by_id( id );
     926       
     927        imcb_ask_auth( ic, who, NULL );
     928}
     929
    913930void ext_yahoo_contact_added( int id, const char *myid, const char *who, const char *msg )
    914931{
    915         /* Groups schmoups. If I want to handle groups properly I can get the
    916            buddy data from some internal libyahoo2 structure. */
    917         imcb_add_buddy( byahoo_get_ic_by_id( id ), (char*) who, NULL );
     932        struct im_connection *ic = byahoo_get_ic_by_id( id );
     933       
     934        imcb_add_buddy( ic, (char*) who, NULL );
    918935}
    919936
  • protocols/yahoo/yahoo2.h

    rc6ca3ee rfb00989  
    217217void yahoo_buddyicon_request(int id, const char *who);
    218218
     219void yahoo_accept_buddy_ymsg13(int,const char*,const char*);
     220void yahoo_reject_buddy_ymsg13(int,const char*,const char*,const char*);
     221
    219222#include "yahoo_httplib.h"
    220223
  • protocols/yahoo/yahoo2_callbacks.h

    rc6ca3ee rfb00989  
    361361
    362362/*
     363 * Name: ext_yahoo_contact_auth_request
     364 *      Called when a contact wants to add you to his/her contact list
     365 * Params:
     366 *      id   - the id that identifies the server connection
     367 *      myid - the identity s/he added
     368 *      who  - who did it
     369 *      msg  - any message sent
     370 */
     371void YAHOO_CALLBACK_TYPE(ext_yahoo_contact_auth_request)(int id, const char *myid, const char *who, const char *msg);
     372
     373
     374/*
    363375 * Name: ext_yahoo_contact_added
    364376 *      Called when a contact is added to your list
  • protocols/yahoo/yahoo2_types.h

    rc6ca3ee rfb00989  
    5757        YAHOO_LOGIN_LOCK = 14,
    5858        YAHOO_LOGIN_DUPL = 99,
    59         YAHOO_LOGIN_SOCK = -1
     59        YAHOO_LOGIN_SOCK = -1,
     60};
     61
     62enum ypacket_status {
     63        YPACKET_STATUS_DISCONNECTED = -1,
     64        YPACKET_STATUS_DEFAULT = 0,
     65        YPACKET_STATUS_SERVERACK = 1,
     66        YPACKET_STATUS_GAME     = 0x2,
     67        YPACKET_STATUS_AWAY     = 0x4,
     68        YPACKET_STATUS_CONTINUED = 0x5,
     69        YPACKET_STATUS_INVISIBLE = 12,
     70        YPACKET_STATUS_NOTIFY = 0x16, /* TYPING */
     71        YPACKET_STATUS_WEBLOGIN = 0x5a55aa55,
     72        YPACKET_STATUS_OFFLINE = 0x5a55aa56
    6073};
    6174
     
    8598};
    8699
    87 #define YAHOO_PROTO_VER 0x000b
     100#define YAHOO_PROTO_VER 0x0010
    88101
    89102/* Yahoo style/color directives */
     
    115128        YAHOO_CONNECTION_WEBCAM,
    116129        YAHOO_CONNECTION_CHATCAT,
    117         YAHOO_CONNECTION_SEARCH
     130        YAHOO_CONNECTION_SEARCH,
     131        YAHOO_CONNECTION_AUTH,
    118132};
    119133
     
    131145/* chat member attribs */
    132146#define YAHOO_CHAT_MALE 0x8000
    133 #define YAHOO_CHAT_FEMALE 0x10000
    134147#define YAHOO_CHAT_FEMALE 0x10000
    135148#define YAHOO_CHAT_DUNNO 0x400
     
    183196
    184197        void  *server_settings;
     198       
     199        struct yahoo_process_status_entry *half_user;
    185200};
    186201
     
    248263};
    249264
     265struct yahoo_process_status_entry {
     266        char *name;     /* 7      name */
     267        int state;      /* 10     state */
     268        int flags;      /* 13     flags, bit 0 = pager, bit 1 = chat, bit 2 = game */
     269        int mobile;     /* 60     mobile */
     270        char *msg;      /* 19     custom status message */
     271        int away;       /* 47     away (or invisible) */
     272        int buddy_session; /* 11  state */
     273        int f17;        /* 17     in chat? then what about flags? */
     274        int idle;       /* 137    seconds idle */
     275        int f138;       /* 138    state */
     276        char *f184;     /* 184    state */
     277        int f192;       /* 192    state */
     278        int f10001;     /* 10001  state */
     279        int f10002;     /* 10002  state */
     280        int f198;       /* 198    state */
     281        char *f197;     /* 197    state */
     282        char *f205;     /* 205    state */
     283        int f213;       /* 213    state */
     284};
     285
    250286#ifdef __cplusplus
    251287}
  • root_commands.c

    rc6ca3ee rfb00989  
    2929#include "bitlbee.h"
    3030#include "help.h"
     31#include "chat.h"
    3132
    3233#include <string.h>
     
    7879}
    7980
     81#define MIN_ARGS( x, y... )                                                    \
     82        do                                                                     \
     83        {                                                                      \
     84                int blaat;                                                     \
     85                for( blaat = 0; blaat <= x; blaat ++ )                         \
     86                        if( cmd[blaat] == NULL )                               \
     87                        {                                                      \
     88                                irc_usermsg( irc, "Not enough parameters given (need %d).", x ); \
     89                                return y;                                      \
     90                        }                                                      \
     91        } while( 0 )
     92
    8093void root_command( irc_t *irc, char *cmd[] )
    8194{       
     
    88101                if( g_strcasecmp( commands[i].command, cmd[0] ) == 0 )
    89102                {
    90                         if( !cmd[commands[i].required_parameters] )
    91                         {
    92                                 irc_usermsg( irc, "Not enough parameters given (need %d)", commands[i].required_parameters );
    93                                 return;
    94                         }
     103                        MIN_ARGS( commands[i].required_parameters );
     104                       
    95105                        commands[i].execute( irc, cmd );
    96106                        return;
     
    131141static void cmd_identify( irc_t *irc, char **cmd )
    132142{
    133         storage_status_t status = storage_load( irc->nick, cmd[1], irc );
     143        storage_status_t status = storage_load( irc, cmd[1] );
    134144        char *account_on[] = { "account", "on", NULL };
     145       
     146        if( strchr( irc->umode, 'R' ) != NULL )
     147        {
     148                irc_usermsg( irc, "You're already logged in." );
     149                return;
     150        }
    135151       
    136152        switch (status) {
     
    143159        case STORAGE_OK:
    144160                irc_usermsg( irc, "Password accepted, settings and accounts loaded" );
     161                irc_setpass( irc, cmd[1] );
     162                irc->status |= USTATUS_IDENTIFIED;
    145163                irc_umode_set( irc, "+R", 1 );
    146164                if( set_getbool( &irc->set, "auto_connect" ) )
     
    162180        }
    163181
    164         irc_setpass( irc, cmd[1] );
    165         switch( storage_save( irc, FALSE )) {
     182        switch( storage_save( irc, cmd[1], FALSE ) ) {
    166183                case STORAGE_ALREADY_EXISTS:
    167184                        irc_usermsg( irc, "Nick is already registered" );
     
    170187                case STORAGE_OK:
    171188                        irc_usermsg( irc, "Account successfully created" );
     189                        irc_setpass( irc, cmd[1] );
    172190                        irc->status |= USTATUS_IDENTIFIED;
    173191                        irc_umode_set( irc, "+R", 1 );
     
    238256}
    239257
     258static void cmd_showset( irc_t *irc, set_t **head, char *key )
     259{
     260        char *val;
     261       
     262        if( ( val = set_getstr( head, key ) ) )
     263                irc_usermsg( irc, "%s = `%s'", key, val );
     264        else
     265                irc_usermsg( irc, "%s is empty", key );
     266}
     267
     268typedef set_t** (*cmd_set_findhead)( irc_t*, char* );
     269typedef int (*cmd_set_checkflags)( irc_t*, set_t *set );
     270
     271static int cmd_set_real( irc_t *irc, char **cmd, cmd_set_findhead findhead, cmd_set_checkflags checkflags )
     272{
     273        char *set_full = NULL, *set_name = NULL, *tmp;
     274        set_t **head;
     275       
     276        if( cmd[1] && g_strncasecmp( cmd[1], "-del", 4 ) == 0 )
     277        {
     278                MIN_ARGS( 2, 0 );
     279                set_full = cmd[2];
     280        }
     281        else
     282                set_full = cmd[1];
     283       
     284        if( findhead == NULL )
     285        {
     286                set_name = set_full;
     287               
     288                head = &irc->set;
     289        }
     290        else
     291        {
     292                char *id;
     293               
     294                if( ( tmp = strchr( set_full, '/' ) ) )
     295                {
     296                        id = g_strndup( set_full, ( tmp - set_full ) );
     297                        set_name = tmp + 1;
     298                }
     299                else
     300                {
     301                        id = g_strdup( set_full );
     302                }
     303               
     304                if( ( head = findhead( irc, id ) ) == NULL )
     305                {
     306                        g_free( id );
     307                        irc_usermsg( irc, "Could not find setting." );
     308                        return 0;
     309                }
     310                g_free( id );
     311        }
     312       
     313        if( cmd[1] && cmd[2] && set_name )
     314        {
     315                set_t *s = set_find( head, set_name );
     316                int st;
     317               
     318                if( s && checkflags && checkflags( irc, s ) == 0 )
     319                        return 0;
     320               
     321                if( g_strncasecmp( cmd[1], "-del", 4 ) == 0 )
     322                        st = set_reset( head, set_name );
     323                else
     324                        st = set_setstr( head, set_name, cmd[2] );
     325               
     326                if( set_getstr( head, set_name ) == NULL )
     327                {
     328                        if( st )
     329                                irc_usermsg( irc, "Setting changed successfully" );
     330                        else
     331                                irc_usermsg( irc, "Failed to change setting" );
     332                }
     333                else
     334                {
     335                        cmd_showset( irc, head, set_name );
     336                }
     337        }
     338        else if( set_name )
     339        {
     340                cmd_showset( irc, head, set_name );
     341        }
     342        else
     343        {
     344                set_t *s = *head;
     345                while( s )
     346                {
     347                        cmd_showset( irc, &s, s->key );
     348                        s = s->next;
     349                }
     350        }
     351       
     352        return 1;
     353}
     354
     355static set_t **cmd_account_set_findhead( irc_t *irc, char *id )
     356{
     357        account_t *a;
     358       
     359        if( ( a = account_get( irc, id ) ) )
     360                return &a->set;
     361        else
     362                return NULL;
     363}
     364
     365static int cmd_account_set_checkflags( irc_t *irc, set_t *s )
     366{
     367        account_t *a = s->data;
     368       
     369        if( a->ic && s && s->flags & ACC_SET_OFFLINE_ONLY )
     370        {
     371                irc_usermsg( irc, "This setting can only be changed when the account is %s-line", "off" );
     372                return 0;
     373        }
     374        else if( !a->ic && s && s->flags & ACC_SET_ONLINE_ONLY )
     375        {
     376                irc_usermsg( irc, "This setting can only be changed when the account is %s-line", "on" );
     377                return 0;
     378        }
     379       
     380        return 1;
     381}
     382
    240383static void cmd_account( irc_t *irc, char **cmd )
    241384{
     
    252395                struct prpl *prpl;
    253396               
    254                 if( cmd[2] == NULL || cmd[3] == NULL || cmd[4] == NULL )
    255                 {
    256                         irc_usermsg( irc, "Not enough parameters" );
    257                         return;
    258                 }
    259                
    260                 prpl = find_protocol(cmd[2]);
     397                MIN_ARGS( 4 );
     398               
     399                prpl = find_protocol( cmd[2] );
    261400               
    262401                if( prpl == NULL )
     
    278417        else if( g_strcasecmp( cmd[1], "del" ) == 0 )
    279418        {
    280                 if( !cmd[2] )
    281                 {
    282                         irc_usermsg( irc, "Not enough parameters given (need %d)", 2 );
    283                 }
    284                 else if( !( a = account_get( irc, cmd[2] ) ) )
     419                MIN_ARGS( 2 );
     420
     421                if( !( a = account_get( irc, cmd[2] ) ) )
    285422                {
    286423                        irc_usermsg( irc, "Invalid account" );
     
    410547        else if( g_strcasecmp( cmd[1], "set" ) == 0 )
    411548        {
    412                 char *acc_handle, *set_name = NULL, *tmp;
    413                
    414                 if( !cmd[2] )
    415                 {
    416                         irc_usermsg( irc, "Not enough parameters given (need %d)", 2 );
    417                         return;
    418                 }
    419                
    420                 if( g_strncasecmp( cmd[2], "-del", 4 ) == 0 )
    421                         acc_handle = g_strdup( cmd[3] );
    422                 else
    423                         acc_handle = g_strdup( cmd[2] );
    424                
    425                 if( !acc_handle )
    426                 {
    427                         irc_usermsg( irc, "Not enough parameters given (need %d)", 3 );
    428                         return;
    429                 }
    430                
    431                 if( ( tmp = strchr( acc_handle, '/' ) ) )
    432                 {
    433                         *tmp = 0;
    434                         set_name = tmp + 1;
    435                 }
    436                
    437                 if( ( a = account_get( irc, acc_handle ) ) == NULL )
    438                 {
    439                         g_free( acc_handle );
    440                         irc_usermsg( irc, "Invalid account" );
    441                         return;
    442                 }
    443                
    444                 if( cmd[3] && set_name )
    445                 {
    446                         set_t *s = set_find( &a->set, set_name );
    447                        
    448                         if( a->ic && s && s->flags & ACC_SET_OFFLINE_ONLY )
    449                         {
    450                                 g_free( acc_handle );
    451                                 irc_usermsg( irc, "This setting can only be changed when the account is %s-line", "off" );
    452                                 return;
    453                         }
    454                         else if( !a->ic && s && s->flags & ACC_SET_ONLINE_ONLY )
    455                         {
    456                                 g_free( acc_handle );
    457                                 irc_usermsg( irc, "This setting can only be changed when the account is %s-line", "on" );
    458                                 return;
    459                         }
    460                        
    461                         if( g_strncasecmp( cmd[2], "-del", 4 ) == 0 )
    462                                 set_reset( &a->set, set_name );
    463                         else
    464                                 set_setstr( &a->set, set_name, cmd[3] );
    465                 }
    466                 if( set_name ) /* else 'forgotten' on purpose.. Must show new value after changing */
    467                 {
    468                         char *s = set_getstr( &a->set, set_name );
    469                         if( s )
    470                                 irc_usermsg( irc, "%s = `%s'", set_name, s );
    471                         else
    472                                 irc_usermsg( irc, "%s is empty", set_name );
    473                 }
    474                 else
    475                 {
    476                         set_t *s = a->set;
    477                         while( s )
    478                         {
    479                                 if( s->value || s->def )
    480                                         irc_usermsg( irc, "%s = `%s'", s->key, s->value ? s->value : s->def );
    481                                 else
    482                                         irc_usermsg( irc, "%s is empty", s->key );
    483                                 s = s->next;
    484                         }
    485                 }
    486                
    487                 g_free( acc_handle );
    488         }
    489         else
    490         {
    491                 irc_usermsg( irc, "Unknown command: account %s. Please use \x02help commands\x02 to get a list of available commands.", cmd[1] );
     549                MIN_ARGS( 2 );
     550               
     551                cmd_set_real( irc, cmd + 1, cmd_account_set_findhead, cmd_account_set_checkflags );
     552        }
     553        else
     554        {
     555                irc_usermsg( irc, "Unknown command: %s %s. Please use \x02help commands\x02 to get a list of available commands.", "account", cmd[1] );
    492556        }
    493557}
     
    500564        if( g_strcasecmp( cmd[1], "-tmp" ) == 0 )
    501565        {
     566                MIN_ARGS( 3 );
    502567                add_on_server = 0;
    503568                cmd ++;
     
    610675                        irc->mynick = g_strdup( cmd[2] );
    611676                       
     677                        /* If we're called internally (user did "set root_nick"),
     678                           let's not go O(INF). :-) */
    612679                        if( strcmp( cmd[0], "set_rename" ) != 0 )
    613680                                set_setstr( &irc->set, "root_nick", cmd[2] );
     
    633700        }
    634701       
    635         return strcmp( irc->mynick, new_nick ) == 0 ? new_nick : NULL;
     702        return strcmp( irc->mynick, new_nick ) == 0 ? new_nick : SET_INVALID;
    636703}
    637704
     
    817884static void cmd_set( irc_t *irc, char **cmd )
    818885{
    819         char *set_name = cmd[1];
    820        
    821         if( cmd[1] && cmd[2] )
    822         {
    823                 if( g_strncasecmp( cmd[1], "-del", 4 ) == 0 )
    824                 {
    825                         set_reset( &irc->set, cmd[2] );
    826                         set_name = cmd[2];
    827                 }
    828                 else
    829                 {
    830                         set_setstr( &irc->set, cmd[1], cmd[2] );
    831                 }
    832         }
    833         if( set_name ) /* else 'forgotten' on purpose.. Must show new value after changing */
    834         {
    835                 char *s = set_getstr( &irc->set, set_name );
    836                 if( s )
    837                         irc_usermsg( irc, "%s = `%s'", set_name, s );
    838                 else
    839                         irc_usermsg( irc, "%s is empty", set_name );
    840 
    841                 if( strchr( set_name, '/' ) )
    842                         irc_usermsg( irc, "Warning: / found in setting name, you're probably looking for the `account set' command." );
    843         }
    844         else
    845         {