Changes in / [3742fb6:3429b58]


Ignore:
Files:
23 added
9 deleted
37 edited

Legend:

Unmodified
Added
Removed
  • Makefile

    r3742fb6 r3429b58  
    1010
    1111# Program variables
    12 objects = 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
    13 headers = 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
     12#objects = chat.o
     13objects = bitlbee.o dcc.o help.o ipc.o irc.o irc_im.o irc_channel.o irc_commands.o irc_send.o irc_user.o irc_util.o nick.o query.o root_commands.o set.o storage.o $(STORAGE_OBJS)
     14headers = account.h bitlbee.h commands.h conf.h config.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/ftutil.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/ft.h protocols/nogaim.h
    1415subdirs = lib protocols
    1516
  • bitlbee.h

    r3742fb6 r3429b58  
    126126#define CONF_FILE_DEF ETCDIR "bitlbee.conf"
    127127
     128#include "bee.h"
    128129#include "irc.h"
    129130#include "storage.h"
     
    160161gboolean bitlbee_io_current_client_write( gpointer data, gint source, b_input_condition cond );
    161162
    162 void root_command_string( irc_t *irc, user_t *u, char *command, int flags );
     163void root_command_string( irc_t *irc, char *command );
    163164void root_command( irc_t *irc, char *command[] );
    164165gboolean bitlbee_shutdown( gpointer data, gint fd, b_input_condition cond );
  • conf.c

    r3742fb6 r3429b58  
    6363        conf->ping_timeout = 300;
    6464        conf->user = NULL;
     65        conf->ft_max_size = SIZE_MAX;
     66        conf->ft_max_kbps = G_MAXUINT;
     67        conf->ft_listen = NULL;
    6568        conf->protocols = NULL;
    6669        proxytype = 0;
     
    315318                                conf->user = g_strdup( ini->value );
    316319                        }
     320                        else if( g_strcasecmp( ini->key, "ft_max_size" ) == 0 )
     321                        {
     322                                size_t ft_max_size;
     323                                if( sscanf( ini->value, "%zu", &ft_max_size ) != 1 )
     324                                {
     325                                        fprintf( stderr, "Invalid %s value: %s\n", ini->key, ini->value );
     326                                        return 0;
     327                                }
     328                                conf->ft_max_size = ft_max_size;
     329                        }
     330                        else if( g_strcasecmp( ini->key, "ft_max_kbps" ) == 0 )
     331                        {
     332                                if( sscanf( ini->value, "%d", &i ) != 1 )
     333                                {
     334                                        fprintf( stderr, "Invalid %s value: %s\n", ini->key, ini->value );
     335                                        return 0;
     336                                }
     337                                conf->ft_max_kbps = i;
     338                        }
     339                        else if( g_strcasecmp( ini->key, "ft_listen" ) == 0 )
     340                        {
     341                                g_free( conf->ft_listen );
     342                                conf->ft_listen = g_strdup( ini->value );
     343                        }
    317344                        else if( g_strcasecmp( ini->key, "protocols" ) == 0 )
    318345                        {
     
    349376                if( g_strcasecmp( ini->section, "defaults" ) == 0 )
    350377                {
    351                         set_t *s = set_find( &irc->set, ini->key );
     378                        set_t *s = set_find( &irc->b->set, ini->key );
    352379                       
    353380                        if( s )
  • conf.h

    r3742fb6 r3429b58  
    5050        int ping_timeout;
    5151        char *user;
     52        size_t ft_max_size;
     53        int ft_max_kbps;
     54        char *ft_listen;
    5255        char **protocols;
    5356} conf_t;
  • configure

    r3742fb6 r3429b58  
    398398fi
    399399
    400 STORAGES="text xml"
     400STORAGES="xml"
    401401
    402402if [ "$ldap" = "auto" ]; then
  • doc/user-guide/commands.xml

    r3742fb6 r3429b58  
    11681168
    11691169        </bitlbee-command>
     1170       
     1171        <bitlbee-command name="transfers">
     1172                <short-description>Monitor, cancel, or reject file transfers</short-description>
     1173                <syntax>transfers [&lt;cancel&gt; id | &lt;reject&gt;]</syntax>
     1174               
     1175                <description>
     1176                        <para>
     1177                                Without parameters the currently pending file transfers and their status will be listed. Available actions are <emphasis>cancel</emphasis> and <emphasis>reject</emphasis>. See <emphasis>help transfers &lt;action&gt;</emphasis> for more information.
     1178                        </para>
     1179
     1180                        <ircexample>
     1181                                <ircline nick="ulim">transfers</ircline>
     1182                        </ircexample>
     1183                </description>
     1184               
     1185                <bitlbee-command name="cancel">
     1186                        <short-description>Cancels the file transfer with the given id</short-description>
     1187                        <syntax>transfers &lt;cancel&gt; id</syntax>
     1188
     1189                        <description>
     1190                                <para>Cancels the file transfer with the given id</para>
     1191                        </description>
     1192
     1193                        <ircexample>
     1194                                <ircline nick="ulim">transfers cancel 1</ircline>
     1195                                <ircline nick="root">Canceling file transfer for test</ircline>
     1196                        </ircexample>
     1197                </bitlbee-command>
     1198
     1199                <bitlbee-command name="reject">
     1200                        <short-description>Rejects all incoming transfers</short-description>
     1201                        <syntax>transfers &lt;reject&gt;</syntax>
     1202
     1203                        <description>
     1204                                <para>Rejects all incoming (not already transferring) file transfers. Since you probably have only one incoming transfer at a time, no id is neccessary. Or is it?</para>
     1205                        </description>
     1206
     1207                        <ircexample>
     1208                                <ircline nick="ulim">transfers reject</ircline>
     1209                        </ircexample>
     1210                </bitlbee-command>
     1211        </bitlbee-command>
     1212       
    11701213</chapter>
  • ipc.c

    r3742fb6 r3429b58  
    138138       
    139139        if( strchr( irc->umode, 'w' ) )
    140                 irc_write( irc, ":%s WALLOPS :%s", irc->myhost, cmd[1] );
     140                irc_write( irc, ":%s WALLOPS :%s", irc->root->host, cmd[1] );
    141141}
    142142
     
    147147       
    148148        if( strchr( irc->umode, 's' ) )
    149                 irc_write( irc, ":%s NOTICE %s :%s", irc->myhost, irc->nick, cmd[1] );
     149                irc_write( irc, ":%s NOTICE %s :%s", irc->root->host, irc->user->nick, cmd[1] );
    150150}
    151151
     
    156156       
    157157        if( strchr( irc->umode, 'o' ) )
    158                 irc_write( irc, ":%s NOTICE %s :*** OperMsg *** %s", irc->myhost, irc->nick, cmd[1] );
     158                irc_write( irc, ":%s NOTICE %s :*** OperMsg *** %s", irc->root->host, irc->user->nick, cmd[1] );
    159159}
    160160
     
    176176                return;
    177177       
    178         if( nick_cmp( cmd[1], irc->nick ) != 0 )
     178        if( nick_cmp( cmd[1], irc->user->nick ) != 0 )
    179179                return;         /* It's not for us. */
    180180       
    181         irc_write( irc, ":%s!%s@%s KILL %s :%s", irc->mynick, irc->mynick, irc->myhost, irc->nick, cmd[2] );
     181        irc_write( irc, ":%s!%s@%s KILL %s :%s", irc->root->nick, irc->root->nick, irc->root->host, irc->user->nick, cmd[2] );
    182182        irc_abort( irc, 0, "Killed by operator: %s", cmd[2] );
    183183}
     
    188188                ipc_to_master_str( "HELLO\r\n" );
    189189        else
    190                 ipc_to_master_str( "HELLO %s %s :%s\r\n", irc->host, irc->nick, irc->realname );
     190                ipc_to_master_str( "HELLO %s %s :%s\r\n", irc->user->host, irc->user->nick, irc->user->fullname );
    191191}
    192192
  • irc.c

    r3742fb6 r3429b58  
    55  \********************************************************************/
    66
    7 /* The big hairy IRCd part of the project                               */
     7/* The IRC-based UI (for now the only one)                              */
    88
    99/*
     
    2424*/
    2525
    26 #define BITLBEE_CORE
    2726#include "bitlbee.h"
    28 #include "sock.h"
    29 #include "crypting.h"
    3027#include "ipc.h"
    3128
    32 static gboolean irc_userping( gpointer _irc, int fd, b_input_condition cond );
    33 
    34 GSList *irc_connection_list = NULL;
    35 
    36 static char *set_eval_password( set_t *set, char *value )
    37 {
    38         irc_t *irc = set->data;
    39        
    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         }
    49 }
    50 
    51 static char *set_eval_charset( set_t *set, char *value )
    52 {
    53         irc_t *irc = set->data;
    54         char *test;
    55         gsize test_bytes = 0;
    56         GIConv ic, oc;
    57 
    58         if( g_strcasecmp( value, "none" ) == 0 )
    59                 value = g_strdup( "utf-8" );
    60 
    61         if( ( oc = g_iconv_open( value, "utf-8" ) ) == (GIConv) -1 )
    62         {
    63                 return NULL;
    64         }
    65        
    66         /* Do a test iconv to see if the user picked an IRC-compatible
    67            charset (for example utf-16 goes *horribly* wrong). */
    68         if( ( test = g_convert_with_iconv( " ", 1, oc, NULL, &test_bytes, NULL ) ) == NULL ||
    69             test_bytes > 1 )
    70         {
    71                 g_free( test );
    72                 g_iconv_close( oc );
    73                 irc_usermsg( irc, "Unsupported character set: The IRC protocol "
    74                                   "only supports 8-bit character sets." );
    75                 return NULL;
    76         }
    77         g_free( test );
    78        
    79         if( ( ic = g_iconv_open( "utf-8", value ) ) == (GIConv) -1 )
    80         {
    81                 g_iconv_close( oc );
    82                 return NULL;
    83         }
    84        
    85         if( irc->iconv != (GIConv) -1 )
    86                 g_iconv_close( irc->iconv );
    87         if( irc->oconv != (GIConv) -1 )
    88                 g_iconv_close( irc->oconv );
    89        
    90         irc->iconv = ic;
    91         irc->oconv = oc;
    92 
    93         return value;
    94 }
    95 
    96 static char *set_eval_away_status( set_t *set, char *value )
    97 {
    98         irc_t *irc = set->data;
    99         account_t *a;
    100        
    101         g_free( set->value );
    102         set->value = g_strdup( value );
    103        
    104         for( a = irc->accounts; a; a = a->next )
    105         {
    106                 struct im_connection *ic = a->ic;
    107                
    108                 if( ic && ic->flags & OPT_LOGGED_IN )
    109                         imc_away_send_update( ic );
    110         }
    111        
    112         return value;
    113 }
     29GSList *irc_connection_list;
     30
     31static gboolean irc_userping( gpointer _irc, gint fd, b_input_condition cond );
     32static char *set_eval_charset( set_t *set, char *value );
    11433
    11534irc_t *irc_new( int fd )
     
    11837        struct sockaddr_storage sock;
    11938        socklen_t socklen = sizeof( sock );
     39        char *host = NULL, *myhost = NULL;
     40        irc_user_t *iu;
    12041        set_t *s;
     42        bee_t *b;
    12143       
    12244        irc = g_new0( irc_t, 1 );
     
    13052        irc->last_pong = gettime();
    13153       
    132         irc->userhash = g_hash_table_new( g_str_hash, g_str_equal );
     54        irc->nick_user_hash = g_hash_table_new( g_str_hash, g_str_equal );
    13355        irc->watches = g_hash_table_new( g_str_hash, g_str_equal );
    134        
    135         strcpy( irc->umode, UMODE );
    136         irc->mynick = g_strdup( ROOT_NICK );
    137         irc->channel = g_strdup( ROOT_CHAN );
    13856       
    13957        irc->iconv = (GIConv) -1;
     
    14260        if( global.conf->hostname )
    14361        {
    144                 irc->myhost = g_strdup( global.conf->hostname );
     62                myhost = g_strdup( global.conf->hostname );
    14563        }
    14664        else if( getsockname( irc->fd, (struct sockaddr*) &sock, &socklen ) == 0 )
     
    15169                                 NI_MAXHOST, NULL, 0, 0 ) == 0 )
    15270                {
    153                         irc->myhost = g_strdup( ipv6_unwrap( buf ) );
     71                        myhost = g_strdup( ipv6_unwrap( buf ) );
    15472                }
    15573        }
     
    16280                                 NI_MAXHOST, NULL, 0, 0 ) == 0 )
    16381                {
    164                         irc->host = g_strdup( ipv6_unwrap( buf ) );
    165                 }
    166         }
    167        
    168         if( irc->host == NULL )
    169                 irc->host = g_strdup( "localhost.localdomain" );
    170         if( irc->myhost == NULL )
    171                 irc->myhost = g_strdup( "localhost.localdomain" );
     82                        host = g_strdup( ipv6_unwrap( buf ) );
     83                }
     84        }
     85       
     86        if( host == NULL )
     87                host = g_strdup( "localhost.localdomain" );
     88        if( myhost == NULL )
     89                myhost = g_strdup( "localhost.localdomain" );
    17290       
    17391        if( global.conf->ping_interval > 0 && global.conf->ping_timeout > 0 )
    17492                irc->ping_source_id = b_timeout_add( global.conf->ping_interval * 1000, irc_userping, irc );
    175        
    176         irc_write( irc, ":%s NOTICE AUTH :%s", irc->myhost, "BitlBee-IRCd initialized, please go on" );
    17793
    17894        irc_connection_list = g_slist_append( irc_connection_list, irc );
    17995       
    180         s = set_add( &irc->set, "away", NULL,  set_eval_away_status, irc );
    181         s->flags |= SET_NULL_OK;
    182         s = set_add( &irc->set, "away_devoice", "true",  set_eval_away_devoice, irc );
    183         s = set_add( &irc->set, "auto_connect", "true", set_eval_bool, irc );
    184         s = set_add( &irc->set, "auto_reconnect", "true", set_eval_bool, irc );
    185         s = set_add( &irc->set, "auto_reconnect_delay", "5*3<900", set_eval_account_reconnect_delay, irc );
    186         s = set_add( &irc->set, "buddy_sendbuffer", "false", set_eval_bool, irc );
    187         s = set_add( &irc->set, "buddy_sendbuffer_delay", "200", set_eval_int, irc );
    188         s = set_add( &irc->set, "charset", "utf-8", set_eval_charset, irc );
    189         s = set_add( &irc->set, "control_channel", irc->channel, set_eval_control_channel, irc );
    190         s = set_add( &irc->set, "debug", "false", set_eval_bool, irc );
    191         s = set_add( &irc->set, "default_target", "root", NULL, irc );
    192         s = set_add( &irc->set, "display_namechanges", "false", set_eval_bool, irc );
    193         s = set_add( &irc->set, "display_timestamps", "true", set_eval_bool, irc );
    194         s = set_add( &irc->set, "handle_unknown", "root", NULL, irc );
    195         s = set_add( &irc->set, "lcnicks", "true", set_eval_bool, irc );
    196         s = set_add( &irc->set, "ops", "both", set_eval_ops, irc );
    197         s = set_add( &irc->set, "password", NULL, set_eval_password, irc );
    198         s->flags |= SET_NULL_OK;
    199         s = set_add( &irc->set, "private", "true", set_eval_bool, irc );
    200         s = set_add( &irc->set, "query_order", "lifo", NULL, irc );
    201         s = set_add( &irc->set, "root_nick", irc->mynick, set_eval_root_nick, irc );
    202         s = set_add( &irc->set, "save_on_quit", "true", set_eval_bool, irc );
    203         s = set_add( &irc->set, "show_offline", "false", set_eval_bool, irc );
    204         s = set_add( &irc->set, "simulate_netsplit", "true", set_eval_bool, irc );
    205         s = set_add( &irc->set, "status", NULL,  set_eval_away_status, irc );
    206         s->flags |= SET_NULL_OK;
    207         s = set_add( &irc->set, "strip_html", "true", NULL, irc );
    208         s = set_add( &irc->set, "timezone", "local", set_eval_timezone, irc );
    209         s = set_add( &irc->set, "to_char", ": ", set_eval_to_char, irc );
    210         s = set_add( &irc->set, "typing_notice", "false", set_eval_bool, irc );
     96        b = irc->b = bee_new();
     97        b->ui_data = irc;
     98        b->ui = &irc_ui_funcs;
     99       
     100        s = set_add( &b->set, "away_devoice", "true", NULL/*set_eval_away_devoice*/, irc );
     101        s = set_add( &b->set, "buddy_sendbuffer", "false", set_eval_bool, irc );
     102        s = set_add( &b->set, "buddy_sendbuffer_delay", "200", set_eval_int, irc );
     103        s = set_add( &b->set, "charset", "utf-8", set_eval_charset, irc );
     104        //s = set_add( &b->set, "control_channel", irc->channel, NULL/*set_eval_control_channel*/, irc );
     105        s = set_add( &b->set, "default_target", "root", NULL, irc );
     106        s = set_add( &b->set, "display_namechanges", "false", set_eval_bool, irc );
     107        s = set_add( &b->set, "display_timestamps", "true", set_eval_bool, irc );
     108        s = set_add( &b->set, "handle_unknown", "root", NULL, irc );
     109        s = set_add( &b->set, "lcnicks", "true", set_eval_bool, irc );
     110        s = set_add( &b->set, "ops", "both", NULL/*set_eval_ops*/, irc );
     111        s = set_add( &b->set, "private", "true", set_eval_bool, irc );
     112        s = set_add( &b->set, "query_order", "lifo", NULL, irc );
     113        s = set_add( &b->set, "root_nick", ROOT_NICK, NULL/*set_eval_root_nick*/, irc );
     114        s = set_add( &b->set, "simulate_netsplit", "true", set_eval_bool, irc );
     115        s = set_add( &b->set, "timezone", "local", set_eval_timezone, irc );
     116        s = set_add( &b->set, "to_char", ": ", set_eval_to_char, irc );
     117        s = set_add( &b->set, "typing_notice", "false", set_eval_bool, irc );
     118
     119        irc->root = iu = irc_user_new( irc, ROOT_NICK );
     120        iu->host = g_strdup( myhost );
     121        iu->fullname = g_strdup( ROOT_FN );
     122        iu->f = &irc_user_root_funcs;
     123       
     124        iu = irc_user_new( irc, NS_NICK );
     125        iu->host = g_strdup( myhost );
     126        iu->fullname = g_strdup( ROOT_FN );
     127        iu->f = &irc_user_root_funcs;
     128       
     129        irc->user = g_new0( irc_user_t, 1 );
     130        irc->user->host = g_strdup( host );
    211131       
    212132        conf_loaddefaults( irc );
    213133       
    214134        /* Evaluator sets the iconv/oconv structures. */
    215         set_eval_charset( set_find( &irc->set, "charset" ), set_getstr( &irc->set, "charset" ) );
    216        
    217         return( irc );
     135        set_eval_charset( set_find( &b->set, "charset" ), set_getstr( &b->set, "charset" ) );
     136       
     137        irc_write( irc, ":%s NOTICE AUTH :%s", irc->root->host, "BitlBee-IRCd initialized, please go on" );
     138       
     139        g_free( myhost );
     140        g_free( host );
     141       
     142        return irc;
    218143}
    219144
     
    236161               
    237162                ipc_to_master_str( "OPERMSG :Client exiting: %s@%s [%s]\r\n",
    238                                    irc->nick ? irc->nick : "(NONE)", irc->host, reason );
     163                                   irc->user->nick ? irc->user->nick : "(NONE)", irc->root->host, reason );
    239164               
    240165                g_free( reason );
     
    246171               
    247172                ipc_to_master_str( "OPERMSG :Client exiting: %s@%s [%s]\r\n",
    248                                    irc->nick ? irc->nick : "(NONE)", irc->host, "No reason given" );
     173                                   irc->user->nick ? irc->user->nick : "(NONE)", irc->root->host, "No reason given" );
    249174        }
    250175       
     
    267192}
    268193
    269 static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data )
    270 {
    271         g_free( key );
    272        
    273         return( TRUE );
    274 }
    275 
    276 /* Because we have no garbage collection, this is quite annoying */
     194static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data );
     195
    277196void irc_free( irc_t * irc )
    278197{
    279         user_t *user, *usertmp;
    280        
    281198        log_message( LOGLVL_INFO, "Destroying connection with fd %d", irc->fd );
    282199       
    283         if( irc->status & USTATUS_IDENTIFIED && set_getbool( &irc->set, "save_on_quit" ) )
     200        if( irc->status & USTATUS_IDENTIFIED && set_getbool( &irc->b->set, "save_on_quit" ) )
    284201                if( storage_save( irc, NULL, TRUE ) != STORAGE_OK )
    285                         irc_usermsg( irc, "Error while saving settings!" );
     202                        log_message( LOGLVL_WARNING, "Error while saving settings for user %s", irc->user->nick );
    286203       
    287204        irc_connection_list = g_slist_remove( irc_connection_list, irc );
    288        
    289         while( irc->accounts )
    290         {
    291                 if( irc->accounts->ic )
    292                         imc_logout( irc->accounts->ic, FALSE );
    293                 else if( irc->accounts->reconnect )
    294                         cancel_auto_reconnect( irc->accounts );
    295                
    296                 if( irc->accounts->ic == NULL )
    297                         account_del( irc, irc->accounts );
    298                 else
    299                         /* Nasty hack, but account_del() doesn't work in this
    300                            case and we don't want infinite loops, do we? ;-) */
    301                         irc->accounts = irc->accounts->next;
    302         }
    303205       
    304206        while( irc->queries != NULL )
    305207                query_del( irc, irc->queries );
    306208       
    307         while( irc->set )
    308                 set_del( &irc->set, irc->set->key );
    309        
    310         if (irc->users != NULL)
    311         {
    312                 user = irc->users;
    313                 while( user != NULL )
    314                 {
    315                         g_free( user->nick );
    316                         g_free( user->away );
    317                         g_free( user->handle );
    318                         if( user->user != user->nick ) g_free( user->user );
    319                         if( user->host != user->nick ) g_free( user->host );
    320                         if( user->realname != user->nick ) g_free( user->realname );
    321                         b_event_remove( user->sendbuf_timer );
    322                                        
    323                         usertmp = user;
    324                         user = user->next;
    325                         g_free( usertmp );
    326                 }
    327         }
     209        /* This is a little bit messy: bee_free() frees all b->users which
     210           calls us back to free the corresponding irc->users. So do this
     211           before we clear the remaining ones ourselves. */
     212        bee_free( irc->b );
     213       
     214        while( irc->users )
     215                irc_user_free( irc, (irc_user_t *) irc->users->data );
     216       
     217        while( irc->channels )
     218                irc_channel_free( irc->channels->data );
    328219       
    329220        if( irc->ping_source_id > 0 )
     
    337228        irc->fd = -1;
    338229       
    339         g_hash_table_foreach_remove( irc->userhash, irc_free_hashkey, NULL );
    340         g_hash_table_destroy( irc->userhash );
     230        g_hash_table_foreach_remove( irc->nick_user_hash, irc_free_hashkey, NULL );
     231        g_hash_table_destroy( irc->nick_user_hash );
    341232       
    342233        g_hash_table_foreach_remove( irc->watches, irc_free_hashkey, NULL );
     
    350241        g_free( irc->sendbuffer );
    351242        g_free( irc->readbuffer );
    352        
    353         g_free( irc->nick );
    354         g_free( irc->user );
    355         g_free( irc->host );
    356         g_free( irc->realname );
    357243        g_free( irc->password );
    358        
    359         g_free( irc->myhost );
    360         g_free( irc->mynick );
    361        
    362         g_free( irc->channel );
    363        
    364         g_free( irc->last_target );
     244        g_free( irc->last_root_cmd );
    365245       
    366246        g_free( irc );
     
    374254}
    375255
     256static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data )
     257{
     258        g_free( key );
     259       
     260        return( TRUE );
     261}
     262
    376263/* USE WITH CAUTION!
    377264   Sets pass without checking */
    378 void irc_setpass (irc_t *irc, const char *pass) 
     265void irc_setpass (irc_t *irc, const char *pass)
    379266{
    380267        g_free (irc->password);
     
    387274}
    388275
     276static char **irc_splitlines( char *buffer );
     277
    389278void irc_process( irc_t *irc )
    390279{
     
    394283        if( irc->readbuffer != NULL )
    395284        {
    396                 lines = irc_tokenize( irc->readbuffer );
     285                lines = irc_splitlines( irc->readbuffer );
    397286               
    398287                for( i = 0; *lines[i] != '\0'; i ++ )
     
    431320                                                                  "`help set charset' for more information. Your "
    432321                                                                  "message was ignored.",
    433                                                                   set_getstr( &irc->set, "charset" ) );
     322                                                                  set_getstr( &irc->b->set, "charset" ) );
    434323                                               
    435324                                                g_free( conv );
     
    438327                                        else
    439328                                        {
    440                                                 irc_write( irc, ":%s NOTICE AUTH :%s", irc->myhost,
     329                                                irc_write( irc, ":%s NOTICE AUTH :%s", irc->root->host,
    441330                                                           "Warning: invalid characters received at login time." );
    442331                                               
     
    476365}
    477366
    478 /* Splits a long string into separate lines. The array is NULL-terminated and, unless the string
    479    contains an incomplete line at the end, ends with an empty string. */
    480 char **irc_tokenize( char *buffer )
     367/* Splits a long string into separate lines. The array is NULL-terminated
     368   and, unless the string contains an incomplete line at the end, ends with
     369   an empty string. Could use g_strsplit() but this one does it in-place.
     370   (So yes, it's destructive.) */
     371static char **irc_splitlines( char *buffer )
    481372{
    482373        int i, j, n = 3;
     
    609500}
    610501
    611 void irc_reply( irc_t *irc, int code, char *format, ... )
    612 {
    613         char text[IRC_MAX_LINE];
    614         va_list params;
    615        
    616         va_start( params, format );
    617         g_vsnprintf( text, IRC_MAX_LINE, format, params );
    618         va_end( params );
    619         irc_write( irc, ":%s %03d %s %s", irc->myhost, code, irc->nick?irc->nick:"*", text );
    620        
    621         return;
    622 }
    623 
    624 int irc_usermsg( irc_t *irc, char *format, ... )
    625 {
    626         char text[1024];
    627         va_list params;
    628         char is_private = 0;
    629         user_t *u;
    630        
    631         u = user_find( irc, irc->mynick );
    632         is_private = u->is_private;
    633        
    634         va_start( params, format );
    635         g_vsnprintf( text, sizeof( text ), format, params );
    636         va_end( params );
    637        
    638         return( irc_msgfrom( irc, u->nick, text ) );
    639 }
    640 
    641502void irc_write( irc_t *irc, char *format, ... )
    642503{
     
    649510        return;
    650511}
     512
     513void irc_write_all( int now, char *format, ... )
     514{
     515        va_list params;
     516        GSList *temp;   
     517       
     518        va_start( params, format );
     519       
     520        temp = irc_connection_list;
     521        while( temp != NULL )
     522        {
     523                irc_t *irc = temp->data;
     524               
     525                if( now )
     526                {
     527                        g_free( irc->sendbuffer );
     528                        irc->sendbuffer = g_strdup( "\r\n" );
     529                }
     530                irc_vawrite( temp->data, format, params );
     531                if( now )
     532                {
     533                        bitlbee_io_current_client_write( irc, irc->fd, GAIM_INPUT_WRITE );
     534                }
     535                temp = temp->next;
     536        }
     537       
     538        va_end( params );
     539        return;
     540}
    651541
    652542void irc_vawrite( irc_t *irc, char *format, va_list params )
     
    705595}
    706596
    707 void irc_write_all( int now, char *format, ... )
    708 {
    709         va_list params;
    710         GSList *temp;   
    711        
    712         va_start( params, format );
    713        
    714         temp = irc_connection_list;
    715         while( temp != NULL )
    716         {
    717                 irc_t *irc = temp->data;
    718                
    719                 if( now )
    720                 {
    721                         g_free( irc->sendbuffer );
    722                         irc->sendbuffer = g_strdup( "\r\n" );
    723                 }
    724                 irc_vawrite( temp->data, format, params );
    725                 if( now )
    726                 {
    727                         bitlbee_io_current_client_write( irc, irc->fd, GAIM_INPUT_WRITE );
    728                 }
    729                 temp = temp->next;
    730         }
    731        
    732         va_end( params );
    733         return;
    734 }
    735 
    736 void irc_names( irc_t *irc, char *channel )
    737 {
    738         user_t *u;
    739         char namelist[385] = "";
    740         struct groupchat *c = NULL;
    741         char *ops = set_getstr( &irc->set, "ops" );
    742        
    743         /* RFCs say there is no error reply allowed on NAMES, so when the
    744            channel is invalid, just give an empty reply. */
    745        
    746         if( g_strcasecmp( channel, irc->channel ) == 0 )
    747         {
    748                 for( u = irc->users; u; u = u->next ) if( u->online )
    749                 {
    750                         if( strlen( namelist ) + strlen( u->nick ) > sizeof( namelist ) - 4 )
     597int irc_check_login( irc_t *irc )
     598{
     599        if( irc->user->user && irc->user->nick )
     600        {
     601                if( global.conf->authmode == AUTHMODE_CLOSED && !( irc->status & USTATUS_AUTHORIZED ) )
     602                {
     603                        irc_send_num( irc, 464, ":This server is password-protected." );
     604                        return 0;
     605                }
     606                else
     607                {
     608                        irc_channel_t *ic;
     609                        irc_user_t *iu = irc->user;
     610                       
     611                        irc->user = irc_user_new( irc, iu->nick );
     612                        irc->user->user = iu->user;
     613                        irc->user->host = iu->host;
     614                        irc->user->fullname = iu->fullname;
     615                        irc->user->f = &irc_user_self_funcs;
     616                        g_free( iu->nick );
     617                        g_free( iu );
     618                       
     619                        if( global.conf->runmode == RUNMODE_FORKDAEMON || global.conf->runmode == RUNMODE_DAEMON )
     620                                ipc_to_master_str( "CLIENT %s %s :%s\r\n", irc->user->host, irc->user->nick, irc->user->fullname );
     621                       
     622                        irc->status |= USTATUS_LOGGED_IN;
     623                       
     624                        /* This is for bug #209 (use PASS to identify to NickServ). */
     625                        if( irc->password != NULL )
    751626                        {
    752                                 irc_reply( irc, 353, "= %s :%s", channel, namelist );
    753                                 *namelist = 0;
     627                                char *send_cmd[] = { "identify", g_strdup( irc->password ), NULL };
     628                               
     629                                /*irc_setpass( irc, NULL );*/
     630                                /*root_command( irc, send_cmd );*/
     631                                g_free( send_cmd[1] );
    754632                        }
    755633                       
    756                         if( u->ic && !u->away && set_getbool( &irc->set, "away_devoice" ) )
    757                                 strcat( namelist, "+" );
    758                         else if( ( strcmp( u->nick, irc->mynick ) == 0 && ( strcmp( ops, "root" ) == 0 || strcmp( ops, "both" ) == 0 ) ) ||
    759                                  ( strcmp( u->nick, irc->nick ) == 0 && ( strcmp( ops, "user" ) == 0 || strcmp( ops, "both" ) == 0 ) ) )
    760                                 strcat( namelist, "@" );
    761                        
    762                         strcat( namelist, u->nick );
    763                         strcat( namelist, " " );
    764                 }
    765         }
    766         else if( ( c = irc_chat_by_channel( irc, channel ) ) )
    767         {
    768                 GList *l;
    769                
    770                 /* root and the user aren't in the channel userlist but should
    771                    show up in /NAMES, so list them first: */
    772                 sprintf( namelist, "%s%s %s%s ", strcmp( ops, "root" ) == 0 || strcmp( ops, "both" ) ? "@" : "", irc->mynick,
    773                                                  strcmp( ops, "user" ) == 0 || strcmp( ops, "both" ) ? "@" : "", irc->nick );
    774                
    775                 for( l = c->in_room; l; l = l->next ) if( ( u = user_findhandle( c->ic, l->data ) ) )
    776                 {
    777                         if( strlen( namelist ) + strlen( u->nick ) > sizeof( namelist ) - 4 )
    778                         {
    779                                 irc_reply( irc, 353, "= %s :%s", channel, namelist );
    780                                 *namelist = 0;
    781                         }
    782                        
    783                         strcat( namelist, u->nick );
    784                         strcat( namelist, " " );
    785                 }
    786         }
    787        
    788         if( *namelist )
    789                 irc_reply( irc, 353, "= %s :%s", channel, namelist );
    790        
    791         irc_reply( irc, 366, "%s :End of /NAMES list", channel );
    792 }
    793 
    794 int irc_check_login( irc_t *irc )
    795 {
    796         if( irc->user && irc->nick )
    797         {
    798                 if( global.conf->authmode == AUTHMODE_CLOSED && !( irc->status & USTATUS_AUTHORIZED ) )
    799                 {
    800                         irc_reply( irc, 464, ":This server is password-protected." );
    801                         return 0;
    802                 }
    803                 else
    804                 {
    805                         irc_login( irc );
     634                        irc_send_login( irc );
     635                       
     636                        irc->umode[0] = '\0';
     637                        irc_umode_set( irc, "+" UMODE, TRUE );
     638                       
     639                        ic = irc->default_channel = irc_channel_new( irc, ROOT_CHAN );
     640                        irc_channel_set_topic( ic, CONTROL_TOPIC, irc->root );
     641                        irc_channel_add_user( ic, irc->user );
     642                       
     643                        if( strcmp( set_getstr( &irc->b->set, "ops" ), "both" ) == 0 ||
     644                            strcmp( set_getstr( &irc->b->set, "ops" ), "user" ) == 0 )
     645                                irc_channel_user_set_mode( ic, irc->user, IRC_CHANNEL_USER_OP );
     646                       
     647                        irc->last_root_cmd = g_strdup( ROOT_CHAN );
     648                       
     649                        irc_send_msg( irc->root, "PRIVMSG", ROOT_CHAN,
     650                                      "Welcome to the BitlBee gateway!\n\n"
     651                                      "If you've never used BitlBee before, please do read the help "
     652                                      "information using the \x02help\x02 command. Lots of FAQs are "
     653                                      "answered there.\n"
     654                                      "If you already have an account on this server, just use the "
     655                                      "\x02identify\x02 command to identify yourself.", NULL );
     656                       
    806657                        return 1;
    807658                }
     
    814665}
    815666
    816 void irc_login( irc_t *irc )
    817 {
    818         user_t *u;
    819        
    820         irc_reply( irc,   1, ":Welcome to the BitlBee gateway, %s", irc->nick );
    821         irc_reply( irc,   2, ":Host %s is running BitlBee " BITLBEE_VERSION " " ARCH "/" CPU ".", irc->myhost );
    822         irc_reply( irc,   3, ":%s", IRCD_INFO );
    823         irc_reply( irc,   4, "%s %s %s %s", irc->myhost, BITLBEE_VERSION, UMODES UMODES_PRIV, CMODES );
    824         irc_reply( irc,   5, "PREFIX=(ov)@+ CHANTYPES=%s CHANMODES=,,,%s NICKLEN=%d NETWORK=BitlBee "
    825                              "CASEMAPPING=rfc1459 MAXTARGETS=1 WATCH=128 :are supported by this server",
    826                              CTYPES, CMODES, MAX_NICK_LENGTH - 1 );
    827         irc_motd( irc );
    828         irc->umode[0] = '\0';
    829         irc_umode_set( irc, "+" UMODE, 1 );
    830 
    831         u = user_add( irc, irc->mynick );
    832         u->host = g_strdup( irc->myhost );
    833         u->realname = g_strdup( ROOT_FN );
    834         u->online = 1;
    835         u->send_handler = root_command_string;
    836         u->is_private = 0; /* [SH] The channel is root's personal playground. */
    837         irc_spawn( irc, u );
    838        
    839         u = user_add( irc, NS_NICK );
    840         u->host = g_strdup( irc->myhost );
    841         u->realname = g_strdup( ROOT_FN );
    842         u->online = 0;
    843         u->send_handler = root_command_string;
    844         u->is_private = 1; /* [SH] NickServ is not in the channel, so should always /query. */
    845        
    846         u = user_add( irc, irc->nick );
    847         u->user = g_strdup( irc->user );
    848         u->host = g_strdup( irc->host );
    849         u->realname = g_strdup( irc->realname );
    850         u->online = 1;
    851         irc_spawn( irc, u );
    852        
    853         irc_usermsg( irc, "Welcome to the BitlBee gateway!\n\n"
    854                           "If you've never used BitlBee before, please do read the help "
    855                           "information using the \x02help\x02 command. Lots of FAQs are "
    856                           "answered there.\n"
    857                           "If you already have an account on this server, just use the "
    858                           "\x02identify\x02 command to identify yourself." );
    859        
    860         if( global.conf->runmode == RUNMODE_FORKDAEMON || global.conf->runmode == RUNMODE_DAEMON )
    861                 ipc_to_master_str( "CLIENT %s %s :%s\r\n", irc->host, irc->nick, irc->realname );
    862        
    863         irc->status |= USTATUS_LOGGED_IN;
    864        
    865         /* This is for bug #209 (use PASS to identify to NickServ). */
    866         if( irc->password != NULL )
    867         {
    868                 char *send_cmd[] = { "identify", g_strdup( irc->password ), NULL };
    869                
    870                 irc_setpass( irc, NULL );
    871                 root_command( irc, send_cmd );
    872                 g_free( send_cmd[1] );
    873         }
    874 }
    875 
    876 void irc_motd( irc_t *irc )
    877 {
    878         int fd;
    879        
    880         fd = open( global.conf->motdfile, O_RDONLY );
    881         if( fd == -1 )
    882         {
    883                 irc_reply( irc, 422, ":We don't need MOTDs." );
    884         }
    885         else
    886         {
    887                 char linebuf[80];       /* Max. line length for MOTD's is 79 chars. It's what most IRC networks seem to do. */
    888                 char *add, max;
    889                 int len;
    890                
    891                 linebuf[79] = len = 0;
    892                 max = sizeof( linebuf ) - 1;
    893                
    894                 irc_reply( irc, 375, ":- %s Message Of The Day - ", irc->myhost );
    895                 while( read( fd, linebuf + len, 1 ) == 1 )
    896                 {
    897                         if( linebuf[len] == '\n' || len == max )
    898                         {
    899                                 linebuf[len] = 0;
    900                                 irc_reply( irc, 372, ":- %s", linebuf );
    901                                 len = 0;
    902                         }
    903                         else if( linebuf[len] == '%' )
    904                         {
    905                                 read( fd, linebuf + len, 1 );
    906                                 if( linebuf[len] == 'h' )
    907                                         add = irc->myhost;
    908                                 else if( linebuf[len] == 'v' )
    909                                         add = BITLBEE_VERSION;
    910                                 else if( linebuf[len] == 'n' )
    911                                         add = irc->nick;
    912                                 else
    913                                         add = "%";
    914                                
    915                                 strncpy( linebuf + len, add, max - len );
    916                                 while( linebuf[++len] );
    917                         }
    918                         else if( len < max )
    919                         {
    920                                 len ++;
    921                         }
    922                 }
    923                 irc_reply( irc, 376, ":End of MOTD" );
    924                 close( fd );
    925         }
    926 }
    927 
    928 void irc_topic( irc_t *irc, char *channel )
    929 {
    930         struct groupchat *c = irc_chat_by_channel( irc, channel );
    931        
    932         if( c && c->topic )
    933                 irc_reply( irc, 332, "%s :%s", channel, c->topic );
    934         else if( g_strcasecmp( channel, irc->channel ) == 0 )
    935                 irc_reply( irc, 332, "%s :%s", channel, CONTROL_TOPIC );
    936         else
    937                 irc_reply( irc, 331, "%s :No topic for this channel", channel );
    938 }
    939 
    940 void irc_umode_set( irc_t *irc, char *s, int allow_priv )
     667void irc_umode_set( irc_t *irc, const char *s, gboolean allow_priv )
    941668{
    942669        /* allow_priv: Set to 0 if s contains user input, 1 if you want
    943670           to set a "privileged" mode (+o, +R, etc). */
    944         char m[256], st = 1, *t;
     671        char m[128], st = 1;
     672        const char *t;
    945673        int i;
    946674        char changes[512], *p, st2 = 2;
     
    950678       
    951679        for( t = irc->umode; *t; t ++ )
    952                 m[(int)*t] = 1;
    953 
     680                if( *t < sizeof( m ) )
     681                        m[(int)*t] = 1;
     682       
    954683        p = changes;
    955684        for( t = s; *t; t ++ )
     
    957686                if( *t == '+' || *t == '-' )
    958687                        st = *t == '+';
    959                 else if( st == 0 || ( strchr( UMODES, *t ) || ( allow_priv && strchr( UMODES_PRIV, *t ) ) ) )
     688                else if( ( st == 0 && ( !strchr( UMODES_KEEP, *t ) || allow_priv ) ) ||
     689                         ( st == 1 && strchr( UMODES, *t ) ) ||
     690                         ( st == 1 && allow_priv && strchr( UMODES_PRIV, *t ) ) )
    960691                {
    961692                        if( m[(int)*t] != st)
     
    974705        memset( irc->umode, 0, sizeof( irc->umode ) );
    975706       
    976         for( i = 0; i < 256 && strlen( irc->umode ) < ( sizeof( irc->umode ) - 1 ); i ++ )
     707        for( i = 'A'; i <= 'z' && strlen( irc->umode ) < ( sizeof( irc->umode ) - 1 ); i ++ )
    977708                if( m[i] )
    978709                        irc->umode[strlen(irc->umode)] = i;
    979710       
    980711        if( badflag )
    981                 irc_reply( irc, 501, ":Unknown MODE flag" );
    982         /* Deliberately no !user@host on the prefix here */
     712                irc_send_num( irc, 501, ":Unknown MODE flag" );
    983713        if( *changes )
    984                 irc_write( irc, ":%s MODE %s %s", irc->nick, irc->nick, changes );
    985 }
    986 
    987 void irc_spawn( irc_t *irc, user_t *u )
    988 {
    989         irc_join( irc, u, irc->channel );
    990 }
    991 
    992 void irc_join( irc_t *irc, user_t *u, char *channel )
    993 {
    994         char *nick;
    995        
    996         if( ( g_strcasecmp( channel, irc->channel ) != 0 ) || user_find( irc, irc->nick ) )
    997                 irc_write( irc, ":%s!%s@%s JOIN :%s", u->nick, u->user, u->host, channel );
    998        
    999         if( nick_cmp( u->nick, irc->nick ) == 0 )
    1000         {
    1001                 irc_write( irc, ":%s MODE %s +%s", irc->myhost, channel, CMODE );
    1002                 irc_names( irc, channel );
    1003                 irc_topic( irc, channel );
    1004         }
    1005        
    1006         nick = g_strdup( u->nick );
    1007         nick_lc( nick );
    1008         if( g_hash_table_lookup( irc->watches, nick ) )
    1009         {
    1010                 irc_reply( irc, 600, "%s %s %s %d :%s", u->nick, u->user, u->host, (int) time( NULL ), "logged online" );
    1011         }
    1012         g_free( nick );
    1013 }
    1014 
    1015 void irc_part( irc_t *irc, user_t *u, char *channel )
    1016 {
    1017         irc_write( irc, ":%s!%s@%s PART %s :%s", u->nick, u->user, u->host, channel, "" );
    1018 }
    1019 
    1020 void irc_kick( irc_t *irc, user_t *u, char *channel, user_t *kicker )
    1021 {
    1022         irc_write( irc, ":%s!%s@%s KICK %s %s :%s", kicker->nick, kicker->user, kicker->host, channel, u->nick, "" );
    1023 }
    1024 
    1025 void irc_kill( irc_t *irc, user_t *u )
    1026 {
    1027         char *nick, *s;
    1028         char reason[128];
    1029        
    1030         if( u->ic && u->ic->flags & OPT_LOGGING_OUT && set_getbool( &irc->set, "simulate_netsplit" ) )
    1031         {
    1032                 if( u->ic->acc->server )
    1033                         g_snprintf( reason, sizeof( reason ), "%s %s", irc->myhost,
    1034                                     u->ic->acc->server );
    1035                 else if( ( s = strchr( u->ic->acc->user, '@' ) ) )
    1036                         g_snprintf( reason, sizeof( reason ), "%s %s", irc->myhost,
    1037                                     s + 1 );
    1038                 else
    1039                         g_snprintf( reason, sizeof( reason ), "%s %s.%s", irc->myhost,
    1040                                     u->ic->acc->prpl->name, irc->myhost );
    1041                
    1042                 /* proto_opt might contain garbage after the : */
    1043                 if( ( s = strchr( reason, ':' ) ) )
    1044                         *s = 0;
    1045         }
    1046         else
    1047         {
    1048                 strcpy( reason, "Leaving..." );
    1049         }
    1050        
    1051         irc_write( irc, ":%s!%s@%s QUIT :%s", u->nick, u->user, u->host, reason );
    1052        
    1053         nick = g_strdup( u->nick );
    1054         nick_lc( nick );
    1055         if( g_hash_table_lookup( irc->watches, nick ) )
    1056         {
    1057                 irc_reply( irc, 601, "%s %s %s %d :%s", u->nick, u->user, u->host, (int) time( NULL ), "logged offline" );
    1058         }
    1059         g_free( nick );
    1060 }
    1061 
    1062 int irc_send( irc_t *irc, char *nick, char *s, int flags )
    1063 {
    1064         struct groupchat *c = NULL;
    1065         user_t *u = NULL;
    1066        
    1067         if( strchr( CTYPES, *nick ) )
    1068         {
    1069                 if( !( c = irc_chat_by_channel( irc, nick ) ) )
    1070                 {
    1071                         irc_reply( irc, 403, "%s :Channel does not exist", nick );
    1072                         return( 0 );
    1073                 }
    1074         }
    1075         else
    1076         {
    1077                 u = user_find( irc, nick );
    1078                
    1079                 if( !u )
    1080                 {
    1081                         if( irc->is_private )
    1082                                 irc_reply( irc, 401, "%s :Nick does not exist", nick );
    1083                         else
    1084                                 irc_usermsg( irc, "Nick `%s' does not exist!", nick );
    1085                         return( 0 );
    1086                 }
    1087         }
    1088        
    1089         if( *s == 1 && s[strlen(s)-1] == 1 )
    1090         {
    1091                 if( g_strncasecmp( s + 1, "ACTION", 6 ) == 0 )
    1092                 {
    1093                         if( s[7] == ' ' ) s ++;
    1094                         s += 3;
    1095                         *(s++) = '/';
    1096                         *(s++) = 'm';
    1097                         *(s++) = 'e';
    1098                         *(s++) = ' ';
    1099                         s -= 4;
    1100                         s[strlen(s)-1] = 0;
    1101                 }
    1102                 else if( g_strncasecmp( s + 1, "VERSION", 7 ) == 0 )
    1103                 {
    1104                         u = user_find( irc, irc->mynick );
    1105                         irc_privmsg( irc, u, "NOTICE", irc->nick, "", "\001VERSION BitlBee " BITLBEE_VERSION " " ARCH "/" CPU "\001" );
    1106                         return( 1 );
    1107                 }
    1108                 else if( g_strncasecmp( s + 1, "PING", 4 ) == 0 )
    1109                 {
    1110                         u = user_find( irc, irc->mynick );
    1111                         irc_privmsg( irc, u, "NOTICE", irc->nick, "", s );
    1112                         return( 1 );
    1113                 }
    1114                 else if( g_strncasecmp( s + 1, "TYPING", 6 ) == 0 )
    1115                 {
    1116                         if( u && u->ic && u->ic->acc->prpl->send_typing && strlen( s ) >= 10 )
    1117                         {
    1118                                 time_t current_typing_notice = time( NULL );
    1119                                
    1120                                 if( current_typing_notice - u->last_typing_notice >= 5 )
    1121                                 {
    1122                                         u->ic->acc->prpl->send_typing( u->ic, u->handle, ( s[8] - '0' ) << 8 );
    1123                                         u->last_typing_notice = current_typing_notice;
    1124                                 }
    1125                         }
    1126                         return( 1 );
    1127                 }
    1128                 else
    1129                 {
    1130                         irc_usermsg( irc, "Non-ACTION CTCP's aren't supported" );
    1131                         return( 0 );
    1132                 }
    1133         }
    1134        
    1135         if( u )
    1136         {
    1137                 /* For the next message, we probably do have to send new notices... */
    1138                 u->last_typing_notice = 0;
    1139                 u->is_private = irc->is_private;
    1140                
    1141                 if( u->is_private )
    1142                 {
    1143                         if( !u->online )
    1144                                 irc_reply( irc, 301, "%s :%s", u->nick, "User is offline" );
    1145                         else if( u->away )
    1146                                 irc_reply( irc, 301, "%s :%s", u->nick, u->away );
    1147                 }
    1148                
    1149                 if( u->send_handler )
    1150                 {
    1151                         u->send_handler( irc, u, s, flags );
    1152                         return 1;
    1153                 }
    1154         }
    1155         else if( c && c->ic && c->ic->acc && c->ic->acc->prpl )
    1156         {
    1157                 return( imc_chat_msg( c, s, 0 ) );
    1158         }
    1159        
    1160         return( 0 );
    1161 }
    1162 
    1163 static gboolean buddy_send_handler_delayed( gpointer data, gint fd, b_input_condition cond )
    1164 {
    1165         user_t *u = data;
    1166        
    1167         /* Shouldn't happen, but just to be sure. */
    1168         if( u->sendbuf_len < 2 )
    1169                 return FALSE;
    1170        
    1171         u->sendbuf[u->sendbuf_len-2] = 0; /* Cut off the last newline */
    1172         imc_buddy_msg( u->ic, u->handle, u->sendbuf, u->sendbuf_flags );
    1173        
    1174         g_free( u->sendbuf );
    1175         u->sendbuf = NULL;
    1176         u->sendbuf_len = 0;
    1177         u->sendbuf_timer = 0;
    1178         u->sendbuf_flags = 0;
    1179        
    1180         return FALSE;
    1181 }
    1182 
    1183 void buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags )
    1184 {
    1185         if( !u || !u->ic ) return;
    1186        
    1187         if( set_getbool( &irc->set, "buddy_sendbuffer" ) && set_getint( &irc->set, "buddy_sendbuffer_delay" ) > 0 )
    1188         {
    1189                 int delay;
    1190                
    1191                 if( u->sendbuf_len > 0 && u->sendbuf_flags != flags)
    1192                 {
    1193                         /* Flush the buffer */
    1194                         b_event_remove( u->sendbuf_timer );
    1195                         buddy_send_handler_delayed( u, -1, 0 );
    1196                 }
    1197 
    1198                 if( u->sendbuf_len == 0 )
    1199                 {
    1200                         u->sendbuf_len = strlen( msg ) + 2;
    1201                         u->sendbuf = g_new( char, u->sendbuf_len );
    1202                         u->sendbuf[0] = 0;
    1203                         u->sendbuf_flags = flags;
    1204                 }
    1205                 else
    1206                 {
    1207                         u->sendbuf_len += strlen( msg ) + 1;
    1208                         u->sendbuf = g_renew( char, u->sendbuf, u->sendbuf_len );
    1209                 }
    1210                
    1211                 strcat( u->sendbuf, msg );
    1212                 strcat( u->sendbuf, "\n" );
    1213                
    1214                 delay = set_getint( &irc->set, "buddy_sendbuffer_delay" );
    1215                 if( delay <= 5 )
    1216                         delay *= 1000;
    1217                
    1218                 if( u->sendbuf_timer > 0 )
    1219                         b_event_remove( u->sendbuf_timer );
    1220                 u->sendbuf_timer = b_timeout_add( delay, buddy_send_handler_delayed, u );
    1221         }
    1222         else
    1223         {
    1224                 imc_buddy_msg( u->ic, u->handle, msg, flags );
    1225         }
    1226 }
    1227 
    1228 int irc_privmsg( irc_t *irc, user_t *u, char *type, char *to, char *prefix, char *msg )
    1229 {
    1230         char last = 0;
    1231         char *s = msg, *line = msg;
    1232        
    1233         /* The almighty linesplitter .. woohoo!! */
    1234         while( !last )
    1235         {
    1236                 if( *s == '\r' && *(s+1) == '\n' )
    1237                         *(s++) = 0;
    1238                 if( *s == '\n' )
    1239                 {
    1240                         last = s[1] == 0;
    1241                         *s = 0;
    1242                 }
    1243                 else
    1244                 {
    1245                         last = s[0] == 0;
    1246                 }
    1247                 if( *s == 0 )
    1248                 {
    1249                         if( g_strncasecmp( line, "/me ", 4 ) == 0 && ( !prefix || !*prefix ) && g_strcasecmp( type, "PRIVMSG" ) == 0 )
    1250                         {
    1251                                 irc_write( irc, ":%s!%s@%s %s %s :\001ACTION %s\001", u->nick, u->user, u->host,
    1252                                            type, to, line + 4 );
    1253                         }
    1254                         else
    1255                         {
    1256                                 irc_write( irc, ":%s!%s@%s %s %s :%s%s", u->nick, u->user, u->host,
    1257                                            type, to, prefix ? prefix : "", line );
    1258                         }
    1259                         line = s + 1;
    1260                 }
    1261                 s ++;
    1262         }
    1263        
    1264         return( 1 );
    1265 }
    1266 
    1267 int irc_msgfrom( irc_t *irc, char *nick, char *msg )
    1268 {
    1269         user_t *u = user_find( irc, nick );
    1270         static char *prefix = NULL;
    1271        
    1272         if( !u ) return( 0 );
    1273         if( prefix && *prefix ) g_free( prefix );
    1274        
    1275         if( !u->is_private && nick_cmp( u->nick, irc->mynick ) != 0 )
    1276         {
    1277                 int len = strlen( irc->nick) + 3;
    1278                 prefix = g_new (char, len );
    1279                 g_snprintf( prefix, len, "%s%s", irc->nick, set_getstr( &irc->set, "to_char" ) );
    1280                 prefix[len-1] = 0;
    1281         }
    1282         else
    1283         {
    1284                 prefix = "";
    1285         }
    1286        
    1287         return( irc_privmsg( irc, u, "PRIVMSG", u->is_private ? irc->nick : irc->channel, prefix, msg ) );
    1288 }
    1289 
    1290 int irc_noticefrom( irc_t *irc, char *nick, char *msg )
    1291 {
    1292         user_t *u = user_find( irc, nick );
    1293        
    1294         if( u )
    1295                 return( irc_privmsg( irc, u, "NOTICE", irc->nick, "", msg ) );
    1296         else
    1297                 return( 0 );
    1298 }
     714                irc_write( irc, ":%s!%s@%s MODE %s :%s", irc->user->nick,
     715                           irc->user->user, irc->user->host, irc->user->nick,
     716                           changes );
     717}
     718
    1299719
    1300720/* Returns 0 if everything seems to be okay, a number >0 when there was a
     
    1334754}
    1335755
    1336 struct groupchat *irc_chat_by_channel( irc_t *irc, char *channel )
    1337 {
    1338         struct groupchat *c;
    1339         account_t *a;
    1340        
    1341         /* This finds the connection which has a conversation which belongs to this channel */
    1342         for( a = irc->accounts; a; a = a->next )
    1343         {
    1344                 if( a->ic == NULL )
    1345                         continue;
    1346                
    1347                 c = a->ic->groupchats;
    1348                 while( c )
    1349                 {
    1350                         if( c->channel && g_strcasecmp( c->channel, channel ) == 0 )
    1351                                 return c;
    1352                        
    1353                         c = c->next;
    1354                 }
    1355         }
    1356        
    1357         return NULL;
    1358 }
     756static char *set_eval_charset( set_t *set, char *value )
     757{
     758        irc_t *irc = (irc_t*) set->data;
     759        char *test;
     760        gsize test_bytes = 0;
     761        GIConv ic, oc;
     762
     763        if( g_strcasecmp( value, "none" ) == 0 )
     764                value = g_strdup( "utf-8" );
     765
     766        if( ( oc = g_iconv_open( value, "utf-8" ) ) == (GIConv) -1 )
     767        {
     768                return NULL;
     769        }
     770       
     771        /* Do a test iconv to see if the user picked an IRC-compatible
     772           charset (for example utf-16 goes *horribly* wrong). */
     773        if( ( test = g_convert_with_iconv( " ", 1, oc, NULL, &test_bytes, NULL ) ) == NULL ||
     774            test_bytes > 1 )
     775        {
     776                g_free( test );
     777                g_iconv_close( oc );
     778                irc_usermsg( irc, "Unsupported character set: The IRC protocol "
     779                                  "only supports 8-bit character sets." );
     780                return NULL;
     781        }
     782        g_free( test );
     783       
     784        if( ( ic = g_iconv_open( "utf-8", value ) ) == (GIConv) -1 )
     785        {
     786                g_iconv_close( oc );
     787                return NULL;
     788        }
     789       
     790        if( irc->iconv != (GIConv) -1 )
     791                g_iconv_close( irc->iconv );
     792        if( irc->oconv != (GIConv) -1 )
     793                g_iconv_close( irc->oconv );
     794       
     795        irc->iconv = ic;
     796        irc->oconv = oc;
     797
     798        return value;
     799}
  • irc.h

    r3742fb6 r3429b58  
    55  \********************************************************************/
    66
    7 /* The big hairy IRCd part of the project                               */
     7/* The IRC-based UI (for now the only one)                              */
    88
    99/*
     
    3333#define IRC_PING_STRING "PinglBee"
    3434
    35 #define UMODES "abisw"
    36 #define UMODES_PRIV "Ro"
    37 #define CMODES "nt"
    38 #define CMODE "t"
    39 #define UMODE "s"
    40 #define CTYPES "&#"
     35#define UMODES "abisw"     /* Allowed umodes (although they mostly do nothing) */
     36#define UMODES_PRIV "Ro"   /* Allowed, but not by user directly */
     37#define UMODES_KEEP "R"    /* Don't allow unsetting using /MODE */
     38#define CMODES "nt"        /* Allowed modes */
     39#define CMODE "t"          /* Default mode */
     40#define UMODE "s"          /* Default mode */
     41
     42#define CTYPES "&#"        /* Valid channel name prefixes */
    4143
    4244typedef enum
     
    4850        USTATUS_SHUTDOWN = 8
    4951} irc_status_t;
     52
     53struct irc_user;
    5054
    5155typedef struct irc
     
    5963        GIConv iconv, oconv;
    6064
    61         int sentbytes;
    62         time_t oldtime;
    63 
     65        struct irc_user *root;
     66        struct irc_user *user;
     67       
     68        char *last_root_cmd;
     69
     70        char *password; /* HACK: Used to save the user's password, but before
     71                           logging in, this may contain a password we should
     72                           send to identify after USER/NICK are received. */
     73
     74        char umode[8];
     75       
     76        struct query *queries;
     77        GSList *file_transfers;
     78       
     79        GSList *users, *channels;
     80        struct irc_channel *default_channel;
     81        GHashTable *nick_user_hash;
     82        GHashTable *watches;
     83
     84        gint r_watch_source_id;
     85        gint w_watch_source_id;
     86        gint ping_source_id;
     87       
     88        struct bee *b;
     89} irc_t;
     90
     91typedef enum
     92{
     93        IRC_USER_PRIVATE = 1,
     94        IRC_USER_AWAY = 2,
     95} irc_user_flags_t;
     96
     97typedef struct irc_user
     98{
     99        irc_t *irc;
     100       
    64101        char *nick;
    65102        char *user;
    66103        char *host;
    67         char *realname;
    68         char *password; /* HACK: Used to save the user's password, but before
    69                            logging in, this may contain a password we should
    70                            send to identify after USER/NICK are received. */
    71 
    72         char umode[8];
    73        
    74         char *myhost;
    75         char *mynick;
    76 
    77         char *channel;
    78         int c_id;
    79 
    80         char is_private;                /* Not too nice... */
    81         char *last_target;
    82        
    83         struct query *queries;
    84         struct account *accounts;
    85         struct chat *chatrooms;
    86        
    87         struct __USER *users;
    88         GHashTable *userhash;
    89         GHashTable *watches;
    90         struct __NICK *nicks;
     104        char *fullname;
     105       
     106        /* Nickname in lowercase for case sensitive searches */
     107        char *key;
     108       
     109        irc_user_flags_t flags;
     110       
     111        char *sendbuf;
     112        int sendbuf_len;
     113        guint sendbuf_timer;
     114        //int sendbuf_flags;
     115       
     116        struct bee_user *bu;
     117       
     118        const struct irc_user_funcs *f;
     119} irc_user_t;
     120
     121struct irc_user_funcs
     122{
     123        gboolean (*privmsg)( irc_user_t *iu, const char *msg );
     124        gboolean (*ctcp)( irc_user_t *iu, char * const* ctcp );
     125};
     126
     127extern const struct irc_user_funcs irc_user_root_funcs;
     128extern const struct irc_user_funcs irc_user_self_funcs;
     129
     130typedef enum
     131{
     132        IRC_CHANNEL_JOINED = 1,
     133       
     134        /* Hack: Set this flag right before jumping into IM when we expect
     135           a call to imcb_chat_new(). */
     136        IRC_CHANNEL_CHAT_PICKME = 0x10000,
     137} irc_channel_flags_t;
     138
     139typedef struct irc_channel
     140{
     141        irc_t *irc;
     142        char *name;
     143        char mode[8];
     144        int flags;
     145       
     146        char *topic;
     147        char *topic_who;
     148        time_t topic_time;
     149       
     150        GSList *users;
    91151        struct set *set;
    92 
    93         gint r_watch_source_id;
    94         gint w_watch_source_id;
    95         gint ping_source_id;
    96 } irc_t;
    97 
    98 #include "user.h"
    99 
     152       
     153        const struct irc_channel_funcs *f;
     154        void *data;
     155} irc_channel_t;
     156
     157struct irc_channel_funcs
     158{
     159        gboolean (*privmsg)( irc_channel_t *ic, const char *msg );
     160        gboolean (*join)( irc_channel_t *ic );
     161        gboolean (*part)( irc_channel_t *ic, const char *msg );
     162        gboolean (*topic)( irc_channel_t *ic, const char *new );
     163        gboolean (*invite)( irc_channel_t *ic, irc_user_t *iu );
     164       
     165        gboolean (*_init)( irc_channel_t *ic );
     166        gboolean (*_free)( irc_channel_t *ic );
     167};
     168
     169typedef enum
     170{
     171        IRC_CHANNEL_USER_OP = 1,
     172        IRC_CHANNEL_USER_HALFOP = 2,
     173        IRC_CHANNEL_USER_VOICE = 4,
     174} irc_channel_user_flags_t;
     175
     176typedef struct irc_channel_user
     177{
     178        irc_user_t *iu;
     179        int flags;
     180} irc_channel_user_t;
     181
     182typedef enum
     183{
     184        IRC_CC_TYPE_DEFAULT,
     185        IRC_CC_TYPE_REST,
     186        IRC_CC_TYPE_GROUP,
     187        IRC_CC_TYPE_ACCOUNT,
     188} irc_control_channel_type_t;
     189
     190struct irc_control_channel
     191{
     192        irc_control_channel_type_t type;
     193        struct bee_group *group;
     194        struct account *account;
     195};
     196
     197extern const struct bee_ui_funcs irc_ui_funcs;
     198
     199/* irc.c */
    100200extern GSList *irc_connection_list;
    101201
     
    103203void irc_abort( irc_t *irc, int immed, char *format, ... ) G_GNUC_PRINTF( 3, 4 );
    104204void irc_free( irc_t *irc );
    105 
    106 void irc_exec( irc_t *irc, char **cmd );
     205void irc_setpass (irc_t *irc, const char *pass);
     206
    107207void irc_process( irc_t *irc );
    108208char **irc_parse_line( char *line );
    109209char *irc_build_line( char **cmd );
    110210
    111 void irc_vawrite( irc_t *irc, char *format, va_list params );
    112211void irc_write( irc_t *irc, char *format, ... ) G_GNUC_PRINTF( 2, 3 );
    113212void irc_write_all( int now, char *format, ... ) G_GNUC_PRINTF( 2, 3 );
    114 void irc_reply( irc_t *irc, int code, char *format, ... ) G_GNUC_PRINTF( 3, 4 );
    115 G_MODULE_EXPORT int irc_usermsg( irc_t *irc, char *format, ... ) G_GNUC_PRINTF( 2, 3 );
    116 char **irc_tokenize( char *buffer );
    117 
    118 void irc_login( irc_t *irc );
     213void irc_vawrite( irc_t *irc, char *format, va_list params );
     214
    119215int irc_check_login( irc_t *irc );
    120 void irc_motd( irc_t *irc );
    121 void irc_names( irc_t *irc, char *channel );
    122 void irc_topic( irc_t *irc, char *channel );
    123 void irc_umode_set( irc_t *irc, char *s, int allow_priv );
    124 void irc_who( irc_t *irc, char *channel );
    125 void irc_spawn( irc_t *irc, user_t *u );
    126 void irc_join( irc_t *irc, user_t *u, char *channel );
    127 void irc_part( irc_t *irc, user_t *u, char *channel );
    128 void irc_kick( irc_t *irc, user_t *u, char *channel, user_t *kicker );
    129 void irc_kill( irc_t *irc, user_t *u );
    130 void irc_invite( irc_t *irc, char *nick, char *channel );
    131 void irc_whois( irc_t *irc, char *nick );
    132 void irc_setpass( irc_t *irc, const char *pass ); /* USE WITH CAUTION! */
    133 
    134 int irc_send( irc_t *irc, char *nick, char *s, int flags );
    135 int irc_privmsg( irc_t *irc, user_t *u, char *type, char *to, char *prefix, char *msg );
    136 int irc_msgfrom( irc_t *irc, char *nick, char *msg );
    137 int irc_noticefrom( irc_t *irc, char *nick, char *msg );
    138 
    139 void buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags );
    140 struct groupchat *irc_chat_by_channel( irc_t *irc, char *channel );
     216
     217void irc_umode_set( irc_t *irc, const char *s, gboolean allow_priv );
     218
     219/* irc_channel.c */
     220irc_channel_t *irc_channel_new( irc_t *irc, const char *name );
     221irc_channel_t *irc_channel_by_name( irc_t *irc, const char *name );
     222int irc_channel_free( irc_channel_t *ic );
     223int irc_channel_add_user( irc_channel_t *ic, irc_user_t *iu );
     224int irc_channel_del_user( irc_channel_t *ic, irc_user_t *iu );
     225irc_channel_user_t *irc_channel_has_user( irc_channel_t *ic, irc_user_t *iu );
     226int irc_channel_set_topic( irc_channel_t *ic, const char *topic, const irc_user_t *who );
     227void irc_channel_user_set_mode( irc_channel_t *ic, irc_user_t *iu, irc_channel_user_flags_t flags );
     228void irc_channel_printf( irc_channel_t *ic, char *format, ... );
     229gboolean irc_channel_name_ok( const char *name );
     230
     231/* irc_commands.c */
     232void irc_exec( irc_t *irc, char **cmd );
     233
     234/* irc_send.c */
     235void irc_send_num( irc_t *irc, int code, char *format, ... ) G_GNUC_PRINTF( 3, 4 );
     236void irc_send_login( irc_t *irc );
     237void irc_send_motd( irc_t *irc );
     238void irc_usermsg( irc_t *irc, char *format, ... );
     239void irc_send_join( irc_channel_t *ic, irc_user_t *iu );
     240void irc_send_part( irc_channel_t *ic, irc_user_t *iu, const char *reason );
     241void irc_send_names( irc_channel_t *ic );
     242void irc_send_topic( irc_channel_t *ic, gboolean topic_change );
     243void irc_send_whois( irc_user_t *iu );
     244void irc_send_who( irc_t *irc, GSList *l, const char *channel );
     245void irc_send_msg( irc_user_t *iu, const char *type, const char *dst, const char *msg, const char *prefix );
     246void irc_send_msg_raw( irc_user_t *iu, const char *type, const char *dst, const char *msg );
     247void irc_send_msg_f( irc_user_t *iu, const char *type, const char *dst, const char *format, ... ) G_GNUC_PRINTF( 4, 5 );
     248void irc_send_nick( irc_user_t *iu, const char *new );
     249void irc_send_channel_user_mode_diff( irc_channel_t *ic, irc_user_t *iu,
     250                                      irc_channel_user_flags_t old, irc_channel_user_flags_t new );
     251
     252/* irc_user.c */
     253irc_user_t *irc_user_new( irc_t *irc, const char *nick );
     254int irc_user_free( irc_t *irc, irc_user_t *iu );
     255irc_user_t *irc_user_by_name( irc_t *irc, const char *nick );
     256int irc_user_set_nick( irc_user_t *iu, const char *new );
     257gint irc_user_cmp( gconstpointer a_, gconstpointer b_ );
     258const char *irc_user_get_away( irc_user_t *iu );
     259
     260/* irc_util.c */
     261char *set_eval_timezone( struct set *set, char *value );
     262char *irc_format_timestamp( irc_t *irc, time_t msg_ts );
     263
     264/* irc_im.c */
     265void bee_irc_channel_update( irc_t *irc, irc_channel_t *ic, irc_user_t *iu );
    141266
    142267#endif
  • irc_commands.c

    r3742fb6 r3429b58  
    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
     
    5353        else if( global.conf->auth_pass )
    5454        {
    55                 irc_reply( irc, 464, ":Incorrect password" );
     55                irc_send_num( irc, 464, ":Incorrect password" );
    5656        }
    5757        else
    5858        {
    5959                /* Remember the password and try to identify after USER/NICK. */
    60                 irc_setpass( irc, cmd[1] );
     60                /*irc_setpass( irc, cmd[1] ); */
    6161                irc_check_login( irc );
    6262        }
     
    6565static void irc_cmd_user( irc_t *irc, char **cmd )
    6666{
    67         irc->user = g_strdup( cmd[1] );
    68         irc->realname = g_strdup( cmd[4] );
     67        irc->user->user = g_strdup( cmd[1] );
     68        irc->user->fullname = g_strdup( cmd[4] );
    6969       
    7070        irc_check_login( irc );
     
    7373static void irc_cmd_nick( irc_t *irc, char **cmd )
    7474{
    75         if( irc->nick )
    76         {
    77                 irc_reply( irc, 438, ":The hand of the deity is upon thee, thy nick may not change" );
    78         }
    79         /* This is not clean, but for now it'll have to be like this... */
    80         else if( ( nick_cmp( cmd[1], irc->mynick ) == 0 ) || ( nick_cmp( cmd[1], NS_NICK ) == 0 ) )
    81         {
    82                 irc_reply( irc, 433, ":This nick is already in use" );
     75        if( irc_user_by_name( irc, cmd[1] ) )
     76        {
     77                irc_send_num( irc, 433, ":This nick is already in use" );
    8378        }
    8479        else if( !nick_ok( cmd[1] ) )
    8580        {
    8681                /* [SH] Invalid characters. */
    87                 irc_reply( irc, 432, ":This nick contains invalid characters" );
    88         }
    89         else
    90         {
    91                 irc->nick = g_strdup( cmd[1] );
     82                irc_send_num( irc, 432, ":This nick contains invalid characters" );
     83        }
     84        else if( irc->user->nick )
     85        {
     86                if( irc->status & USTATUS_IDENTIFIED )
     87                {
     88                        irc_setpass( irc, NULL );
     89                        irc->status &= ~USTATUS_IDENTIFIED;
     90                        irc_umode_set( irc, "-R", 1 );
     91                }
     92               
     93                irc_user_set_nick( irc->user, cmd[1] );
     94        }
     95        else
     96        {
     97                irc->user->nick = g_strdup( cmd[1] );
    9298               
    9399                irc_check_login( irc );
     
    105111static void irc_cmd_ping( irc_t *irc, char **cmd )
    106112{
    107         irc_write( irc, ":%s PONG %s :%s", irc->myhost, irc->myhost, cmd[1]?cmd[1]:irc->myhost );
    108 }
    109 
    110 static void irc_cmd_oper( irc_t *irc, char **cmd )
    111 {
    112         if( global.conf->oper_pass &&
    113             ( strncmp( global.conf->oper_pass, "md5:", 4 ) == 0 ?
    114                 md5_verify_password( cmd[2], global.conf->oper_pass + 4 ) == 0 :
    115                 strcmp( cmd[2], global.conf->oper_pass ) == 0 ) )
    116         {
    117                 irc_umode_set( irc, "+o", 1 );
    118                 irc_reply( irc, 381, ":Password accepted" );
    119         }
    120         else
    121         {
    122                 irc_reply( irc, 432, ":Incorrect password" );
    123         }
     113        irc_write( irc, ":%s PONG %s :%s", irc->root->host,
     114                   irc->root->host, cmd[1]?cmd[1]:irc->root->host );
     115}
     116
     117static void irc_cmd_pong( irc_t *irc, char **cmd )
     118{
     119        /* We could check the value we get back from the user, but in
     120           fact we don't care, we're just happy s/he's still alive. */
     121        irc->last_pong = gettime();
     122        irc->pinging = 0;
     123}
     124
     125static void irc_cmd_join( irc_t *irc, char **cmd )
     126{
     127        irc_channel_t *ic;
     128       
     129        if( ( ic = irc_channel_by_name( irc, cmd[1] ) ) == NULL )
     130                ic = irc_channel_new( irc, cmd[1] );
     131       
     132        if( ic == NULL )
     133        {
     134                irc_send_num( irc, 479, "%s :Invalid channel name", cmd[1] );
     135                return;
     136        }
     137       
     138        if( ic->flags & IRC_CHANNEL_JOINED )
     139                return; /* Dude, you're already there...
     140                           RFC doesn't have any reply for that though? */
     141       
     142        irc_channel_add_user( ic, irc->user );
     143}
     144
     145static void irc_cmd_names( irc_t *irc, char **cmd )
     146{
     147        irc_channel_t *ic;
     148       
     149        if( cmd[1] && ( ic = irc_channel_by_name( irc, cmd[1] ) ) )
     150                irc_send_names( ic );
     151        /* With no args, we should show /names of all chans. Make the code
     152           below work well if necessary.
     153        else
     154        {
     155                GSList *l;
     156               
     157                for( l = irc->channels; l; l = l->next )
     158                        irc_send_names( l->data );
     159        }
     160        */
     161}
     162
     163static void irc_cmd_part( irc_t *irc, char **cmd )
     164{
     165        irc_channel_t *ic;
     166       
     167        if( ( ic = irc_channel_by_name( irc, cmd[1] ) ) == NULL )
     168        {
     169                irc_send_num( irc, 403, "%s :No such channel", cmd[1] );
     170        }
     171        else if( irc_channel_del_user( ic, irc->user ) )
     172        {
     173                if( ic->f->part )
     174                        ic->f->part( ic, NULL );
     175        }
     176        else
     177        {
     178                irc_send_num( irc, 442, "%s :You're not on that channel", cmd[1] );
     179        }
     180}
     181
     182static void irc_cmd_whois( irc_t *irc, char **cmd )
     183{
     184        char *nick = cmd[1];
     185        irc_user_t *iu = irc_user_by_name( irc, nick );
     186       
     187        if( iu )
     188                irc_send_whois( iu );
     189        else
     190                irc_send_num( irc, 401, "%s :Nick does not exist", nick );
     191}
     192
     193static void irc_cmd_whowas( irc_t *irc, char **cmd )
     194{
     195        /* For some reason irssi tries a whowas when whois fails. We can
     196           ignore this, but then the user never gets a "user not found"
     197           message from irssi which is a bit annoying. So just respond
     198           with not-found and irssi users will get better error messages */
     199       
     200        irc_send_num( irc, 406, "%s :Nick does not exist", cmd[1] );
     201        irc_send_num( irc, 369, "%s :End of WHOWAS", cmd[1] );
     202}
     203
     204static void irc_cmd_motd( irc_t *irc, char **cmd )
     205{
     206        irc_send_motd( irc );
    124207}
    125208
    126209static void irc_cmd_mode( irc_t *irc, char **cmd )
    127210{
    128         if( strchr( CTYPES, *cmd[1] ) )
    129         {
    130                 if( cmd[2] )
     211        if( irc_channel_name_ok( cmd[1] ) )
     212        {
     213                irc_channel_t *ic;
     214               
     215                if( ( ic = irc_channel_by_name( irc, cmd[1] ) ) == NULL )
     216                        irc_send_num( irc, 403, "%s :No such channel", cmd[1] );
     217                else if( cmd[2] )
    131218                {
    132219                        if( *cmd[2] == '+' || *cmd[2] == '-' )
    133                                 irc_reply( irc, 477, "%s :Can't change channel modes", cmd[1] );
     220                                irc_send_num( irc, 477, "%s :Can't change channel modes", cmd[1] );
    134221                        else if( *cmd[2] == 'b' )
    135                                 irc_reply( irc, 368, "%s :No bans possible", cmd[1] );
     222                                irc_send_num( irc, 368, "%s :No bans possible", cmd[1] );
    136223                }
    137224                else
    138                         irc_reply( irc, 324, "%s +%s", cmd[1], CMODE );
    139         }
    140         else
    141         {
    142                 if( nick_cmp( cmd[1], irc->nick ) == 0 )
     225                        irc_send_num( irc, 324, "%s +%s", cmd[1], ic->mode );
     226        }
     227        else
     228        {
     229                if( nick_cmp( cmd[1], irc->user->nick ) == 0 )
    143230                {
    144231                        if( cmd[2] )
    145232                                irc_umode_set( irc, cmd[2], 0 );
    146233                        else
    147                                 irc_reply( irc, 221, "+%s", irc->umode );
     234                                irc_send_num( irc, 221, "+%s", irc->umode );
    148235                }
    149236                else
    150                         irc_reply( irc, 502, ":Don't touch their modes" );
    151         }
    152 }
    153 
    154 static void irc_cmd_names( irc_t *irc, char **cmd )
    155 {
    156         irc_names( irc, cmd[1]?cmd[1]:irc->channel );
    157 }
    158 
    159 static void irc_cmd_part( irc_t *irc, char **cmd )
    160 {
    161         struct groupchat *c;
    162        
    163         if( g_strcasecmp( cmd[1], irc->channel ) == 0 )
    164         {
    165                 user_t *u = user_find( irc, irc->nick );
    166                
    167                 /* Not allowed to leave control channel */
    168                 irc_part( irc, u, irc->channel );
    169                 irc_join( irc, u, irc->channel );
    170         }
    171         else if( ( c = irc_chat_by_channel( irc, cmd[1] ) ) )
    172         {
    173                 user_t *u = user_find( irc, irc->nick );
    174                
    175                 irc_part( irc, u, c->channel );
    176                
    177                 if( c->ic )
    178                 {
    179                         c->joined = 0;
    180                         c->ic->acc->prpl->chat_leave( c );
    181                 }
    182         }
    183         else
    184         {
    185                 irc_reply( irc, 403, "%s :No such channel", cmd[1] );
    186         }
    187 }
    188 
    189 static void irc_cmd_join( irc_t *irc, char **cmd )
    190 {
    191         if( g_strcasecmp( cmd[1], irc->channel ) == 0 )
    192                 ; /* Dude, you're already there...
    193                      RFC doesn't have any reply for that though? */
    194         else if( cmd[1] )
    195         {
    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] );
    202                 else
    203                         irc_reply( irc, 403, "%s :No such channel", cmd[1] );
    204         }
    205 }
    206 
    207 static void irc_cmd_invite( irc_t *irc, char **cmd )
    208 {
    209         char *nick = cmd[1], *channel = cmd[2];
    210         struct groupchat *c = irc_chat_by_channel( irc, channel );
    211         user_t *u = user_find( irc, nick );
    212        
    213         if( u && c && ( u->ic == c->ic ) )
    214                 if( c->ic && c->ic->acc->prpl->chat_invite )
    215                 {
    216                         c->ic->acc->prpl->chat_invite( c, u->handle, NULL );
    217                         irc_reply( irc, 341, "%s %s", nick, channel );
    218                         return;
    219                 }
    220        
    221         irc_reply( irc, 482, "%s :Invite impossible; User/Channel non-existent or incompatible", channel );
     237                        irc_send_num( irc, 502, ":Don't touch their modes" );
     238        }
     239}
     240
     241static void irc_cmd_who( irc_t *irc, char **cmd )
     242{
     243        char *channel = cmd[1];
     244        irc_channel_t *ic;
     245       
     246        if( !channel || *channel == '0' || *channel == '*' || !*channel )
     247                irc_send_who( irc, irc->users, "**" );
     248        else if( ( ic = irc_channel_by_name( irc, channel ) ) )
     249                irc_send_who( irc, ic->users, channel );
     250        else
     251                irc_send_num( irc, 403, "%s :No such channel", channel );
    222252}
    223253
    224254static void irc_cmd_privmsg( irc_t *irc, char **cmd )
    225255{
    226         if ( !cmd[2] )
    227         {
    228                 irc_reply( irc, 412, ":No text to send" );
    229         }
    230         else if ( irc->nick && g_strcasecmp( cmd[1], irc->nick ) == 0 )
    231         {
    232                 irc_write( irc, ":%s!%s@%s %s %s :%s", irc->nick, irc->user, irc->host, cmd[0], cmd[1], cmd[2] );
     256        irc_channel_t *ic;
     257        irc_user_t *iu;
     258       
     259        if( !cmd[2] )
     260        {
     261                irc_send_num( irc, 412, ":No text to send" );
     262                return;
     263        }
     264       
     265        /* Don't treat CTCP actions as real CTCPs, just convert them right now. */
     266        if( g_strncasecmp( cmd[2], "\001ACTION", 7 ) == 0 )
     267        {
     268                cmd[2] += 4;
     269                strcpy( cmd[2], "/me" );
     270                if( cmd[2][strlen(cmd[2])-1] == '\001' )
     271                        cmd[2][strlen(cmd[2])-1] = '\0';
     272        }
     273       
     274        if( irc_channel_name_ok( cmd[1] ) &&
     275            ( ic = irc_channel_by_name( irc, cmd[1] ) ) )
     276        {
     277                if( ic->f->privmsg )
     278                        ic->f->privmsg( ic, cmd[2] );
     279        }
     280        else if( ( iu = irc_user_by_name( irc, cmd[1] ) ) )
     281        {
     282                if( cmd[2][0] == '\001' )
     283                {
     284                        char **ctcp;
     285                       
     286                        if( iu->f->ctcp == NULL )
     287                                return;
     288                        if( cmd[2][strlen(cmd[2])-1] == '\001' )
     289                                cmd[2][strlen(cmd[2])-1] = '\0';
     290                       
     291                        ctcp = split_command_parts( cmd[2] + 1 );
     292                        iu->f->ctcp( iu, ctcp );
     293                }
     294                else if( iu->f->privmsg )
     295                {
     296                        iu->flags |= IRC_USER_PRIVATE;
     297                        iu->f->privmsg( iu, cmd[2] );
     298                }
     299        }
     300        else
     301        {
     302                irc_send_num( irc, 401, "%s :No such nick/channel", cmd[1] );
     303        }
     304
     305
     306#if 0
     307        else if( irc->nick && g_strcasecmp( cmd[1], irc->nick ) == 0 )
     308        {
    233309        }
    234310        else
     
    271347                irc_send( irc, cmd[1], cmd[2], ( g_strcasecmp( cmd[0], "NOTICE" ) == 0 ) ? OPT_AWAY : 0 );
    272348        }
    273 }
    274 
    275 static void irc_cmd_who( irc_t *irc, char **cmd )
    276 {
    277         char *channel = cmd[1];
    278         user_t *u = irc->users;
    279         struct groupchat *c;
    280         GList *l;
    281        
    282         if( !channel || *channel == '0' || *channel == '*' || !*channel )
    283                 while( u )
    284                 {
    285                         irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", u->online ? irc->channel : "*", u->user, u->host, irc->myhost, u->nick, u->online ? ( u->away ? 'G' : 'H' ) : 'G', u->realname );
    286                         u = u->next;
    287                 }
    288         else if( g_strcasecmp( channel, irc->channel ) == 0 )
    289                 while( u )
    290                 {
    291                         if( u->online )
    292                                 irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->away ? 'G' : 'H', u->realname );
    293                         u = u->next;
    294                 }
    295         else if( ( c = irc_chat_by_channel( irc, channel ) ) )
    296                 for( l = c->in_room; l; l = l->next )
    297                 {
    298                         if( ( u = user_findhandle( c->ic, l->data ) ) )
    299                                 irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->away ? 'G' : 'H', u->realname );
    300                 }
    301         else if( ( u = user_find( irc, channel ) ) )
    302                 irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->online ? ( u->away ? 'G' : 'H' ) : 'G', u->realname );
    303        
    304         irc_reply( irc, 315, "%s :End of /WHO list", channel?channel:"**" );
     349#endif
     350}
     351
     352static void irc_cmd_nickserv( irc_t *irc, char **cmd )
     353{
     354        /* [SH] This aliases the NickServ command to PRIVMSG root */
     355        /* [TV] This aliases the NS command to PRIVMSG root as well */
     356        root_command( irc, cmd + 1 );
     357}
     358
     359
     360
     361static void irc_cmd_oper( irc_t *irc, char **cmd )
     362{
     363        if( global.conf->oper_pass &&
     364            ( strncmp( global.conf->oper_pass, "md5:", 4 ) == 0 ?
     365                md5_verify_password( cmd[2], global.conf->oper_pass + 4 ) == 0 :
     366                strcmp( cmd[2], global.conf->oper_pass ) == 0 ) )
     367        {
     368                irc_umode_set( irc, "+o", 1 );
     369                irc_send_num( irc, 381, ":Password accepted" );
     370        }
     371        else
     372        {
     373                irc_send_num( irc, 432, ":Incorrect password" );
     374        }
     375}
     376
     377static void irc_cmd_invite( irc_t *irc, char **cmd )
     378{
     379        irc_channel_t *ic;
     380        irc_user_t *iu;
     381       
     382        if( ( iu = irc_user_by_name( irc, cmd[1] ) ) == NULL )
     383        {
     384                irc_send_num( irc, 401, "%s :No such nick", cmd[1] );
     385                return;
     386        }
     387        else if( ( ic = irc_channel_by_name( irc, cmd[2] ) ) == NULL )
     388        {
     389                irc_send_num( irc, 403, "%s :No such channel", cmd[2] );
     390                return;
     391        }
     392       
     393        if( ic->f->invite )
     394                ic->f->invite( ic, iu );
     395        else
     396                irc_send_num( irc, 482, "%s :Can't invite people here", cmd[2] );
    305397}
    306398
    307399static void irc_cmd_userhost( irc_t *irc, char **cmd )
    308400{
    309         user_t *u;
    310401        int i;
    311402       
     
    317408       
    318409        for( i = 1; cmd[i]; i ++ )
    319                 if( ( u = user_find( irc, cmd[i] ) ) )
    320                 {
    321                         if( u->online && u->away )
    322                                 irc_reply( irc, 302, ":%s=-%s@%s", u->nick, u->user, u->host );
    323                         else
    324                                 irc_reply( irc, 302, ":%s=+%s@%s", u->nick, u->user, u->host );
    325                 }
     410        {
     411                irc_user_t *iu = irc_user_by_name( irc, cmd[i] );
     412               
     413                if( iu )
     414                        irc_send_num( irc, 302, ":%s=%c%s@%s", iu->nick,
     415                                      irc_user_get_away( iu ) ? '-' : '+',
     416                                      iu->user, iu->host );
     417        }
    326418}
    327419
    328420static void irc_cmd_ison( irc_t *irc, char **cmd )
    329421{
    330         user_t *u;
    331422        char buff[IRC_MAX_LINE];
    332423        int lenleft, i;
     
    344435                while( *this )
    345436                {
     437                        irc_user_t *iu;
     438                       
    346439                        if( ( next = strchr( this, ' ' ) ) )
    347440                                *next = 0;
    348441                       
    349                         if( ( u = user_find( irc, this ) ) && u->online )
    350                         {
    351                                 lenleft -= strlen( u->nick ) + 1;
     442                        if( ( iu = irc_user_by_name( irc, this ) ) &&
     443                            iu->bu && iu->bu->flags & BEE_USER_ONLINE )
     444                        {
     445                                lenleft -= strlen( iu->nick ) + 1;
    352446                               
    353447                                if( lenleft < 0 )
    354448                                        break;
    355449                               
    356                                 strcat( buff, u->nick );
     450                                strcat( buff, iu->nick );
    357451                                strcat( buff, " " );
    358452                        }
     
    377471                buff[strlen(buff)-1] = '\0';
    378472       
    379         irc_reply( irc, 303, ":%s", buff );
     473        irc_send_num( irc, 303, ":%s", buff );
    380474}
    381475
     
    390484        {
    391485                char *nick;
    392                 user_t *u;
     486                irc_user_t *iu;
    393487               
    394488                if( !cmd[i][0] || !cmd[i][1] )
     
    398492                nick_lc( nick );
    399493               
    400                 u = user_find( irc, nick );
     494                iu = irc_user_by_name( irc, nick );
    401495               
    402496                if( cmd[i][0] == '+' )
     
    405499                                g_hash_table_insert( irc->watches, nick, nick );
    406500                       
    407                         if( u && u->online )
    408                                 irc_reply( irc, 604, "%s %s %s %d :%s", u->nick, u->user, u->host, (int) time( NULL ), "is online" );
     501                        if( iu && iu->bu && iu->bu->flags & BEE_USER_ONLINE )
     502                                irc_send_num( irc, 604, "%s %s %s %d :%s", iu->nick, iu->user,
     503                                              iu->host, (int) time( NULL ), "is online" );
    409504                        else
    410                                 irc_reply( irc, 605, "%s %s %s %d :%s", nick, "*", "*", (int) time( NULL ), "is offline" );
     505                                irc_send_num( irc, 605, "%s %s %s %d :%s", nick, "*", "*",
     506                                              (int) time( NULL ), "is offline" );
    411507                }
    412508                else if( cmd[i][0] == '-' )
     
    419515                                g_free( okey );
    420516                               
    421                                 irc_reply( irc, 602, "%s %s %s %d :%s", nick, "*", "*", 0, "Stopped watching" );
    422                         }
    423                 }
    424         }
    425 }
    426 
     517                                irc_send_num( irc, 602, "%s %s %s %d :%s", nick, "*", "*", 0, "Stopped watching" );
     518                        }
     519                }
     520        }
     521}
     522
     523#if 0
    427524static void irc_cmd_topic( irc_t *irc, char **cmd )
    428525{
     
    443540        }
    444541}
     542#endif
    445543
    446544static void irc_cmd_away( irc_t *irc, char **cmd )
    447545{
    448         user_t *u = user_find( irc, irc->nick );
    449         char *away = cmd[1];
    450        
    451         if( !u ) return;
    452        
    453         if( away && *away )
    454         {
     546        if( cmd[1] && *cmd[1] )
     547        {
     548                char away[strlen(cmd[1])+1];
    455549                int i, j;
    456550               
    457551                /* Copy away string, but skip control chars. Mainly because
    458552                   Jabber really doesn't like them. */
    459                 u->away = g_malloc( strlen( away ) + 1 );
    460                 for( i = j = 0; away[i]; i ++ )
    461                         if( ( u->away[j] = away[i] ) >= ' ' )
     553                for( i = j = 0; cmd[1][i]; i ++ )
     554                        if( ( away[j] = cmd[1][i] ) >= ' ' )
    462555                                j ++;
    463                 u->away[j] = 0;
    464                
    465                 irc_reply( irc, 306, ":You're now away: %s", u->away );
    466                 /* irc_umode_set( irc, irc->myhost, "+a" ); */
    467         }
    468         else
    469         {
    470                 if( u->away ) g_free( u->away );
    471                 u->away = NULL;
    472                 /* irc_umode_set( irc, irc->myhost, "-a" ); */
    473                 irc_reply( irc, 305, ":Welcome back" );
    474         }
    475        
    476         set_setstr( &irc->set, "away", u->away );
    477 }
    478 
    479 static void irc_cmd_whois( irc_t *irc, char **cmd )
    480 {
    481         char *nick = cmd[1];
    482         user_t *u = user_find( irc, nick );
    483        
    484         if( u )
    485         {
    486                 irc_reply( irc, 311, "%s %s %s * :%s", u->nick, u->user, u->host, u->realname );
    487                
    488                 if( u->ic )
    489                         irc_reply( irc, 312, "%s %s.%s :%s network", u->nick, u->ic->acc->user,
    490                                    u->ic->acc->server && *u->ic->acc->server ? u->ic->acc->server : "",
    491                                    u->ic->acc->prpl->name );
    492                 else
    493                         irc_reply( irc, 312, "%s %s :%s", u->nick, irc->myhost, IRCD_INFO );
    494                
    495                 if( !u->online )
    496                         irc_reply( irc, 301, "%s :%s", u->nick, "User is offline" );
    497                 else if( u->away )
    498                         irc_reply( irc, 301, "%s :%s", u->nick, u->away );
    499                 if( u->status_msg )
    500                         irc_reply( irc, 320, "%s :%s", u->nick, u->status_msg );
    501                
    502                 irc_reply( irc, 318, "%s :End of /WHOIS list", nick );
    503         }
    504         else
    505         {
    506                 irc_reply( irc, 401, "%s :Nick does not exist", nick );
    507         }
    508 }
    509 
    510 static void irc_cmd_whowas( irc_t *irc, char **cmd )
    511 {
    512         /* For some reason irssi tries a whowas when whois fails. We can
    513            ignore this, but then the user never gets a "user not found"
    514            message from irssi which is a bit annoying. So just respond
    515            with not-found and irssi users will get better error messages */
    516        
    517         irc_reply( irc, 406, "%s :Nick does not exist", cmd[1] );
    518         irc_reply( irc, 369, "%s :End of WHOWAS", cmd[1] );
    519 }
    520 
    521 static void irc_cmd_nickserv( irc_t *irc, char **cmd )
    522 {
    523         /* [SH] This aliases the NickServ command to PRIVMSG root */
    524         /* [TV] This aliases the NS command to PRIVMSG root as well */
    525         root_command( irc, cmd + 1 );
    526 }
    527 
    528 static void irc_cmd_motd( irc_t *irc, char **cmd )
    529 {
    530         irc_motd( irc );
    531 }
    532 
    533 static void irc_cmd_pong( irc_t *irc, char **cmd )
    534 {
    535         /* We could check the value we get back from the user, but in
    536            fact we don't care, we're just happy he's still alive. */
    537         irc->last_pong = gettime();
    538         irc->pinging = 0;
     556                away[j] = '\0';
     557               
     558                irc_send_num( irc, 306, ":You're now away: %s", away );
     559                set_setstr( &irc->b->set, "away", away );
     560        }
     561        else
     562        {
     563                irc_send_num( irc, 305, ":Welcome back" );
     564                set_setstr( &irc->b->set, "away", NULL );
     565        }
    539566}
    540567
    541568static void irc_cmd_version( irc_t *irc, char **cmd )
    542569{
    543         irc_reply( irc, 351, "bitlbee-%s. %s :%s/%s ", BITLBEE_VERSION, irc->myhost, ARCH, CPU );
     570        irc_send_num( irc, 351, "bitlbee-%s. %s :%s/%s ",
     571                      BITLBEE_VERSION, irc->root->host, ARCH, CPU );
    544572}
    545573
    546574static void irc_cmd_completions( irc_t *irc, char **cmd )
    547575{
    548         user_t *u = user_find( irc, irc->mynick );
    549576        help_t *h;
    550577        set_t *s;
    551578        int i;
    552579       
    553         irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", "OK" );
     580        irc_send_msg_raw( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS OK" );
    554581       
    555582        for( i = 0; commands[i].command; i ++ )
    556                 irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", commands[i].command );
     583                irc_send_msg_f( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS %s", commands[i].command );
    557584       
    558585        for( h = global.help; h; h = h->next )
    559                 irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS help ", h->title );
    560        
    561         for( s = irc->set; s; s = s->next )
    562                 irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS set ", s->key );
    563        
    564         irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", "END" );
     586                irc_send_msg_f( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS help %s", h->title );
     587       
     588        for( s = irc->b->set; s; s = s->next )
     589                irc_send_msg_f( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS set %s", s->key );
     590       
     591        irc_send_msg_raw( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS END" );
    565592}
    566593
     
    572599                ipc_to_master( cmd );
    573600       
    574         irc_reply( irc, 382, "%s :Rehashing", global.conf_file );
     601        irc_send_num( irc, 382, "%s :Rehashing", global.conf_file );
    575602}
    576603
     
    581608        { "quit",        0, irc_cmd_quit,        0 },
    582609        { "ping",        0, irc_cmd_ping,        0 },
    583         { "oper",        2, irc_cmd_oper,        IRC_CMD_LOGGED_IN },
     610        { "pong",        0, irc_cmd_pong,        IRC_CMD_LOGGED_IN },
     611        { "join",        1, irc_cmd_join,        IRC_CMD_LOGGED_IN },
     612        { "names",       1, irc_cmd_names,       IRC_CMD_LOGGED_IN },
     613        { "part",        1, irc_cmd_part,        IRC_CMD_LOGGED_IN },
     614        { "whois",       1, irc_cmd_whois,       IRC_CMD_LOGGED_IN },
     615        { "whowas",      1, irc_cmd_whowas,      IRC_CMD_LOGGED_IN },
     616        { "motd",        0, irc_cmd_motd,        IRC_CMD_LOGGED_IN },
    584617        { "mode",        1, irc_cmd_mode,        IRC_CMD_LOGGED_IN },
    585         { "names",       0, irc_cmd_names,       IRC_CMD_LOGGED_IN },
    586         { "part",        1, irc_cmd_part,        IRC_CMD_LOGGED_IN },
    587         { "join",        1, irc_cmd_join,        IRC_CMD_LOGGED_IN },
    588         { "invite",      2, irc_cmd_invite,      IRC_CMD_LOGGED_IN },
     618        { "who",         0, irc_cmd_who,         IRC_CMD_LOGGED_IN },
    589619        { "privmsg",     1, irc_cmd_privmsg,     IRC_CMD_LOGGED_IN },
    590         { "notice",      1, irc_cmd_privmsg,     IRC_CMD_LOGGED_IN },
    591         { "who",         0, irc_cmd_who,         IRC_CMD_LOGGED_IN },
     620        { "nickserv",    1, irc_cmd_nickserv,    IRC_CMD_LOGGED_IN },
     621        { "ns",          1, irc_cmd_nickserv,    IRC_CMD_LOGGED_IN },
     622        { "away",        0, irc_cmd_away,        IRC_CMD_LOGGED_IN },
     623        { "version",     0, irc_cmd_version,     IRC_CMD_LOGGED_IN },
     624        { "completions", 0, irc_cmd_completions, IRC_CMD_LOGGED_IN },
    592625        { "userhost",    1, irc_cmd_userhost,    IRC_CMD_LOGGED_IN },
    593626        { "ison",        1, irc_cmd_ison,        IRC_CMD_LOGGED_IN },
    594627        { "watch",       1, irc_cmd_watch,       IRC_CMD_LOGGED_IN },
     628        { "invite",      2, irc_cmd_invite,      IRC_CMD_LOGGED_IN },
     629#if 0
     630        { "notice",      1, irc_cmd_privmsg,     IRC_CMD_LOGGED_IN },
    595631        { "topic",       1, irc_cmd_topic,       IRC_CMD_LOGGED_IN },
    596         { "away",        0, irc_cmd_away,        IRC_CMD_LOGGED_IN },
    597         { "whois",       1, irc_cmd_whois,       IRC_CMD_LOGGED_IN },
    598         { "whowas",      1, irc_cmd_whowas,      IRC_CMD_LOGGED_IN },
    599         { "nickserv",    1, irc_cmd_nickserv,    IRC_CMD_LOGGED_IN },
    600         { "ns",          1, irc_cmd_nickserv,    IRC_CMD_LOGGED_IN },
    601         { "motd",        0, irc_cmd_motd,        IRC_CMD_LOGGED_IN },
    602         { "pong",        0, irc_cmd_pong,        IRC_CMD_LOGGED_IN },
    603         { "version",     0, irc_cmd_version,     IRC_CMD_LOGGED_IN },
    604         { "completions", 0, irc_cmd_completions, IRC_CMD_LOGGED_IN },
     632#endif
     633        { "oper",        2, irc_cmd_oper,        IRC_CMD_LOGGED_IN },
    605634        { "die",         0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
    606635        { "deaf",        0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
     
    628657                        if( irc_commands[i].flags & IRC_CMD_PRE_LOGIN && irc->status & USTATUS_LOGGED_IN )
    629658                        {
    630                                 irc_reply( irc, 462, ":Only allowed before logging in" );
     659                                irc_send_num( irc, 462, ":Only allowed before logging in" );
    631660                        }
    632661                        else if( irc_commands[i].flags & IRC_CMD_LOGGED_IN && !( irc->status & USTATUS_LOGGED_IN ) )
    633662                        {
    634                                 irc_reply( irc, 451, ":Register first" );
     663                                irc_send_num( irc, 451, ":Register first" );
    635664                        }
    636665                        else if( irc_commands[i].flags & IRC_CMD_OPER_ONLY && !strchr( irc->umode, 'o' ) )
    637666                        {
    638                                 irc_reply( irc, 481, ":Permission denied - You're not an IRC operator" );
     667                                irc_send_num( irc, 481, ":Permission denied - You're not an IRC operator" );
    639668                        }
    640669                        else if( n_arg < irc_commands[i].required_parameters )
    641670                        {
    642                                 irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
     671                                irc_send_num( irc, 461, "%s :Need more parameters", cmd[0] );
    643672                        }
    644673                        else if( irc_commands[i].flags & IRC_CMD_TO_MASTER )
     
    657686       
    658687        if( irc->status >= USTATUS_LOGGED_IN )
    659                 irc_reply( irc, 421, "%s :Unknown command", cmd[0] );
    660 }
     688                irc_send_num( irc, 421, "%s :Unknown command", cmd[0] );
     689}
  • lib/Makefile

    r3742fb6 r3429b58  
    1010
    1111# [SH] Program variables
    12 objects = arc.o base64.o $(EVENT_HANDLER) http_client.o ini.o md5.o misc.o oauth.o proxy.o sha1.o $(SSL_CLIENT) url.o xmltree.o
     12objects = arc.o base64.o $(EVENT_HANDLER) ftutil.o http_client.o ini.o md5.o misc.o oauth.o proxy.o sha1.o $(SSL_CLIENT) url.o xmltree.o
    1313
    1414CFLAGS += -Wall
  • lib/misc.c

    r3742fb6 r3429b58  
    648648        return ret;
    649649}
     650
     651char **split_command_parts( char *command )
     652{
     653        static char *cmd[IRC_MAX_ARGS+1];
     654        char *s, q = 0;
     655        int k;
     656       
     657        memset( cmd, 0, sizeof( cmd ) );
     658        cmd[0] = command;
     659        k = 1;
     660        for( s = command; *s && k < IRC_MAX_ARGS; s ++ )
     661                if( *s == ' ' && !q )
     662                {
     663                        *s = 0;
     664                        while( *++s == ' ' );
     665                        if( *s == '"' || *s == '\'' )
     666                        {
     667                                q = *s;
     668                                s ++;
     669                        }
     670                        if( *s )
     671                        {
     672                                cmd[k++] = s;
     673                                s --;
     674                        }
     675                        else
     676                        {
     677                                break;
     678                        }
     679                }
     680                else if( *s == '\\' && ( ( !q && s[1] ) || ( q && q == s[1] ) ) )
     681                {
     682                        char *cpy;
     683                       
     684                        for( cpy = s; *cpy; cpy ++ )
     685                                cpy[0] = cpy[1];
     686                }
     687                else if( *s == q )
     688                {
     689                        q = *s = 0;
     690                }
     691       
     692        /* Full zero-padding for easier argc checking. */
     693        while( k <= IRC_MAX_ARGS )
     694                cmd[k++] = NULL;
     695       
     696        return cmd;
     697}
  • lib/misc.h

    r3742fb6 r3429b58  
    6969G_MODULE_EXPORT int md5_verify_password( char *password, char *hash );
    7070
     71G_MODULE_EXPORT char **split_command_parts( char *command );
     72
    7173#endif
  • nick.c

    r3742fb6 r3429b58  
    7878               
    7979                nick_strip( nick );
    80                 if( set_getbool( &acc->irc->set, "lcnicks" ) )
     80                if( set_getbool( &acc->bee->set, "lcnicks" ) )
    8181                        nick_lc( nick );
    8282        }
     
    9292void nick_dedupe( account_t *acc, const char *handle, char nick[MAX_NICK_LENGTH+1] )
    9393{
     94        irc_t *irc = (irc_t*) acc->bee->ui_data;
    9495        int inf_protection = 256;
    9596       
    9697        /* Now, find out if the nick is already in use at the moment, and make
    9798           subtle changes to make it unique. */
    98         while( !nick_ok( nick ) || user_find( acc->irc, nick ) )
     99        while( !nick_ok( nick ) || irc_user_by_name( irc, nick ) )
    99100        {
    100101                if( strlen( nick ) < ( MAX_NICK_LENGTH - 1 ) )
     
    112113                        int i;
    113114                       
    114                         irc_usermsg( acc->irc, "Warning: Almost had an infinite loop in nick_get()! "
    115                                                "This used to be a fatal BitlBee bug, but we tried to fix it. "
    116                                                "This message should *never* appear anymore. "
    117                                                "If it does, please *do* send us a bug report! "
    118                                                "Please send all the following lines in your report:" );
    119                        
    120                         irc_usermsg( acc->irc, "Trying to get a sane nick for handle %s", handle );
     115                        irc_usermsg( irc, "Warning: Almost had an infinite loop in nick_get()! "
     116                                          "This used to be a fatal BitlBee bug, but we tried to fix it. "
     117                                          "This message should *never* appear anymore. "
     118                                          "If it does, please *do* send us a bug report! "
     119                                          "Please send all the following lines in your report:" );
     120                       
     121                        irc_usermsg( irc, "Trying to get a sane nick for handle %s", handle );
    121122                        for( i = 0; i < MAX_NICK_LENGTH; i ++ )
    122                                 irc_usermsg( acc->irc, "Char %d: %c/%d", i, nick[i], nick[i] );
    123                        
    124                         irc_usermsg( acc->irc, "FAILED. Returning an insane nick now. Things might break. "
    125                                                "Good luck, and please don't forget to paste the lines up here "
    126                                                "in #bitlbee on OFTC or in a mail to wilmer@gaast.net" );
     123                                irc_usermsg( irc, "Char %d: %c/%d", i, nick[i], nick[i] );
     124                       
     125                        irc_usermsg( irc, "FAILED. Returning an insane nick now. Things might break. "
     126                                          "Good luck, and please don't forget to paste the lines up here "
     127                                          "in #bitlbee on OFTC or in a mail to wilmer@gaast.net" );
    127128                       
    128129                        g_snprintf( nick, MAX_NICK_LENGTH + 1, "xx%x", rand() );
  • protocols/Makefile

    r3742fb6 r3429b58  
    1010
    1111# [SH] Program variables
    12 objects = nogaim.o
     12objects = account.o bee.o bee_chat.o bee_ft.o bee_user.o nogaim.o
     13
    1314
    1415# [SH] The next two lines should contain the directory name (in $(subdirs))
  • protocols/jabber/Makefile

    r3742fb6 r3429b58  
    1010
    1111# [SH] Program variables
    12 objects = conference.o io.o iq.o jabber.o jabber_util.o message.o presence.o sasl.o
     12objects = conference.o io.o iq.o jabber.o jabber_util.o message.o presence.o s5bytestream.o sasl.o si.o
    1313
    1414CFLAGS += -Wall
  • protocols/jabber/conference.c

    r3742fb6 r3429b58  
    9292{
    9393        char *normalized = jabber_normalize( name );
     94        GSList *l;
    9495        struct groupchat *ret;
    9596        struct jabber_chat *jc;
    9697       
    97         for( ret = ic->groupchats; ret; ret = ret->next )
    98         {
     98        for( l = ic->groupchats; l; l = l->next )
     99        {
     100                ret = l->data;
    99101                jc = ret->data;
    100102                if( strcmp( normalized, jc->name ) == 0 )
     
    103105        g_free( normalized );
    104106       
    105         return ret;
     107        return l ? ret : NULL;
    106108}
    107109
  • protocols/jabber/iq.c

    r3742fb6 r3429b58  
    9191                        pack = 0;
    9292                }
    93                 else if( strcmp( s, XMLNS_DISCOVER ) == 0 )
    94                 {
    95                         const char *features[] = { XMLNS_DISCOVER,
     93                else if( strcmp( s, XMLNS_DISCO_INFO ) == 0 )
     94                {
     95                        const char *features[] = { XMLNS_DISCO_INFO,
    9696                                                   XMLNS_VERSION,
    9797                                                   XMLNS_TIME,
     
    9999                                                   XMLNS_MUC,
    100100                                                   XMLNS_PING,
     101                                                   XMLNS_SI,
     102                                                   XMLNS_BYTESTREAMS,
     103                                                   XMLNS_FILETRANSFER,
    101104                                                   NULL };
    102105                        const char **f;
     
    118121                {
    119122                        xt_free_node( reply );
    120                         reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel" );
     123                        reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel", NULL );
    121124                        pack = 0;
    122125                }
     
    124127        else if( strcmp( type, "set" ) == 0 )
    125128        {
    126                 if( !( c = xt_find_node( node->children, "query" ) ) ||
    127                     !( s = xt_find_attr( c, "xmlns" ) ) )
     129                if( ( c = xt_find_node( node->children, "si" ) ) &&
     130                    ( s = xt_find_attr( c, "xmlns" ) ) &&
     131                    ( strcmp( s, XMLNS_SI ) == 0 ) )
     132                {
     133                        return jabber_si_handle_request( ic, node, c );
     134                }
     135                else if( !( c = xt_find_node( node->children, "query" ) ) ||
     136                         !( s = xt_find_attr( c, "xmlns" ) ) )
    128137                {
    129138                        imcb_log( ic, "Warning: Received incomplete IQ-%s packet", type );
    130139                        return XT_HANDLED;
    131140                }
    132                
     141                else if( strcmp( s, XMLNS_ROSTER ) == 0 )
     142                {
    133143                /* This is a roster push. XMPP servers send this when someone
    134144                   was added to (or removed from) the buddy list. AFAIK they're
    135145                   sent even if we added this buddy in our own session. */
    136                 if( strcmp( s, XMLNS_ROSTER ) == 0 )
    137                 {
    138146                        int bare_len = strlen( ic->acc->user );
    139147                       
     
    152160                               
    153161                                xt_free_node( reply );
    154                                 reply = jabber_make_error_packet( node, "not-allowed", "cancel" );
     162                                reply = jabber_make_error_packet( node, "not-allowed", "cancel", NULL );
    155163                                pack = 0;
    156164                        }
    157165                }
     166                else if( strcmp( s, XMLNS_BYTESTREAMS ) == 0 )
     167                {
     168                        /* Bytestream Request (stage 2 of file transfer) */
     169                        return jabber_bs_recv_request( ic, node, c );
     170                }
    158171                else
    159172                {
    160173                        xt_free_node( reply );
    161                         reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel" );
     174                        reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel", NULL );
    162175                        pack = 0;
    163176                }
     
    370383        while( ( c = xt_find_node( c, "item" ) ) )
    371384        {
    372                 struct xt_node *group = xt_find_node( node->children, "group" );
     385                struct xt_node *group = xt_find_node( c->children, "group" );
    373386                char *jid = xt_find_attr( c, "jid" );
    374387                char *name = xt_find_attr( c, "name" );
     
    379392                        if( ( strcmp( sub, "both" ) == 0 || strcmp( sub, "to" ) == 0 ) )
    380393                        {
    381                                 if( initial || imcb_find_buddy( ic, jid ) == NULL )
     394                                if( initial || bee_user_by_handle( ic->bee, ic, jid ) == NULL )
    382395                                        imcb_add_buddy( ic, jid, ( group && group->text_len ) ?
    383396                                                                   group->text : NULL );
     
    577590            strcmp( s, "result" ) == 0 )
    578591        {
    579                 if( imcb_find_buddy( ic, jid ) == NULL )
     592                if( bee_user_by_handle( ic->bee, ic, jid ) == NULL )
    580593                        imcb_add_buddy( ic, jid, NULL );
    581594        }
     
    609622        return st;
    610623}
     624
     625xt_status jabber_iq_parse_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
     626
     627xt_status jabber_iq_query_features( struct im_connection *ic, char *bare_jid )
     628{
     629        struct xt_node *node, *query;
     630        struct jabber_buddy *bud;
     631       
     632        if( ( bud = jabber_buddy_by_jid( ic, bare_jid , 0 ) ) == NULL )
     633        {
     634                /* Who cares about the unknown... */
     635                imcb_log( ic, "Couldn't find buddy: %s", bare_jid);
     636                return XT_HANDLED;
     637        }
     638       
     639        if( bud->features ) /* been here already */
     640                return XT_HANDLED;
     641       
     642        node = xt_new_node( "query", NULL, NULL );
     643        xt_add_attr( node, "xmlns", XMLNS_DISCO_INFO );
     644       
     645        if( !( query = jabber_make_packet( "iq", "get", bare_jid, node ) ) )
     646        {
     647                imcb_log( ic, "WARNING: Couldn't generate feature query" );
     648                xt_free_node( node );
     649                return XT_HANDLED;
     650        }
     651
     652        jabber_cache_add( ic, query, jabber_iq_parse_features );
     653
     654        return jabber_write_packet( ic, query ) ? XT_HANDLED : XT_ABORT;
     655}
     656
     657xt_status jabber_iq_parse_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
     658{
     659        struct xt_node *c;
     660        struct jabber_buddy *bud;
     661        char *feature, *xmlns, *from;
     662
     663        if( !( from = xt_find_attr( node, "from" ) ) ||
     664            !( c = xt_find_node( node->children, "query" ) ) ||
     665            !( xmlns = xt_find_attr( c, "xmlns" ) ) ||
     666            !( strcmp( xmlns, XMLNS_DISCO_INFO ) == 0 ) )
     667        {
     668                imcb_log( ic, "WARNING: Received incomplete IQ-result packet for discover" );
     669                return XT_HANDLED;
     670        }
     671        if( ( bud = jabber_buddy_by_jid( ic, from, 0 ) ) == NULL )
     672        {
     673                /* Who cares about the unknown... */
     674                imcb_log( ic, "Couldn't find buddy: %s", from );
     675                return XT_HANDLED;
     676        }
     677       
     678        c = c->children;
     679        while( ( c = xt_find_node( c, "feature" ) ) )
     680        {
     681                feature = xt_find_attr( c, "var" );
     682                if( feature )
     683                        bud->features = g_slist_append( bud->features, g_strdup( feature ) );
     684                c = c->next;
     685        }
     686
     687        return XT_HANDLED;
     688}
     689
     690xt_status jabber_iq_parse_server_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
     691
     692xt_status jabber_iq_query_server( struct im_connection *ic, char *jid, char *xmlns )
     693{
     694        struct xt_node *node, *query;
     695        struct jabber_data *jd = ic->proto_data;
     696       
     697        node = xt_new_node( "query", NULL, NULL );
     698        xt_add_attr( node, "xmlns", xmlns );
     699       
     700        if( !( query = jabber_make_packet( "iq", "get", jid, node ) ) )
     701        {
     702                imcb_log( ic, "WARNING: Couldn't generate server query" );
     703                xt_free_node( node );
     704        }
     705
     706        jd->have_streamhosts--;
     707        jabber_cache_add( ic, query, jabber_iq_parse_server_features );
     708
     709        return jabber_write_packet( ic, query ) ? XT_HANDLED : XT_ABORT;
     710}
     711
     712/*
     713 * Query the server for "items", query each "item" for identities, query each "item" that's a proxy for it's bytestream info
     714 */
     715xt_status jabber_iq_parse_server_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
     716{
     717        struct xt_node *c;
     718        struct jabber_data *jd = ic->proto_data;
     719        char *xmlns, *from;
     720
     721        if( !( c = xt_find_node( node->children, "query" ) ) ||
     722            !( from = xt_find_attr( node, "from" ) ) ||
     723            !( xmlns = xt_find_attr( c, "xmlns" ) ) )
     724        {
     725                imcb_log( ic, "WARNING: Received incomplete IQ-result packet for discover" );
     726                return XT_HANDLED;
     727        }
     728
     729        jd->have_streamhosts++;
     730
     731        if( strcmp( xmlns, XMLNS_DISCO_ITEMS ) == 0 )
     732        {
     733                char *itemjid;
     734
     735                /* answer from server */
     736       
     737                c = c->children;
     738                while( ( c = xt_find_node( c, "item" ) ) )
     739                {
     740                        itemjid = xt_find_attr( c, "jid" );
     741                       
     742                        if( itemjid )
     743                                jabber_iq_query_server( ic, itemjid, XMLNS_DISCO_INFO );
     744
     745                        c = c->next;
     746                }
     747        }
     748        else if( strcmp( xmlns, XMLNS_DISCO_INFO ) == 0 )
     749        {
     750                char *category, *type;
     751
     752                /* answer from potential proxy */
     753
     754                c = c->children;
     755                while( ( c = xt_find_node( c, "identity" ) ) )
     756                {
     757                        category = xt_find_attr( c, "category" );
     758                        type = xt_find_attr( c, "type" );
     759
     760                        if( type && ( strcmp( type, "bytestreams" ) == 0 ) &&
     761                            category && ( strcmp( category, "proxy" ) == 0 ) )
     762                                jabber_iq_query_server( ic, from, XMLNS_BYTESTREAMS );
     763
     764                        c = c->next;
     765                }
     766        }
     767        else if( strcmp( xmlns, XMLNS_BYTESTREAMS ) == 0 )
     768        {
     769                char *host, *jid, *port_s;
     770                int port;
     771
     772                /* answer from proxy */
     773
     774                if( ( c = xt_find_node( c->children, "streamhost" ) ) &&
     775                    ( host = xt_find_attr( c, "host" ) ) &&
     776                    ( port_s = xt_find_attr( c, "port" ) ) &&
     777                    ( sscanf( port_s, "%d", &port ) == 1 ) &&
     778                    ( jid = xt_find_attr( c, "jid" ) ) )
     779                {
     780                        jabber_streamhost_t *sh = g_new0( jabber_streamhost_t, 1 );
     781                       
     782                        sh->jid = g_strdup( jid );
     783                        sh->host = g_strdup( host );
     784                        g_snprintf( sh->port, sizeof( sh->port ), "%u", port );
     785
     786                        imcb_log( ic, "Proxy found: jid %s host %s port %u", jid, host, port );
     787                        jd->streamhosts = g_slist_append( jd->streamhosts, sh );
     788                }
     789        }
     790
     791        if( jd->have_streamhosts == 0 )
     792                jd->have_streamhosts++;
     793
     794        return XT_HANDLED;
     795}
  • protocols/jabber/jabber.c

    r3742fb6 r3429b58  
    6565       
    6666        s = set_add( &acc->set, "priority", "0", set_eval_priority, acc );
     67
     68        s = set_add( &acc->set, "proxy", "<local>;<auto>", NULL, acc );
    6769       
    6870        s = set_add( &acc->set, "resource", "BitlBee", NULL, acc );
     
    264266        struct jabber_data *jd = ic->proto_data;
    265267       
     268        while( jd->filetransfers )
     269                imcb_file_canceled( ic, ( ( struct jabber_transfer *) jd->filetransfers->data )->ft, "Logging out" );
     270
     271        while( jd->streamhosts )
     272        {
     273                jabber_streamhost_t *sh = jd->streamhosts->data;
     274                jd->streamhosts = g_slist_remove( jd->streamhosts, sh );
     275                g_free( sh->jid );
     276                g_free( sh->host );
     277                g_free( sh );
     278        }
     279
    266280        if( jd->fd >= 0 )
    267281                jabber_end_stream( ic );
    268282       
    269283        while( ic->groupchats )
    270                 jabber_chat_free( ic->groupchats );
     284                jabber_chat_free( ic->groupchats->data );
    271285       
    272286        if( jd->r_inpa >= 0 )
     
    544558        ret->send_typing = jabber_send_typing;
    545559        ret->handle_cmp = g_strcasecmp;
     560        ret->transfer_request = jabber_si_transfer_request;
    546561
    547562        register_protocol( ret );
  • protocols/jabber/jabber.h

    r3742fb6 r3429b58  
    6161} jabber_buddy_flags_t;
    6262
     63/* Stores a streamhost's (a.k.a. proxy) data */
     64typedef struct
     65{
     66        char *jid;
     67        char *host;
     68        char port[6];
     69} jabber_streamhost_t;
     70
    6371typedef enum
    6472{
     
    9199        GHashTable *node_cache;
    92100        GHashTable *buddies;
     101
     102        GSList *filetransfers;
     103        GSList *streamhosts;
     104        int have_streamhosts;
    93105};
    94106
     
    127139        struct jabber_away_state *away_state;
    128140        char *away_message;
     141        GSList *features;
    129142       
    130143        time_t last_msg;
     
    140153        char *my_full_jid; /* Separate copy because of case sensitivity. */
    141154        struct jabber_buddy *me;
     155};
     156
     157struct jabber_transfer
     158{
     159        /* bitlbee's handle for this transfer */
     160        file_transfer_t *ft;
     161
     162        /* the stream's private handle */
     163        gpointer streamhandle;
     164
     165        /* timeout for discover queries */
     166        gint disco_timeout;
     167        gint disco_timeout_fired;
     168
     169        struct im_connection *ic;
     170
     171        struct jabber_buddy *bud;
     172
     173        int watch_in;
     174        int watch_out;
     175
     176        char *ini_jid;
     177        char *tgt_jid;
     178        char *iq_id;
     179        char *sid;
     180        int accepted;
     181
     182        size_t bytesread, byteswritten;
     183        int fd;
     184        struct sockaddr_storage saddr;
    142185};
    143186
     
    167210
    168211/* Some supported extensions/legacy stuff */
    169 #define XMLNS_AUTH         "jabber:iq:auth"                     /* XEP-0078 */
    170 #define XMLNS_VERSION      "jabber:iq:version"                  /* XEP-0092 */
    171 #define XMLNS_TIME         "jabber:iq:time"                     /* XEP-0090 */
    172 #define XMLNS_PING         "urn:xmpp:ping"                      /* XEP-0199 */
    173 #define XMLNS_VCARD        "vcard-temp"                         /* XEP-0054 */
    174 #define XMLNS_DELAY        "jabber:x:delay"                     /* XEP-0091 */
    175 #define XMLNS_CHATSTATES   "http://jabber.org/protocol/chatstates"  /* 0085 */
    176 #define XMLNS_DISCOVER     "http://jabber.org/protocol/disco#info"  /* 0030 */
    177 #define XMLNS_MUC          "http://jabber.org/protocol/muc"     /* XEP-0045 */
    178 #define XMLNS_MUC_USER     "http://jabber.org/protocol/muc#user"/* XEP-0045 */
    179 #define XMLNS_CAPS         "http://jabber.org/protocol/caps"    /* XEP-0115 */
     212#define XMLNS_AUTH         "jabber:iq:auth"                                      /* XEP-0078 */
     213#define XMLNS_VERSION      "jabber:iq:version"                                   /* XEP-0092 */
     214#define XMLNS_TIME         "jabber:iq:time"                                      /* XEP-0090 */
     215#define XMLNS_PING         "urn:xmpp:ping"                                       /* XEP-0199 */
     216#define XMLNS_VCARD        "vcard-temp"                                          /* XEP-0054 */
     217#define XMLNS_DELAY        "jabber:x:delay"                                      /* XEP-0091 */
     218#define XMLNS_XDATA        "jabber:x:data"                                       /* XEP-0004 */
     219#define XMLNS_CHATSTATES   "http://jabber.org/protocol/chatstates"               /* XEP-0085 */
     220#define XMLNS_DISCO_INFO   "http://jabber.org/protocol/disco#info"               /* XEP-0030 */
     221#define XMLNS_DISCO_ITEMS  "http://jabber.org/protocol/disco#items"              /* XEP-0030 */
     222#define XMLNS_MUC          "http://jabber.org/protocol/muc"                      /* XEP-0045 */
     223#define XMLNS_MUC_USER     "http://jabber.org/protocol/muc#user"                 /* XEP-0045 */
     224#define XMLNS_CAPS         "http://jabber.org/protocol/caps"                     /* XEP-0115 */
     225#define XMLNS_FEATURE      "http://jabber.org/protocol/feature-neg"              /* XEP-0020 */
     226#define XMLNS_SI           "http://jabber.org/protocol/si"                       /* XEP-0095 */
     227#define XMLNS_FILETRANSFER "http://jabber.org/protocol/si/profile/file-transfer" /* XEP-0096 */
     228#define XMLNS_BYTESTREAMS  "http://jabber.org/protocol/bytestreams"              /* XEP-0065 */
     229#define XMLNS_IBB          "http://jabber.org/protocol/ibb"                      /* XEP-0047 */
    180230
    181231/* iq.c */
     
    187237int jabber_add_to_roster( struct im_connection *ic, char *handle, char *name );
    188238int jabber_remove_from_roster( struct im_connection *ic, char *handle );
     239xt_status jabber_iq_query_features( struct im_connection *ic, char *bare_jid );
     240xt_status jabber_iq_query_server( struct im_connection *ic, char *jid, char *xmlns );
     241
     242/* si.c */
     243int jabber_si_handle_request( struct im_connection *ic, struct xt_node *node, struct xt_node *sinode );
     244void jabber_si_transfer_request( struct im_connection *ic, file_transfer_t *ft, char *who );
     245void jabber_si_free_transfer( file_transfer_t *ft);
     246
     247/* s5bytestream.c */
     248int jabber_bs_recv_request( struct im_connection *ic, struct xt_node *node, struct xt_node *qnode);
     249gboolean jabber_bs_send_start( struct jabber_transfer *tf );
     250gboolean jabber_bs_send_write( file_transfer_t *ft, char *buffer, unsigned int len );
    189251
    190252/* message.c */
     
    200262char *set_eval_tls( set_t *set, char *value );
    201263struct xt_node *jabber_make_packet( char *name, char *type, char *to, struct xt_node *children );
    202 struct xt_node *jabber_make_error_packet( struct xt_node *orig, char *err_cond, char *err_type );
     264struct xt_node *jabber_make_error_packet( struct xt_node *orig, char *err_cond, char *err_type, char *err_code );
    203265void jabber_cache_add( struct im_connection *ic, struct xt_node *node, jabber_cache_event func );
    204266struct xt_node *jabber_cache_get( struct im_connection *ic, char *id );
  • protocols/jabber/jabber_util.c

    r3742fb6 r3429b58  
    9999}
    100100
    101 struct xt_node *jabber_make_error_packet( struct xt_node *orig, char *err_cond, char *err_type )
     101struct xt_node *jabber_make_error_packet( struct xt_node *orig, char *err_cond, char *err_type, char *err_code )
    102102{
    103103        struct xt_node *node, *c;
     
    111111        c = xt_new_node( "error", NULL, c );
    112112        xt_add_attr( c, "type", err_type );
     113       
     114        /* Add the error code, if present */
     115        if (err_code)
     116                xt_add_attr( c, "code", err_code );
    113117       
    114118        /* To make the actual error packet, we copy the original packet and
     
    275279        presence_send_request( bla->ic, bla->handle, "subscribed" );
    276280       
    277         if( imcb_find_buddy( bla->ic, bla->handle ) == NULL )
    278                 imcb_ask_add( bla->ic, bla->handle, NULL );
     281        imcb_ask_add( bla->ic, bla->handle, NULL );
    279282       
    280283        g_free( bla->handle );
     
    458461               
    459462                if( bud == NULL && ( flags & GET_BUDDY_CREAT ) &&
    460                     ( bare_exists || imcb_find_buddy( ic, jid ) ) )
     463                    ( bare_exists || bee_user_by_handle( ic->bee, ic, jid ) ) )
    461464                {
    462465                        *s = '/';
     
    479482                if( bud == NULL )
    480483                        /* No match. Create it now? */
    481                         return ( ( flags & GET_BUDDY_CREAT ) && imcb_find_buddy( ic, jid_ ) ) ?
     484                        return ( ( flags & GET_BUDDY_CREAT ) &&
     485                                 bee_user_by_handle( ic->bee, ic, jid_ ) ) ?
    482486                                   jabber_buddy_add( ic, jid_ ) : NULL;
    483487                else if( bud->resource && ( flags & GET_BUDDY_EXACT ) )
  • protocols/jabber/presence.c

    r3742fb6 r3429b58  
    205205        struct jabber_data *jd = ic->proto_data;
    206206        struct xt_node *node, *cap;
    207         struct groupchat *c;
     207        GSList *l;
    208208        int st;
    209209       
     
    229229        /* Have to send this update to all groupchats too, the server won't
    230230           do this automatically. */
    231         for( c = ic->groupchats; c && st; c = c->next )
    232         {
     231        for( l = ic->groupchats; l && st; l = l->next )
     232        {
     233                struct groupchat *c = l->data;
    233234                struct jabber_chat *jc = c->data;
    234235               
  • protocols/msn/msn.c

    r3742fb6 r3429b58  
    7979        if( md )
    8080        {
     81                /** Disabling MSN ft support for now.
     82                while( md->filetransfers ) {
     83                        imcb_file_canceled( md->filetransfers->data, "Closing connection" );
     84                }
     85                */
     86               
    8187                if( md->fd >= 0 )
    8288                        closesocket( md->fd );
     
    217223{
    218224        struct msn_switchboard *sb;
     225        struct groupchat *c = imcb_chat_new( ic, who );
    219226       
    220227        if( ( sb = msn_sb_by_handle( ic, who ) ) )
     
    234241                msn_sb_write_msg( ic, m );
    235242
    236                 return NULL;
    237         }
    238        
    239         return NULL;
     243                return c;
     244        }
    240245}
    241246
     
    328333        ret->send_typing = msn_send_typing;
    329334        ret->handle_cmp = g_strcasecmp;
     335        //ret->transfer_request = msn_ftp_transfer_request;
    330336
    331337        register_protocol(ret);
  • protocols/msn/msn.h

    r3742fb6 r3429b58  
    7474        int sb_failures;
    7575        time_t first_sb_failure;
     76        GSList *filetransfers;
    7677       
    7778        const struct msn_away_state *away_state;
     
    189190void msn_sb_stop_keepalives( struct msn_switchboard *sb );
    190191
     192/* invitation.c */
     193void msn_ftp_transfer_request( struct im_connection *ic, file_transfer_t *ft, char *who );
     194
    191195#endif //_MSN_H
  • protocols/msn/msn_util.c

    r3742fb6 r3429b58  
    9696        msn_buddy_list_add( bla->ic, "AL", bla->handle, bla->realname );
    9797       
    98         if( imcb_find_buddy( bla->ic, bla->handle ) == NULL )
    99                 imcb_ask_add( bla->ic, bla->handle, NULL );
     98        imcb_ask_add( bla->ic, bla->handle, NULL );
    10099       
    101100        g_free( bla->handle );
  • protocols/msn/sb.c

    r3742fb6 r3429b58  
    2929#include "passport.h"
    3030#include "md5.h"
     31#include "invitation.h"
    3132
    3233static gboolean msn_sb_callback( gpointer data, gint source, b_input_condition cond );
     
    177178                {
    178179                        buf = g_strdup( SB_KEEPALIVE_HEADERS );
     180                        i = strlen( buf );
     181                }
     182                else if( strncmp( text, MSN_INVITE_HEADERS, sizeof( MSN_INVITE_HEADERS ) - 1 ) == 0 )
     183                {
     184                        buf = g_strdup( text );
    179185                        i = strlen( buf );
    180186                }
     
    227233{
    228234        struct im_connection *ic = sb->ic;
     235        struct groupchat *c = NULL;
    229236        char buf[1024];
    230237       
    231238        /* Create the groupchat structure. */
    232239        g_snprintf( buf, sizeof( buf ), "MSN groupchat session %d", sb->session );
    233         sb->chat = imcb_chat_new( ic, buf );
     240        if( sb->who )
     241                c = bee_chat_by_title( ic->bee, ic, sb->who );
     242        if( c && !msn_sb_by_chat( c ) )
     243                sb->chat = c;
     244        else
     245                sb->chat = imcb_chat_new( ic, buf );
    234246       
    235247        /* Populate the channel. */
     
    692704                        }
    693705                }
     706#if 0
     707                // Disable MSN ft support for now.
    694708                else if( g_strncasecmp( ct, "text/x-msmsgsinvite", 19 ) == 0 )
    695709                {
    696                         char *itype = msn_findheader( body, "Application-GUID:", blen );
    697                         char buf[1024];
     710                        char *command = msn_findheader( body, "Invitation-Command:", blen );
     711                        char *cookie = msn_findheader( body, "Invitation-Cookie:", blen );
     712                        unsigned int icookie;
    698713                       
    699714                        g_free( ct );
    700715                       
    701                         *buf = 0;
    702                        
    703                         if( !itype )
    704                                 return( 1 );
    705                        
    706                         /* File transfer. */
    707                         if( strcmp( itype, "{5D3E02AB-6190-11d3-BBBB-00C04F795683}" ) == 0 )
    708                         {
    709                                 char *name = msn_findheader( body, "Application-File:", blen );
    710                                 char *size = msn_findheader( body, "Application-FileSize:", blen );
    711                                
    712                                 if( name && size )
    713                                 {
    714                                         g_snprintf( buf, sizeof( buf ), "<< \x02""BitlBee\x02"" - Filetransfer: `%s', %s bytes >>\n"
    715                                                     "Filetransfers are not supported by BitlBee for now...", name, size );
    716                                 }
    717                                 else
    718                                 {
    719                                         strcpy( buf, "<< \x02""BitlBee\x02"" - Corrupted MSN filetransfer invitation message >>" );
    720                                 }
    721                                
    722                                 if( name ) g_free( name );
    723                                 if( size ) g_free( size );
    724                         }
    725                         else
    726                         {
    727                                 char *iname = msn_findheader( body, "Application-Name:", blen );
    728                                
    729                                 g_snprintf( buf, sizeof( buf ), "<< \x02""BitlBee\x02"" - Unknown MSN invitation - %s (%s) >>",
    730                                                                 itype, iname ? iname : "no name" );
    731                                
    732                                 if( iname ) g_free( iname );
    733                         }
    734                        
    735                         g_free( itype );
    736                        
    737                         if( !*buf )
    738                                 return( 1 );
    739                        
    740                         if( sb->who )
    741                         {
    742                                 imcb_buddy_msg( ic, cmd[1], buf, 0, 0 );
    743                         }
    744                         else if( sb->chat )
    745                         {
    746                                 imcb_chat_msg( sb->chat, cmd[1], buf, 0, 0 );
    747                         }
    748                         else
    749                         {
    750                                 /* PANIC! */
    751                         }
     716                        /* Every invite should have both a Command and Cookie header */
     717                        if( !command || !cookie ) {
     718                                g_free( command );
     719                                g_free( cookie );
     720                                imcb_log( ic, "Warning: No command or cookie from %s", sb->who );
     721                                return 1;
     722                        }
     723                       
     724                        icookie = strtoul( cookie, NULL, 10 );
     725                        g_free( cookie );
     726                       
     727                        if( g_strncasecmp( command, "INVITE", 6 ) == 0 ) {
     728                                msn_invitation_invite( sb, cmd[1], icookie, body, blen );
     729                        } else if( g_strncasecmp( command, "ACCEPT", 6 ) == 0 ) {
     730                                msn_invitation_accept( sb, cmd[1], icookie, body, blen );
     731                        } else if( g_strncasecmp( command, "CANCEL", 6 ) == 0 ) {
     732                                msn_invitation_cancel( sb, cmd[1], icookie, body, blen );
     733                        } else {
     734                                imcb_log( ic, "Warning: Received invalid invitation with "
     735                                                "command %s from %s", command, sb->who );
     736                        }
     737                       
     738                        g_free( command );
     739                }
     740#endif
     741                else if( g_strncasecmp( ct, "application/x-msnmsgrp2p", 24 ) == 0 )
     742                {
     743                        imcb_error( sb->ic, "Cannot receive file from %s: BitlBee does not "
     744                                        "support msnmsgrp2p yet.", sb->who );
     745                        g_free( ct );
    752746                }
    753747                else if( g_strncasecmp( ct, "text/x-msmsgscontrol", 20 ) == 0 )
     
    780774void msn_sb_start_keepalives( struct msn_switchboard *sb, gboolean initial )
    781775{
    782         struct buddy *b;
     776        bee_user_t *bu;
    783777       
    784778        if( sb && sb->who && sb->keepalive == 0 &&
    785             ( b = imcb_find_buddy( sb->ic, sb->who ) ) && !b->present &&
     779            ( bu = bee_user_by_handle( sb->ic->bee, sb->ic, sb->who ) ) &&
     780            !( bu->flags & BEE_USER_ONLINE ) &&
    786781            set_getbool( &sb->ic->acc->set, "switchboard_keepalives" ) )
    787782        {
  • protocols/nogaim.c

    r3742fb6 r3429b58  
    3838#include "chat.h"
    3939
    40 static int remove_chat_buddy_silent( struct groupchat *b, const char *handle );
    41 static char *format_timestamp( irc_t *irc, time_t msg_ts );
    42 
    4340GSList *connections;
    4441
     
    9289}
    9390#endif
    94 
    95 /* nogaim.c */
    9691
    9792GList *protocols = NULL;
     
    126121}
    127122
    128 /* nogaim.c */
    129123void nogaim_init()
    130124{
     
    162156GSList *get_connections() { return connections; }
    163157
    164 /* multi.c */
    165 
    166158struct im_connection *imcb_new( account_t *acc )
    167159{
     
    170162        ic = g_new0( struct im_connection, 1 );
    171163       
    172         ic->irc = acc->irc;
     164        ic->bee = acc->bee;
    173165        ic->acc = acc;
    174166        acc->ic = ic;
     
    184176       
    185177        /* Destroy the pointer to this connection from the account list */
    186         for( a = ic->irc->accounts; a; a = a->next )
     178        for( a = ic->bee->accounts; a; a = a->next )
    187179                if( a->ic == ic )
    188180                {
     
    205197        va_end( params );
    206198
    207         if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) ||
    208             ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )
     199        if( ( g_strcasecmp( set_getstr( &ic->bee->set, "strip_html" ), "always" ) == 0 ) ||
     200            ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->bee->set, "strip_html" ) ) )
    209201                strip_html( text );
    210202       
    211203        /* Try to find a different connection on the same protocol. */
    212         for( a = ic->irc->accounts; a; a = a->next )
     204        for( a = ic->bee->accounts; a; a = a->next )
    213205                if( a->prpl == ic->acc->prpl && a->ic != ic )
    214206                        break;
     
    216208        /* If we found one, include the screenname in the message. */
    217209        if( a )
    218                 irc_usermsg( ic->irc, "%s(%s) - %s", ic->acc->prpl->name, ic->acc->user, text );
     210                /* FIXME(wilmer): ui_log callback or so */
     211                irc_usermsg( ic->bee->ui_data, "%s(%s) - %s", ic->acc->prpl->name, ic->acc->user, text );
    219212        else
    220                 irc_usermsg( ic->irc, "%s - %s", ic->acc->prpl->name, text );
     213                irc_usermsg( ic->bee->ui_data, "%s - %s", ic->acc->prpl->name, text );
    221214       
    222215        g_free( text );
     
    269262void imcb_connected( struct im_connection *ic )
    270263{
    271         irc_t *irc = ic->irc;
    272         struct chat *c;
    273         user_t *u;
    274        
    275264        /* MSN servers sometimes redirect you to a different server and do
    276265           the whole login sequence again, so these "late" calls to this
     
    279268                return;
    280269       
    281         u = user_find( ic->irc, ic->irc->nick );
    282        
    283270        imcb_log( ic, "Logged in" );
    284271       
     
    293280        ic->acc->auto_reconnect_delay = 0;
    294281       
     282        /*
    295283        for( c = irc->chatrooms; c; c = c->next )
    296284        {
     
    301289                        chat_join( irc, c, NULL );
    302290        }
     291        */
    303292}
    304293
     
    308297       
    309298        a->reconnect = 0;
    310         account_on( a->irc, a );
     299        account_on( a->bee, a );
    311300       
    312301        return( FALSE );        /* Only have to run the timeout once */
     
    321310void imc_logout( struct im_connection *ic, int allow_reconnect )
    322311{
    323         irc_t *irc = ic->irc;
    324         user_t *t, *u;
     312        bee_t *bee = ic->bee;
    325313        account_t *a;
     314        GSList *l;
    326315        int delay;
    327316       
     
    343332        ic->away = NULL;
    344333       
    345         u = irc->users;
    346         while( u )
    347         {
    348                 if( u->ic == ic )
    349                 {
    350                         t = u->next;
    351                         user_del( irc, u->nick );
    352                         u = t;
    353                 }
    354                 else
    355                         u = u->next;
    356         }
    357        
    358         query_del_by_conn( ic->irc, ic );
    359        
    360         for( a = irc->accounts; a; a = a->next )
     334        for( l = bee->users; l; )
     335        {
     336                bee_user_t *bu = l->data;
     337                GSList *next = l->next;
     338               
     339                if( bu->ic == ic )
     340                        bee_user_free( bee, bu );
     341               
     342                l = next;
     343        }
     344       
     345        query_del_by_conn( (irc_t*) ic->bee->ui_data, ic );
     346       
     347        for( a = bee->accounts; a; a = a->next )
    361348                if( a->ic == ic )
    362349                        break;
     
    366353                /* Uhm... This is very sick. */
    367354        }
    368         else if( allow_reconnect && set_getbool( &irc->set, "auto_reconnect" ) &&
     355        else if( allow_reconnect && set_getbool( &bee->set, "auto_reconnect" ) &&
    369356                 set_getbool( &a->set, "auto_reconnect" ) &&
    370357                 ( delay = account_reconnect_delay( a ) ) > 0 )
     
    377364}
    378365
    379 
    380 /* dialogs.c */
    381 
    382366void imcb_ask( struct im_connection *ic, char *msg, void *data,
    383367               query_callback doit, query_callback dont )
    384368{
    385         query_add( ic->irc, ic, msg, doit, dont, data );
    386 }
    387 
    388 
    389 /* list.c */
     369        query_add( (irc_t *) ic->bee->ui_data, ic, msg, doit, dont, data );
     370}
    390371
    391372void imcb_add_buddy( struct im_connection *ic, const char *handle, const char *group )
    392373{
    393         user_t *u;
    394         char nick[MAX_NICK_LENGTH+1], *s;
    395         irc_t *irc = ic->irc;
    396        
    397         if( user_findhandle( ic, handle ) )
    398         {
    399                 if( set_getbool( &irc->set, "debug" ) )
    400                         imcb_log( ic, "User already exists, ignoring add request: %s", handle );
    401                
    402                 return;
    403                
    404                 /* Buddy seems to exist already. Let's ignore this request then...
    405                    Eventually subsequent calls to this function *should* be possible
    406                    when a buddy is in multiple groups. But for now BitlBee doesn't
    407                    even support groups so let's silently ignore this for now. */
    408         }
    409        
    410         memset( nick, 0, MAX_NICK_LENGTH + 1 );
    411         strcpy( nick, nick_get( ic->acc, handle ) );
    412        
    413         u = user_add( ic->irc, nick );
    414        
    415 //      if( !realname || !*realname ) realname = nick;
    416 //      u->realname = g_strdup( realname );
    417        
    418         if( ( s = strchr( handle, '@' ) ) )
    419         {
    420                 u->host = g_strdup( s + 1 );
    421                 u->user = g_strndup( handle, s - handle );
    422         }
    423         else if( ic->acc->server )
    424         {
    425                 u->host = g_strdup( ic->acc->server );
    426                 u->user = g_strdup( handle );
    427                
    428                 /* s/ /_/ ... important for AOL screennames */
    429                 for( s = u->user; *s; s ++ )
    430                         if( *s == ' ' )
    431                                 *s = '_';
    432         }
    433         else
    434         {
    435                 u->host = g_strdup( ic->acc->prpl->name );
    436                 u->user = g_strdup( handle );
    437         }
    438        
    439         u->ic = ic;
    440         u->handle = g_strdup( handle );
    441         if( group ) u->group = g_strdup( group );
    442         u->send_handler = buddy_send_handler;
    443         u->last_typing_notice = 0;
    444 }
    445 
    446 struct buddy *imcb_find_buddy( struct im_connection *ic, char *handle )
    447 {
    448         static struct buddy b[1];
    449         user_t *u;
    450        
    451         u = user_findhandle( ic, handle );
    452        
    453         if( !u )
    454                 return( NULL );
    455        
    456         memset( b, 0, sizeof( b ) );
    457         strncpy( b->name, handle, 80 );
    458         strncpy( b->show, u->realname, BUDDY_ALIAS_MAXLEN );
    459         b->present = u->online;
    460         b->ic = u->ic;
    461        
    462         return( b );
    463 }
    464 
    465 void imcb_rename_buddy( struct im_connection *ic, const char *handle, const char *realname )
    466 {
    467         user_t *u = user_findhandle( ic, handle );
    468         char *set;
    469        
    470         if( !u || !realname ) return;
    471        
    472         if( g_strcasecmp( u->realname, realname ) != 0 )
    473         {
    474                 if( u->realname != u->nick ) g_free( u->realname );
    475                
    476                 u->realname = g_strdup( realname );
    477                
    478                 if( ( ic->flags & OPT_LOGGED_IN ) && set_getbool( &ic->irc->set, "display_namechanges" ) )
    479                         imcb_log( ic, "User `%s' changed name to `%s'", u->nick, u->realname );
    480         }
    481        
    482         set = set_getstr( &ic->acc->set, "nick_source" );
    483         if( strcmp( set, "handle" ) != 0 )
    484         {
    485                 char *name = g_strdup( realname );
    486                
    487                 if( strcmp( set, "first_name" ) == 0 )
    488                 {
    489                         int i;
    490                         for( i = 0; name[i] && !isspace( name[i] ); i ++ ) {}
    491                         name[i] = '\0';
    492                 }
    493                
    494                 imcb_buddy_nick_hint( ic, handle, name );
    495                
    496                 g_free( name );
     374        bee_user_t *bu;
     375        bee_t *bee = ic->bee;
     376       
     377        if( !( bu = bee_user_by_handle( bee, ic, handle ) ) )
     378                bu = bee_user_new( bee, ic, handle );
     379       
     380        bu->group = bee_group_by_name( bee, group, TRUE );
     381}
     382
     383void imcb_rename_buddy( struct im_connection *ic, const char *handle, const char *fullname )
     384{
     385        bee_t *bee = ic->bee;
     386        bee_user_t *bu = bee_user_by_handle( bee, ic, handle );
     387       
     388        if( !bu || !fullname ) return;
     389       
     390        if( !bu->fullname || strcmp( bu->fullname, fullname ) != 0 )
     391        {
     392                g_free( bu->fullname );
     393                bu->fullname = g_strdup( fullname );
     394               
     395                if( bee->ui->user_fullname )
     396                        bee->ui->user_fullname( bee, bu );
    497397        }
    498398}
     
    500400void imcb_remove_buddy( struct im_connection *ic, const char *handle, char *group )
    501401{
    502         user_t *u;
    503        
    504         if( ( u = user_findhandle( ic, handle ) ) )
    505                 user_del( ic->irc, u->nick );
     402        bee_user_free( ic->bee, bee_user_by_handle( ic->bee, ic, handle ) );
    506403}
    507404
     
    510407void imcb_buddy_nick_hint( struct im_connection *ic, const char *handle, const char *nick )
    511408{
     409#if 0
    512410        user_t *u = user_findhandle( ic, handle );
    513411        char newnick[MAX_NICK_LENGTH+1], *orig_nick;
     
    524422                /* Some processing to make sure this string is a valid IRC nickname. */
    525423                nick_strip( newnick );
    526                 if( set_getbool( &ic->irc->set, "lcnicks" ) )
     424                if( set_getbool( &ic->bee->set, "lcnicks" ) )
    527425                        nick_lc( newnick );
    528426               
     
    541439                }
    542440        }
     441#endif
    543442}
    544443
     
    585484        data->ic = ic;
    586485        data->handle = g_strdup( handle );
    587         query_add( ic->irc, ic, s, imcb_ask_auth_cb_yes, imcb_ask_auth_cb_no, data );
     486        query_add( (irc_t *) ic->bee->ui_data, ic, s,
     487                   imcb_ask_auth_cb_yes, imcb_ask_auth_cb_no, data );
    588488}
    589489
     
    610510       
    611511        /* TODO: Make a setting for this! */
    612         if( user_findhandle( ic, handle ) != NULL )
     512        if( bee_user_by_handle( ic->bee, ic, handle ) != NULL )
    613513                return;
    614514       
     
    617517        data->ic = ic;
    618518        data->handle = g_strdup( handle );
    619         query_add( ic->irc, ic, s, imcb_ask_add_cb_yes, imcb_ask_add_cb_no, data );
    620 }
    621 
    622 
    623 /* server.c */                   
    624 
    625 void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, const char *state, const char *message )
    626 {
    627         user_t *u;
    628         int oa, oo;
    629        
    630         u = user_findhandle( ic, (char*) handle );
    631        
    632         if( !u )
    633         {
    634                 if( g_strcasecmp( set_getstr( &ic->irc->set, "handle_unknown" ), "add" ) == 0 )
    635                 {
    636                         imcb_add_buddy( ic, (char*) handle, NULL );
    637                         u = user_findhandle( ic, (char*) handle );
    638                 }
    639                 else
    640                 {
    641                         if( set_getbool( &ic->irc->set, "debug" ) || g_strcasecmp( set_getstr( &ic->irc->set, "handle_unknown" ), "ignore" ) != 0 )
    642                         {
    643                                 imcb_log( ic, "imcb_buddy_status() for unknown handle %s:", handle );
    644                                 imcb_log( ic, "flags = %d, state = %s, message = %s", flags,
    645                                           state ? state : "NULL", message ? message : "NULL" );
    646                         }
    647                        
    648                         return;
    649                 }
    650         }
    651        
    652         oa = u->away != NULL;
    653         oo = u->online;
    654        
    655         g_free( u->away );
    656         g_free( u->status_msg );
    657         u->away = u->status_msg = NULL;
    658        
    659         if( set_getbool( &ic->irc->set, "show_offline" ) && !u->online )
    660         {
    661                 /* always set users as online */
    662                 irc_spawn( ic->irc, u );
    663                 u->online = 1;
    664                 if( !( flags & OPT_LOGGED_IN ) )
    665                 {
    666                         /* set away message if user isn't really online */
    667                         u->away = g_strdup( "User is offline" );
    668                 }
    669         }
    670         else if( ( flags & OPT_LOGGED_IN ) && !u->online )
    671         {
    672                 irc_spawn( ic->irc, u );
    673                 u->online = 1;
    674         }
    675         else if( !( flags & OPT_LOGGED_IN ) && u->online )
    676         {
    677                 struct groupchat *c;
    678                
    679                 if( set_getbool( &ic->irc->set, "show_offline" ) )
    680                 {
    681                         /* keep offline users in channel and set away message to "offline" */
    682                         u->away = g_strdup( "User is offline" );
    683 
    684                         /* Keep showing him/her in the control channel but not in groupchats. */
    685                         for( c = ic->groupchats; c; c = c->next )
    686                         {
    687                                 if( remove_chat_buddy_silent( c, handle ) && c->joined )
    688                                         irc_part( c->ic->irc, u, c->channel );
    689                         }
    690                 }
    691                 else
    692                 {
    693                         /* kill offline users */
    694                         irc_kill( ic->irc, u );
    695                         u->online = 0;
    696 
    697                         /* Remove him/her from the groupchats to prevent PART messages after he/she QUIT already */
    698                         for( c = ic->groupchats; c; c = c->next )
    699                                 remove_chat_buddy_silent( c, handle );
    700                 }
    701         }
    702 
    703         if( flags & OPT_AWAY )
    704         {
    705                 if( state && message )
    706                 {
    707                         u->away = g_strdup_printf( "%s (%s)", state, message );
    708                 }
    709                 else if( state )
    710                 {
    711                         u->away = g_strdup( state );
    712                 }
    713                 else if( message )
    714                 {
    715                         u->away = g_strdup( message );
    716                 }
    717                 else
    718                 {
    719                         u->away = g_strdup( "Away" );
    720                 }
    721         }
    722         else
    723         {
    724                 u->status_msg = g_strdup( message );
    725         }
    726        
    727         /* early if-clause for show_offline even if there is some redundant code here because this isn't LISP but C ;) */
    728         if( set_getbool( &ic->irc->set, "show_offline" ) && set_getbool( &ic->irc->set, "away_devoice" ) )
    729         {
    730                 char *from;
    731                
    732                 if( set_getbool( &ic->irc->set, "simulate_netsplit" ) )
    733                 {
    734                         from = g_strdup( ic->irc->myhost );
    735                 }
    736                 else
    737                 {
    738                         from = g_strdup_printf( "%s!%s@%s", ic->irc->mynick, ic->irc->mynick,
    739                                                             ic->irc->myhost );
    740                 }
    741 
    742                 /* if we use show_offline, we op online users, voice away users, and devoice/deop offline users */
    743                 if( flags & OPT_LOGGED_IN )
    744                 {
    745                         /* user is "online" (either really online or away) */
    746                         irc_write( ic->irc, ":%s MODE %s %cv%co %s %s", from, ic->irc->channel,
    747                                                                   u->away?'+':'-', u->away?'-':'+', u->nick, u->nick );
    748                 }
    749                 else
    750                 {
    751                         /* user is offline */
    752                         irc_write( ic->irc, ":%s MODE %s -vo %s %s", from, ic->irc->channel, u->nick, u->nick );
    753                 }
    754         }
    755         else
    756         {
    757                 /* LISPy... */
    758                 if( ( set_getbool( &ic->irc->set, "away_devoice" ) ) &&         /* Don't do a thing when user doesn't want it */
    759                     ( u->online ) &&                                            /* Don't touch offline people */
    760                     ( ( ( u->online != oo ) && !u->away ) ||                    /* Voice joining people */
    761                       ( ( u->online == oo ) && ( oa == !u->away ) ) ) )         /* (De)voice people changing state */
    762                 {
    763                         char *from;
    764 
    765                         if( set_getbool( &ic->irc->set, "simulate_netsplit" ) )
    766                         {
    767                                 from = g_strdup( ic->irc->myhost );
    768                         }
    769                         else
    770                         {
    771                                 from = g_strdup_printf( "%s!%s@%s", ic->irc->mynick, ic->irc->mynick,
    772                                                                     ic->irc->myhost );
    773                         }
    774                         irc_write( ic->irc, ":%s MODE %s %cv %s", from, ic->irc->channel,
    775                                                                   u->away?'-':'+', u->nick );
    776                         g_free( from );
    777                 }
    778         }
    779 }
    780 
    781 void imcb_buddy_msg( struct im_connection *ic, const char *handle, char *msg, uint32_t flags, time_t sent_at )
    782 {
    783         irc_t *irc = ic->irc;
    784         char *wrapped, *ts = NULL;
    785         user_t *u;
    786        
    787         u = user_findhandle( ic, handle );
    788        
    789         if( !u )
    790         {
    791                 char *h = set_getstr( &irc->set, "handle_unknown" );
    792                
    793                 if( g_strcasecmp( h, "ignore" ) == 0 )
    794                 {
    795                         if( set_getbool( &irc->set, "debug" ) )
    796                                 imcb_log( ic, "Ignoring message from unknown handle %s", handle );
    797                        
    798                         return;
    799                 }
    800                 else if( g_strncasecmp( h, "add", 3 ) == 0 )
    801                 {
    802                         int private = set_getbool( &irc->set, "private" );
    803                        
    804                         if( h[3] )
    805                         {
    806                                 if( g_strcasecmp( h + 3, "_private" ) == 0 )
    807                                         private = 1;
    808                                 else if( g_strcasecmp( h + 3, "_channel" ) == 0 )
    809                                         private = 0;
    810                         }
    811                        
    812                         imcb_add_buddy( ic, handle, NULL );
    813                         u = user_findhandle( ic, handle );
    814                         u->is_private = private;
    815                 }
    816                 else
    817                 {
    818                         imcb_log( ic, "Message from unknown handle %s:", handle );
    819                         u = user_find( irc, irc->mynick );
    820                 }
    821         }
    822        
    823         if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) ||
    824             ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )
    825                 strip_html( msg );
    826        
    827         if( set_getbool( &ic->irc->set, "display_timestamps" ) &&
    828             ( ts = format_timestamp( irc, sent_at ) ) )
    829         {
    830                 char *new = g_strconcat( ts, msg, NULL );
    831                 g_free( ts );
    832                 ts = msg = new;
    833         }
    834        
    835         wrapped = word_wrap( msg, 425 );
    836         irc_msgfrom( irc, u->nick, wrapped );
    837         g_free( wrapped );
    838         g_free( ts );
    839 }
    840 
    841 void imcb_buddy_typing( struct im_connection *ic, char *handle, uint32_t flags )
    842 {
    843         user_t *u;
    844        
    845         if( !set_getbool( &ic->irc->set, "typing_notice" ) )
    846                 return;
    847        
    848         if( ( u = user_findhandle( ic, handle ) ) )
    849         {
    850                 char buf[256];
    851                
    852                 g_snprintf( buf, 256, "\1TYPING %d\1", ( flags >> 8 ) & 3 );
    853                 irc_privmsg( ic->irc, u, "PRIVMSG", ic->irc->nick, NULL, buf );
    854         }
    855 }
    856 
    857 struct groupchat *imcb_chat_new( struct im_connection *ic, const char *handle )
    858 {
    859         struct groupchat *c;
    860        
    861         /* This one just creates the conversation structure, user won't see anything yet */
    862        
    863         if( ic->groupchats )
    864         {
    865                 for( c = ic->groupchats; c->next; c = c->next );
    866                 c = c->next = g_new0( struct groupchat, 1 );
    867         }
    868         else
    869                 ic->groupchats = c = g_new0( struct groupchat, 1 );
    870        
    871         c->ic = ic;
    872         c->title = g_strdup( handle );
    873         c->channel = g_strdup_printf( "&chat_%03d", ic->irc->c_id++ );
    874         c->topic = g_strdup_printf( "BitlBee groupchat: \"%s\". Please keep in mind that root-commands won't work here. Have fun!", c->title );
    875        
    876         if( set_getbool( &ic->irc->set, "debug" ) )
    877                 imcb_log( ic, "Creating new conversation: (id=%p,handle=%s)", c, handle );
    878        
    879         return c;
    880 }
    881 
    882 void imcb_chat_name_hint( struct groupchat *c, const char *name )
    883 {
    884         if( !c->joined )
    885         {
    886                 struct im_connection *ic = c->ic;
    887                 char stripped[MAX_NICK_LENGTH+1], *full_name;
    888                
    889                 strncpy( stripped, name, MAX_NICK_LENGTH );
    890                 stripped[MAX_NICK_LENGTH] = '\0';
    891                 nick_strip( stripped );
    892                 if( set_getbool( &ic->irc->set, "lcnicks" ) )
    893                         nick_lc( stripped );
    894                
    895                 full_name = g_strdup_printf( "&%s", stripped );
    896                
    897                 if( stripped[0] &&
    898                     nick_cmp( stripped, ic->irc->channel + 1 ) != 0 &&
    899                     irc_chat_by_channel( ic->irc, full_name ) == NULL )
    900                 {
    901                         g_free( c->channel );
    902                         c->channel = full_name;
    903                 }
    904                 else
    905                 {
    906                         g_free( full_name );
    907                 }
    908         }
    909 }
    910 
    911 void imcb_chat_free( struct groupchat *c )
    912 {
    913         struct im_connection *ic = c->ic;
    914         struct groupchat *l;
    915         GList *ir;
    916        
    917         if( set_getbool( &ic->irc->set, "debug" ) )
    918                 imcb_log( ic, "You were removed from conversation %p", c );
    919        
    920         if( c )
    921         {
    922                 if( c->joined )
    923                 {
    924                         user_t *u, *r;
    925                        
    926                         r = user_find( ic->irc, ic->irc->mynick );
    927                         irc_privmsg( ic->irc, r, "PRIVMSG", c->channel, "", "Cleaning up channel, bye!" );
    928                        
    929                         u = user_find( ic->irc, ic->irc->nick );
    930                         irc_kick( ic->irc, u, c->channel, r );
    931                         /* irc_part( ic->irc, u, c->channel ); */
    932                 }
    933                
    934                 /* Find the previous chat in the linked list. */
    935                 for( l = ic->groupchats; l && l->next != c; l = l->next );
    936                
    937                 if( l )
    938                         l->next = c->next;
    939                 else
    940                         ic->groupchats = c->next;
    941                
    942                 for( ir = c->in_room; ir; ir = ir->next )
    943                         g_free( ir->data );
    944                 g_list_free( c->in_room );
    945                 g_free( c->channel );
    946                 g_free( c->title );
    947                 g_free( c->topic );
    948                 g_free( c );
    949         }
    950 }
    951 
    952 void imcb_chat_msg( struct groupchat *c, const char *who, char *msg, uint32_t flags, time_t sent_at )
    953 {
    954         struct im_connection *ic = c->ic;
    955         char *wrapped;
    956         user_t *u;
    957        
    958         /* Gaim sends own messages through this too. IRC doesn't want this, so kill them */
    959         if( g_strcasecmp( who, ic->acc->user ) == 0 )
    960                 return;
    961        
    962         u = user_findhandle( ic, who );
    963        
    964         if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) ||
    965             ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )
    966                 strip_html( msg );
    967        
    968         wrapped = word_wrap( msg, 425 );
    969         if( c && u )
    970         {
    971                 char *ts = NULL;
    972                 if( set_getbool( &ic->irc->set, "display_timestamps" ) )
    973                         ts = format_timestamp( ic->irc, sent_at );
    974                 irc_privmsg( ic->irc, u, "PRIVMSG", c->channel, ts ? : "", wrapped );
    975                 g_free( ts );
    976         }
    977         else
    978         {
    979                 imcb_log( ic, "Message from/to conversation %s@%p (unknown conv/user): %s", who, c, wrapped );
    980         }
    981         g_free( wrapped );
    982 }
    983 
    984 void imcb_chat_log( struct groupchat *c, char *format, ... )
    985 {
    986         irc_t *irc = c->ic->irc;
    987         va_list params;
    988         char *text;
    989         user_t *u;
    990        
    991         va_start( params, format );
    992         text = g_strdup_vprintf( format, params );
    993         va_end( params );
    994        
    995         u = user_find( irc, irc->mynick );
    996        
    997         irc_privmsg( irc, u, "PRIVMSG", c->channel, "System message: ", text );
    998        
    999         g_free( text );
    1000 }
    1001 
    1002 void imcb_chat_topic( struct groupchat *c, char *who, char *topic, time_t set_at )
    1003 {
    1004         struct im_connection *ic = c->ic;
    1005         user_t *u = NULL;
    1006        
    1007         if( who == NULL)
    1008                 u = user_find( ic->irc, ic->irc->mynick );
    1009         else if( g_strcasecmp( who, ic->acc->user ) == 0 )
    1010                 u = user_find( ic->irc, ic->irc->nick );
    1011         else
    1012                 u = user_findhandle( ic, who );
    1013        
    1014         if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) ||
    1015             ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )
    1016                 strip_html( topic );
    1017        
    1018         g_free( c->topic );
    1019         c->topic = g_strdup( topic );
    1020        
    1021         if( c->joined && u )
    1022                 irc_write( ic->irc, ":%s!%s@%s TOPIC %s :%s", u->nick, u->user, u->host, c->channel, topic );
    1023 }
    1024 
    1025 
    1026 /* buddy_chat.c */
    1027 
    1028 void imcb_chat_add_buddy( struct groupchat *b, const char *handle )
    1029 {
    1030         user_t *u = user_findhandle( b->ic, handle );
    1031         int me = 0;
    1032        
    1033         if( set_getbool( &b->ic->irc->set, "debug" ) )
    1034                 imcb_log( b->ic, "User %s added to conversation %p", handle, b );
    1035        
    1036         /* It might be yourself! */
    1037         if( b->ic->acc->prpl->handle_cmp( handle, b->ic->acc->user ) == 0 )
    1038         {
    1039                 u = user_find( b->ic->irc, b->ic->irc->nick );
    1040                 if( !b->joined )
    1041                         irc_join( b->ic->irc, u, b->channel );
    1042                 b->joined = me = 1;
    1043         }
    1044        
    1045         /* Most protocols allow people to join, even when they're not in
    1046            your contact list. Try to handle that here */
    1047         if( !u )
    1048         {
    1049                 imcb_add_buddy( b->ic, handle, NULL );
    1050                 u = user_findhandle( b->ic, handle );
    1051         }
    1052        
    1053         /* Add the handle to the room userlist, if it's not 'me' */
    1054         if( !me )
    1055         {
    1056                 if( b->joined )
    1057                         irc_join( b->ic->irc, u, b->channel );
    1058                 b->in_room = g_list_append( b->in_room, g_strdup( handle ) );
    1059         }
    1060 }
    1061 
    1062 /* This function is one BIG hack... :-( EREWRITE */
    1063 void imcb_chat_remove_buddy( struct groupchat *b, const char *handle, const char *reason )
    1064 {
    1065         user_t *u;
    1066         int me = 0;
    1067        
    1068         if( set_getbool( &b->ic->irc->set, "debug" ) )
    1069                 imcb_log( b->ic, "User %s removed from conversation %p (%s)", handle, b, reason ? reason : "" );
    1070        
    1071         /* It might be yourself! */
    1072         if( g_strcasecmp( handle, b->ic->acc->user ) == 0 )
    1073         {
    1074                 if( b->joined == 0 )
    1075                         return;
    1076                
    1077                 u = user_find( b->ic->irc, b->ic->irc->nick );
    1078                 b->joined = 0;
    1079                 me = 1;
    1080         }
    1081         else
    1082         {
    1083                 u = user_findhandle( b->ic, handle );
    1084         }
    1085        
    1086         if( me || ( remove_chat_buddy_silent( b, handle ) && b->joined && u ) )
    1087                 irc_part( b->ic->irc, u, b->channel );
    1088 }
    1089 
    1090 static int remove_chat_buddy_silent( struct groupchat *b, const char *handle )
    1091 {
    1092         GList *i;
    1093        
    1094         /* Find the handle in the room userlist and shoot it */
    1095         i = b->in_room;
    1096         while( i )
    1097         {
    1098                 if( g_strcasecmp( handle, i->data ) == 0 )
    1099                 {
    1100                         g_free( i->data );
    1101                         b->in_room = g_list_remove( b->in_room, i->data );
    1102                         return( 1 );
    1103                 }
    1104                
    1105                 i = i->next;
    1106         }
    1107        
    1108         return( 0 );
     519        query_add( (irc_t *) ic->bee->ui_data, ic, s,
     520                   imcb_ask_add_cb_yes, imcb_ask_add_cb_no, data );
     521}
     522
     523struct bee_user *imcb_buddy_by_handle( struct im_connection *ic, const char *handle )
     524{
     525        return bee_user_by_handle( ic->bee, ic, handle );
    1109526}
    1110527
    1111528
    1112529/* Misc. BitlBee stuff which shouldn't really be here */
    1113 
     530#if 0
    1114531char *set_eval_away_devoice( set_t *set, char *value )
    1115532{
     
    1124541        /* Horror.... */
    1125542       
    1126         if( st != set_getbool( &irc->set, "away_devoice" ) )
     543        if( st != set_getbool( &irc->b->set, "away_devoice" ) )
    1127544        {
    1128545                char list[80] = "";
     
    1166583        return value;
    1167584}
    1168 
    1169 char *set_eval_timezone( set_t *set, char *value )
    1170 {
    1171         char *s;
    1172        
    1173         if( strcmp( value, "local" ) == 0 ||
    1174             strcmp( value, "gmt" ) == 0 || strcmp( value, "utc" ) == 0 )
    1175                 return value;
    1176        
    1177         /* Otherwise: +/- at the beginning optional, then one or more numbers,
    1178            possibly followed by a colon and more numbers. Don't bother bound-
    1179            checking them since users are free to shoot themselves in the foot. */
    1180         s = value;
    1181         if( *s == '+' || *s == '-' )
    1182                 s ++;
    1183        
    1184         /* \d+ */
    1185         if( !isdigit( *s ) )
    1186                 return SET_INVALID;
    1187         while( *s && isdigit( *s ) ) s ++;
    1188        
    1189         /* EOS? */
    1190         if( *s == '\0' )
    1191                 return value;
    1192        
    1193         /* Otherwise, colon */
    1194         if( *s != ':' )
    1195                 return SET_INVALID;
    1196         s ++;
    1197        
    1198         /* \d+ */
    1199         if( !isdigit( *s ) )
    1200                 return SET_INVALID;
    1201         while( *s && isdigit( *s ) ) s ++;
    1202        
    1203         /* EOS */
    1204         return *s == '\0' ? value : SET_INVALID;
    1205 }
    1206 
    1207 static char *format_timestamp( irc_t *irc, time_t msg_ts )
    1208 {
    1209         time_t now_ts = time( NULL );
    1210         struct tm now, msg;
    1211         char *set;
    1212        
    1213         /* If the timestamp is <= 0 or less than a minute ago, discard it as
    1214            it doesn't seem to add to much useful info and/or might be noise. */
    1215         if( msg_ts <= 0 || msg_ts > now_ts - 60 )
    1216                 return NULL;
    1217        
    1218         set = set_getstr( &irc->set, "timezone" );
    1219         if( strcmp( set, "local" ) == 0 )
    1220         {
    1221                 localtime_r( &now_ts, &now );
    1222                 localtime_r( &msg_ts, &msg );
    1223         }
    1224         else
    1225         {
    1226                 int hr, min = 0, sign = 60;
    1227                
    1228                 if( set[0] == '-' )
    1229                 {
    1230                         sign *= -1;
    1231                         set ++;
    1232                 }
    1233                 else if( set[0] == '+' )
    1234                 {
    1235                         set ++;
    1236                 }
    1237                
    1238                 if( sscanf( set, "%d:%d", &hr, &min ) >= 1 )
    1239                 {
    1240                         msg_ts += sign * ( hr * 60 + min );
    1241                         now_ts += sign * ( hr * 60 + min );
    1242                 }
    1243                
    1244                 gmtime_r( &now_ts, &now );
    1245                 gmtime_r( &msg_ts, &msg );
    1246         }
    1247        
    1248         if( msg.tm_year == now.tm_year && msg.tm_yday == now.tm_yday )
    1249                 return g_strdup_printf( "\x02[\x02\x02\x02%02d:%02d:%02d\x02]\x02 ",
    1250                                         msg.tm_hour, msg.tm_min, msg.tm_sec );
    1251         else
    1252                 return g_strdup_printf( "\x02[\x02\x02\x02%04d-%02d-%02d "
    1253                                         "%02d:%02d:%02d\x02]\x02 ",
    1254                                         msg.tm_year + 1900, msg.tm_mon + 1, msg.tm_mday,
    1255                                         msg.tm_hour, msg.tm_min, msg.tm_sec );
    1256 }
     585#endif
    1257586
    1258587/* The plan is to not allow straight calls to prpl functions anymore, but do
    1259588   them all from some wrappers. We'll start to define some down here: */
    1260 
    1261 int imc_buddy_msg( struct im_connection *ic, char *handle, char *msg, int flags )
    1262 {
    1263         char *buf = NULL;
    1264         int st;
    1265        
    1266         if( ( ic->flags & OPT_DOES_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) )
    1267         {
    1268                 buf = escape_html( msg );
    1269                 msg = buf;
    1270         }
    1271        
    1272         st = ic->acc->prpl->buddy_msg( ic, handle, msg, flags );
    1273         g_free( buf );
    1274        
    1275         return st;
    1276 }
    1277589
    1278590int imc_chat_msg( struct groupchat *c, char *msg, int flags )
     
    1303615       
    1304616        away = set_getstr( &ic->acc->set, "away" ) ?
    1305              : set_getstr( &ic->irc->set, "away" );
     617             : set_getstr( &ic->bee->set, "away" );
    1306618        if( away && *away )
    1307619        {
     
    1314626                away = NULL;
    1315627                msg = set_getstr( &ic->acc->set, "status" ) ?
    1316                     : set_getstr( &ic->irc->set, "status" );
     628                    : set_getstr( &ic->bee->set, "status" );
    1317629        }
    1318630       
  • protocols/nogaim.h

    r3742fb6 r3429b58  
    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
     
    4545#include "proxy.h"
    4646#include "query.h"
     47#include "md5.h"
     48#include "ft.h"
    4749
    4850#define BUDDY_ALIAS_MAXLEN 388   /* because MSN names can be 387 characters */
     
    8587       
    8688        /* BitlBee */
    87         irc_t *irc;
    88        
    89         struct groupchat *groupchats;
     89        bee_t *bee;
     90       
     91        GSList *groupchats;
    9092};
    9193
     
    98100         * already, for example to avoid adding somebody two times. */
    99101        GList *in_room;
    100         GList *ignored;
    101        
    102         struct groupchat *next;
    103         char *channel;
     102        //GList *ignored;
     103       
     104        //struct groupchat *next;
    104105        /* The title variable contains the ID you gave when you created the
    105106         * chat using imcb_chat_new(). */
     
    112113         * structure for your protocol's needs. */
    113114        void *data;
     115        void *ui_data;
    114116};
    115117
     
    228230        void (* auth_allow)     (struct im_connection *, const char *who);
    229231        void (* auth_deny)      (struct im_connection *, const char *who);
     232
     233        /* Incoming transfer request */
     234        void (* transfer_request) (struct im_connection *, file_transfer_t *ft, char *handle );
    230235};
    231236
     
    281286G_MODULE_EXPORT void imcb_buddy_nick_hint( struct im_connection *ic, const char *handle, const char *nick );
    282287
    283 /* Buddy activity */
    284 /* To manipulate the status of a handle.
    285  * - flags can be |='d with OPT_* constants. You will need at least:
    286  *   OPT_LOGGED_IN and OPT_AWAY.
    287  * - 'state' and 'message' can be NULL */
    288 G_MODULE_EXPORT void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, const char *state, const char *message );
    289 /* Not implemented yet! */ G_MODULE_EXPORT void imcb_buddy_times( struct im_connection *ic, const char *handle, time_t login, time_t idle );
    290 /* Call when a handle says something. 'flags' and 'sent_at may be just 0. */
    291 G_MODULE_EXPORT void imcb_buddy_msg( struct im_connection *ic, const char *handle, char *msg, uint32_t flags, time_t sent_at );
    292288G_MODULE_EXPORT void imcb_buddy_typing( struct im_connection *ic, char *handle, uint32_t flags );
     289G_MODULE_EXPORT struct bee_user *imcb_buddy_by_handle( struct im_connection *ic, const char *handle );
    293290G_MODULE_EXPORT void imcb_clean_handle( struct im_connection *ic, char *handle );
    294291
     
    316313/* Actions, or whatever. */
    317314int imc_away_send_update( struct im_connection *ic );
    318 int imc_buddy_msg( struct im_connection *ic, char *handle, char *msg, int flags );
    319315int imc_chat_msg( struct groupchat *c, char *msg, int flags );
    320316
     
    325321
    326322/* Misc. stuff */
    327 char *set_eval_timezone( set_t *set, char *value );
    328323char *set_eval_away_devoice( set_t *set, char *value );
    329324gboolean auto_reconnect( gpointer data, gint fd, b_input_condition cond );
  • protocols/oscar/oscar.c

    r3742fb6 r3429b58  
    254254
    255255        u = t = g_strdup(s);
    256 
    257         strcpy(t, s);
    258256        g_strdown(t);
    259257
     
    651649        struct im_connection *ic = sess->aux_data;
    652650        struct chat_connection *chatcon;
     651        struct groupchat *c = NULL;
    653652        static int id = 1;
    654653
     
    663662        chatcon = find_oscar_chat_by_conn(ic, fr->conn);
    664663        chatcon->id = id;
    665         chatcon->cnv = imcb_chat_new(ic, chatcon->show);
     664       
     665        c = bee_chat_by_title(ic->bee, ic, chatcon->show);
     666        if (c && !c->data)
     667                chatcon->cnv = c;
     668        else
     669                chatcon->cnv = imcb_chat_new(ic, chatcon->show);
    666670        chatcon->cnv->data = chatcon;
    667671
     
    10541058        aim_ssi_auth_reply(od->sess, od->conn, uin, 1, "");
    10551059        // aim_send_im_ch4(od->sess, uin, AIM_ICQMSG_AUTHGRANTED, &message);
    1056         if(imcb_find_buddy(data->ic, uin) == NULL)
    1057                 imcb_ask_add(data->ic, uin, NULL);
     1060        imcb_ask_add(data->ic, uin, NULL);
    10581061       
    10591062        g_free(uin);
     
    18161819        struct oscar_data *odata = (struct oscar_data *)g->proto_data;
    18171820        if (odata->icq) {
     1821                /** FIXME(wilmer): Hmm, lost the ability to get away msgs here, do we care to get that back?
    18181822                struct buddy *budlight = imcb_find_buddy(g, who);
    18191823                if (budlight)
     
    18211825                                if (budlight->caps & AIM_CAPS_ICQSERVERRELAY)
    18221826                                        aim_send_im_ch2_geticqmessage(odata->sess, who, (budlight->uc & 0xff80) >> 7);
     1827                */
    18231828        } else
    18241829                aim_getinfo(odata->sess, odata->conn, who, AIM_GETINFO_AWAYMESSAGE);
     
    19471952static int gaim_ssi_parselist(aim_session_t *sess, aim_frame_t *fr, ...) {
    19481953        struct im_connection *ic = sess->aux_data;
    1949         struct aim_ssi_item *curitem;
     1954        struct aim_ssi_item *curitem, *curgroup;
    19501955        int tmp;
    19511956        char *nrm;
     
    19581963                switch (curitem->type) {
    19591964                        case 0x0000: /* Buddy */
    1960                                 if ((curitem->name) && (!imcb_find_buddy(ic, nrm))) {
     1965                                if ((curitem->name) && (!imcb_buddy_by_handle(ic, nrm))) {
    19611966                                        char *realname = NULL;
    19621967
    19631968                                        if (curitem->data && aim_gettlv(curitem->data, 0x0131, 1))
    19641969                                                    realname = aim_gettlv_str(curitem->data, 0x0131, 1);
    1965                                                
    1966                                         imcb_add_buddy(ic, nrm, NULL);
     1970                                       
     1971                                        imcb_add_buddy(ic, nrm, curgroup->gid == curitem->gid ? curgroup->name : NULL);
    19671972                                       
    19681973                                        if (realname) {
     
    19721977                                        }
    19731978                                }
     1979                                break;
     1980
     1981                        case 0x0001: /* Group */
     1982                                curgroup = curitem;
    19741983                                break;
    19751984
     
    25142523        static int chat_id = 0;
    25152524        char * chatname;
     2525        struct groupchat *c;
    25162526       
    25172527        chatname = g_strdup_printf("%s%s_%d", isdigit(*ic->acc->user) ? "icq_" : "",
    25182528                                   ic->acc->user, chat_id++);
    2519  
     2529       
     2530        c = imcb_chat_new(ic, chatname);
    25202531        ret = oscar_chat_join(ic, chatname, NULL, NULL);
    2521 
    25222532        aim_chat_invite(od->sess, od->conn, who, "", 4, chatname, 0x0);
    25232533
  • protocols/twitter/twitter_lib.c

    r3742fb6 r3429b58  
    103103
    104104        // Check if the buddy is allready in the buddy list.
    105         if (!imcb_find_buddy( ic, name ))
     105        if (!bee_user_by_handle( ic->bee, ic, name ))
    106106        {
    107107                char *mode = set_getstr(&ic->acc->set, "mode");
  • protocols/yahoo/yahoo.c

    r3742fb6 r3429b58  
    153153       
    154154        while( ic->groupchats )
    155                 imcb_chat_free( ic->groupchats );
     155                imcb_chat_free( ic->groupchats->data );
    156156       
    157157        for( l = yd->buddygroups; l; l = l->next )
     
    791791        struct byahoo_conf_invitation *inv = data;
    792792        struct groupchat *b;
    793        
    794         for( b = inv->ic->groupchats; b; b = b->next )
     793        GSList *l;
     794       
     795        for( l = inv->ic->groupchats; l; l = l->next )
     796        {
     797                b = l->data;
    795798                if( b == inv->c )
    796799                        break;
     800        }
    797801       
    798802        if( b != NULL )
     
    860864{
    861865        struct im_connection *ic = byahoo_get_ic_by_id( id );
    862         struct groupchat *c;
    863        
    864         for( c = ic->groupchats; c && strcmp( c->title, room ) != 0; c = c->next );
     866        struct groupchat *c = bee_chat_by_title( ic->bee, ic, room );
    865867       
    866868        if( c )
     
    872874{
    873875        struct im_connection *ic = byahoo_get_ic_by_id( id );
    874         struct groupchat *c;
    875        
    876         for( c = ic->groupchats; c && strcmp( c->title, room ) != 0; c = c->next );
     876        struct groupchat *c = bee_chat_by_title( ic->bee, ic, room );
    877877       
    878878        if( c )
     
    884884        struct im_connection *ic = byahoo_get_ic_by_id( id );
    885885        char *m = byahoo_strip( msg );
    886         struct groupchat *c;
    887        
    888         for( c = ic->groupchats; c && strcmp( c->title, room ) != 0; c = c->next );
     886        struct groupchat *c = bee_chat_by_title( ic->bee, ic, room );
    889887       
    890888        if( c )
  • query.c

    r3742fb6 r3429b58  
    6464        }
    6565       
    66         if( g_strcasecmp( set_getstr( &irc->set, "query_order" ), "lifo" ) == 0 || irc->queries == q )
     66        if( g_strcasecmp( set_getstr( &irc->b->set, "query_order" ), "lifo" ) == 0 || irc->queries == q )
    6767                query_display( irc, q );
    6868       
     
    179179        query_t *q;
    180180       
    181         if( g_strcasecmp( set_getstr( &irc->set, "query_order" ), "fifo" ) == 0 )
     181        if( g_strcasecmp( set_getstr( &irc->b->set, "query_order" ), "fifo" ) == 0 )
    182182                q = irc->queries;
    183183        else
  • root_commands.c

    r3742fb6 r3429b58  
    2626#define BITLBEE_CORE
    2727#include "commands.h"
    28 #include "crypting.h"
    2928#include "bitlbee.h"
    3029#include "help.h"
     
    3332#include <string.h>
    3433
    35 void root_command_string( irc_t *irc, user_t *u, char *command, int flags )
    36 {
    37         char *cmd[IRC_MAX_ARGS];
    38         char *s;
    39         int k;
    40         char q = 0;
    41        
    42         memset( cmd, 0, sizeof( cmd ) );
    43         cmd[0] = command;
    44         k = 1;
    45         for( s = command; *s && k < ( IRC_MAX_ARGS - 1 ); s ++ )
    46                 if( *s == ' ' && !q )
    47                 {
    48                         *s = 0;
    49                         while( *++s == ' ' );
    50                         if( *s == '"' || *s == '\'' )
    51                         {
    52                                 q = *s;
    53                                 s ++;
    54                         }
    55                         if( *s )
    56                         {
    57                                 cmd[k++] = s;
    58                                 s --;
    59                         }
    60                         else
    61                         {
    62                                 break;
    63                         }
    64                 }
    65                 else if( *s == '\\' && ( ( !q && s[1] ) || ( q && q == s[1] ) ) )
    66                 {
    67                         char *cpy;
    68                        
    69                         for( cpy = s; *cpy; cpy ++ )
    70                                 cpy[0] = cpy[1];
    71                 }
    72                 else if( *s == q )
    73                 {
    74                         q = *s = 0;
    75                 }
    76         cmd[k] = NULL;
    77        
    78         root_command( irc, cmd );
     34void root_command_string( irc_t *irc, char *command )
     35{
     36        root_command( irc, split_command_parts( command ) );
    7937}
    8038
     
    9351void root_command( irc_t *irc, char *cmd[] )
    9452{       
    95         int i;
     53        int i, len;
    9654       
    9755        if( !cmd[0] )
    9856                return;
    9957       
     58        len = strlen( cmd[0] );
    10059        for( i = 0; commands[i].command; i++ )
    101                 if( g_strcasecmp( commands[i].command, cmd[0] ) == 0 )
    102                 {
     60                if( g_strncasecmp( commands[i].command, cmd[0], len ) == 0 )
     61                {
     62                        if( commands[i+1].command &&
     63                            g_strncasecmp( commands[i+1].command, cmd[0], len ) == 0 )
     64                                /* Only match on the first letters if the match is unique. */
     65                                break;
     66                       
    10367                        MIN_ARGS( commands[i].required_parameters );
    10468                       
     
    162126                irc->status |= USTATUS_IDENTIFIED;
    163127                irc_umode_set( irc, "+R", 1 );
    164                 if( set_getbool( &irc->set, "auto_connect" ) )
     128                if( set_getbool( &irc->b->set, "auto_connect" ) )
    165129                        cmd_account( irc, account_on );
    166130                break;
     
    202166        storage_status_t status;
    203167       
    204         status = storage_remove (irc->nick, cmd[1]);
     168        status = storage_remove (irc->user->nick, cmd[1]);
    205169        switch (status) {
    206170        case STORAGE_NO_SUCH_USER:
     
    214178                irc->status &= ~USTATUS_IDENTIFIED;
    215179                irc_umode_set( irc, "-R", 1 );
    216                 irc_usermsg( irc, "Account `%s' removed", irc->nick );
     180                irc_usermsg( irc, "Account `%s' removed", irc->user->nick );
    217181                break;
    218182        default:
     
    222186}
    223187
    224 struct cmd_account_del_data
    225 {
    226         account_t *a;
    227         irc_t *irc;
    228 };
    229 
    230 void cmd_account_del_yes( void *data )
    231 {
    232         struct cmd_account_del_data *cad = data;
    233         account_t *a;
    234        
    235         for( a = cad->irc->accounts; a && a != cad->a; a = a->next );
    236        
    237         if( a == NULL )
    238         {
    239                 irc_usermsg( cad->irc, "Account already deleted" );
    240         }
    241         else if( a->ic )
    242         {
    243                 irc_usermsg( cad->irc, "Account is still logged in, can't delete" );
    244         }
    245         else
    246         {
    247                 account_del( cad->irc, a );
    248                 irc_usermsg( cad->irc, "Account deleted" );
    249         }
    250         g_free( data );
    251 }
    252 
    253 void cmd_account_del_no( void *data )
    254 {
    255         g_free( data );
     188static void cmd_save( irc_t *irc, char **cmd )
     189{
     190        if( ( irc->status & USTATUS_IDENTIFIED ) == 0 )
     191                irc_usermsg( irc, "Please create an account first" );
     192        else if( storage_save( irc, NULL, TRUE ) == STORAGE_OK )
     193                irc_usermsg( irc, "Configuration saved" );
     194        else
     195                irc_usermsg( irc, "Configuration could not be saved!" );
    256196}
    257197
     
    286226                set_name = set_full;
    287227               
    288                 head = &irc->set;
     228                head = &irc->b->set;
    289229        }
    290230        else
     
    357297        account_t *a;
    358298       
    359         if( ( a = account_get( irc, id ) ) )
     299        if( ( a = account_get( irc->b, id ) ) )
    360300                return &a->set;
    361301        else
     
    405345                }
    406346
    407                 a = account_add( irc, prpl, cmd[3], cmd[4] );
     347                a = account_add( irc->b, prpl, cmd[3], cmd[4] );
    408348                if( cmd[5] )
    409349                {
     
    419359                MIN_ARGS( 2 );
    420360
    421                 if( !( a = account_get( irc, cmd[2] ) ) )
     361                if( !( a = account_get( irc->b, cmd[2] ) ) )
    422362                {
    423363                        irc_usermsg( irc, "Invalid account" );
     
    429369                else
    430370                {
    431                         struct cmd_account_del_data *cad;
    432                         char *msg;
    433                        
    434                         cad = g_malloc( sizeof( struct cmd_account_del_data ) );
    435                         cad->a = a;
    436                         cad->irc = irc;
    437                        
    438                         msg = g_strdup_printf( "If you remove this account (%s(%s)), BitlBee will "
    439                                                "also forget all your saved nicknames. If you want "
    440                                                "to change your username/password, use the `account "
    441                                                "set' command. Are you sure you want to delete this "
    442                                                "account?", a->prpl->name, a->user );
    443                         query_add( irc, NULL, msg, cmd_account_del_yes, cmd_account_del_no, cad );
    444                         g_free( msg );
     371                        account_del( irc->b, a );
     372                        irc_usermsg( irc, "Account deleted" );
    445373                }
    446374        }
     
    452380                        irc_usermsg( irc, "Account list:" );
    453381               
    454                 for( a = irc->accounts; a; a = a->next )
     382                for( a = irc->b->accounts; a; a = a->next )
    455383                {
    456384                        char *con;
     
    475403                if( cmd[2] )
    476404                {
    477                         if( ( a = account_get( irc, cmd[2] ) ) )
     405                        if( ( a = account_get( irc->b, cmd[2] ) ) )
    478406                        {
    479407                                if( a->ic )
     
    484412                                else
    485413                                {
    486                                         account_on( irc, a );
     414                                        account_on( irc->b, a );
    487415                                }
    488416                        }
     
    495423                else
    496424                {
    497                         if ( irc->accounts ) {
     425                        if ( irc->b->accounts )
     426                        {
    498427                                irc_usermsg( irc, "Trying to get all accounts connected..." );
    499428                       
    500                                 for( a = irc->accounts; a; a = a->next )
     429                                for( a = irc->b->accounts; a; a = a->next )
    501430                                        if( !a->ic && a->auto_connect )
    502                                                 account_on( irc, a );
     431                                                account_on( irc->b, a );
    503432                        }
    504433                        else
     
    514443                        irc_usermsg( irc, "Deactivating all active (re)connections..." );
    515444                       
    516                         for( a = irc->accounts; a; a = a->next )
     445                        for( a = irc->b->accounts; a; a = a->next )
    517446                        {
    518447                                if( a->ic )
    519                                         account_off( irc, a );
     448                                        account_off( irc->b, a );
    520449                                else if( a->reconnect )
    521450                                        cancel_auto_reconnect( a );
    522451                        }
    523452                }
    524                 else if( ( a = account_get( irc, cmd[2] ) ) )
     453                else if( ( a = account_get( irc->b, cmd[2] ) ) )
    525454                {
    526455                        if( a->ic )
    527456                        {
    528                                 account_off( irc, a );
     457                                account_off( irc->b, a );
    529458                        }
    530459                        else if( a->reconnect )
     
    569498        }
    570499       
    571         if( !( a = account_get( irc, cmd[1] ) ) )
     500        if( !( a = account_get( irc->b, cmd[1] ) ) )
    572501        {
    573502                irc_usermsg( irc, "Invalid account" );
     
    587516                        return;
    588517                }
    589                 else if( user_find( irc, cmd[3] ) )
     518                else if( irc_user_by_name( irc, cmd[3] ) )
    590519                {
    591520                        irc_usermsg( irc, "The requested nick `%s' already exists", cmd[3] );
     
    601530                a->ic->acc->prpl->add_buddy( a->ic, cmd[2], NULL );
    602531        else
    603                 /* Yeah, officially this is a call-*back*... So if we just
    604                    called add_buddy, we'll wait for the IM server to respond
    605                    before we do this. */
    606                 imcb_add_buddy( a->ic, cmd[2], NULL );
     532                /* Only for add -tmp. For regular adds, this callback will
     533                   be called once the IM server confirms. */
     534                bee_user_new( irc->b, a->ic, cmd[2] );
    607535       
    608536        irc_usermsg( irc, "Adding `%s' to your contact list", cmd[2]  );
     537}
     538
     539static void cmd_remove( irc_t *irc, char **cmd )
     540{
     541        irc_user_t *iu;
     542        bee_user_t *bu;
     543        char *s;
     544       
     545        if( !( iu = irc_user_by_name( irc, cmd[1] ) ) || !( bu = iu->bu ) )
     546        {
     547                irc_usermsg( irc, "Buddy `%s' not found", cmd[1] );
     548                return;
     549        }
     550        s = g_strdup( bu->handle );
     551       
     552        bu->ic->acc->prpl->remove_buddy( bu->ic, bu->handle, NULL );
     553        nick_del( bu->ic->acc, bu->handle );
     554        //TODO(wilmer): bee_user_free() and/or let the IM mod do it? irc_user_free( irc, cmd[1] );
     555       
     556        irc_usermsg( irc, "Buddy `%s' (nick %s) removed from contact list", s, cmd[1] );
     557        g_free( s );
     558       
     559        return;
    609560}
    610561
     
    616567        if( !cmd[2] )
    617568        {
    618                 user_t *u = user_find( irc, cmd[1] );
    619                 if( !u || !u->ic )
     569                irc_user_t *iu = irc_user_by_name( irc, cmd[1] );
     570                if( !iu || !iu->bu )
    620571                {
    621572                        irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
    622573                        return;
    623574                }
    624                 ic = u->ic;
    625                 cmd[2] = u->handle;
    626         }
    627         else if( !( a = account_get( irc, cmd[1] ) ) )
     575                ic = iu->bu->ic;
     576                cmd[2] = iu->bu->handle;
     577        }
     578        else if( !( a = account_get( irc->b, cmd[1] ) ) )
    628579        {
    629580                irc_usermsg( irc, "Invalid account" );
     
    648599static void cmd_rename( irc_t *irc, char **cmd )
    649600{
    650         user_t *u;
    651        
    652         if( g_strcasecmp( cmd[1], irc->nick ) == 0 )
     601        irc_user_t *iu;
     602       
     603        iu = irc_user_by_name( irc, cmd[1] );
     604       
     605        if( iu == NULL )
     606        {
     607                irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
     608        }
     609        else if( iu == irc->user )
    653610        {
    654611                irc_usermsg( irc, "Nick `%s' can't be changed", cmd[1] );
    655612        }
    656         else if( g_strcasecmp( cmd[1], irc->channel ) == 0 )
    657         {
    658                 if( strchr( CTYPES, cmd[2][0] ) && nick_ok( cmd[2] + 1 ) )
    659                 {
    660                         u = user_find( irc, irc->nick );
    661                        
    662                         irc_part( irc, u, irc->channel );
    663                         g_free( irc->channel );
    664                         irc->channel = g_strdup( cmd[2] );
    665                         irc_join( irc, u, irc->channel );
    666                        
    667                         if( strcmp( cmd[0], "set_rename" ) != 0 )
    668                                 set_setstr( &irc->set, "control_channel", cmd[2] );
    669                 }
    670         }
    671         else if( user_find( irc, cmd[2] ) && ( nick_cmp( cmd[1], cmd[2] ) != 0 ) )
     613        else if( !nick_ok( cmd[2] ) )
     614        {
     615                irc_usermsg( irc, "Nick `%s' is invalid", cmd[2] );
     616        }
     617        else if( irc_user_by_name( irc, cmd[2] ) )
    672618        {
    673619                irc_usermsg( irc, "Nick `%s' already exists", cmd[2] );
    674620        }
    675         else if( !nick_ok( cmd[2] ) )
    676         {
    677                 irc_usermsg( irc, "Nick `%s' is invalid", cmd[2] );
    678         }
    679         else if( !( u = user_find( irc, cmd[1] ) ) )
    680         {
    681                 irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
    682         }
    683         else
    684         {
    685                 user_rename( irc, cmd[1], cmd[2] );
    686                 irc_write( irc, ":%s!%s@%s NICK %s", cmd[1], u->user, u->host, cmd[2] );
    687                 if( g_strcasecmp( cmd[1], irc->mynick ) == 0 )
    688                 {
    689                         g_free( irc->mynick );
    690                         irc->mynick = g_strdup( cmd[2] );
    691                        
     621        else
     622        {
     623                if( !irc_user_set_nick( iu, cmd[2] ) )
     624                {
     625                        irc_usermsg( irc, "Error while changing nick" );
     626                        return;
     627                }
     628               
     629                if( iu == irc->root )
     630                {
    692631                        /* If we're called internally (user did "set root_nick"),
    693632                           let's not go O(INF). :-) */
    694633                        if( strcmp( cmd[0], "set_rename" ) != 0 )
    695                                 set_setstr( &irc->set, "root_nick", cmd[2] );
    696                 }
    697                 else if( u->send_handler == buddy_send_handler )
    698                 {
    699                         nick_set( u->ic->acc, u->handle, cmd[2] );
     634                                set_setstr( &irc->b->set, "root_nick", cmd[2] );
     635                }
     636                else if( iu->bu )
     637                {
     638                        nick_set( iu->bu->ic->acc, iu->bu->handle, cmd[2] );
    700639                }
    701640               
     
    704643}
    705644
     645#if 0
    706646char *set_eval_root_nick( set_t *set, char *new_nick )
    707647{
     
    731671        return strcmp( irc->channel, new_name ) == 0 ? new_name : SET_INVALID;
    732672}
    733 
    734 static void cmd_remove( irc_t *irc, char **cmd )
    735 {
    736         user_t *u;
    737         char *s;
    738        
    739         if( !( u = user_find( irc, cmd[1] ) ) || !u->ic )
    740         {
    741                 irc_usermsg( irc, "Buddy `%s' not found", cmd[1] );
    742                 return;
    743         }
    744         s = g_strdup( u->handle );
    745        
    746         u->ic->acc->prpl->remove_buddy( u->ic, u->handle, NULL );
    747         nick_del( u->ic->acc, u->handle );
    748         user_del( irc, cmd[1] );
    749        
    750         irc_usermsg( irc, "Buddy `%s' (nick %s) removed from contact list", s, cmd[1] );
    751         g_free( s );
    752        
    753         return;
    754 }
     673#endif
    755674
    756675static void cmd_block( irc_t *irc, char **cmd )
     
    759678        account_t *a;
    760679       
    761         if( !cmd[2] && ( a = account_get( irc, cmd[1] ) ) && a->ic )
     680        if( !cmd[2] && ( a = account_get( irc->b, cmd[1] ) ) && a->ic )
    762681        {
    763682                char *format;
     
    772691                for( l = a->ic->deny; l; l = l->next )
    773692                {
    774                         user_t *u = user_findhandle( a->ic, l->data );
    775                         irc_usermsg( irc, format, l->data, u ? u->nick : "(none)" );
     693                        bee_user_t *bu = bee_user_by_handle( irc->b, a->ic, l->data );
     694                        irc_user_t *iu = bu ? bu->ui_data : NULL;
     695                        irc_usermsg( irc, format, l->data, iu ? iu->nick : "(none)" );
    776696                }
    777697                irc_usermsg( irc, "End of list." );
     
    781701        else if( !cmd[2] )
    782702        {
    783                 user_t *u = user_find( irc, cmd[1] );
    784                 if( !u || !u->ic )
     703                irc_user_t *iu = irc_user_by_name( irc, cmd[1] );
     704                if( !iu || !iu->bu )
    785705                {
    786706                        irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
    787707                        return;
    788708                }
    789                 ic = u->ic;
    790                 cmd[2] = u->handle;
    791         }
    792         else if( !( a = account_get( irc, cmd[1] ) ) )
     709                ic = iu->bu->ic;
     710                cmd[2] = iu->bu->handle;
     711        }
     712        else if( !( a = account_get( irc->b, cmd[1] ) ) )
    793713        {
    794714                irc_usermsg( irc, "Invalid account" );
     
    818738        account_t *a;
    819739       
    820         if( !cmd[2] && ( a = account_get( irc, cmd[1] ) ) && a->ic )
     740        if( !cmd[2] && ( a = account_get( irc->b, cmd[1] ) ) && a->ic )
    821741        {
    822742                char *format;
     
    831751                for( l = a->ic->permit; l; l = l->next )
    832752                {
    833                         user_t *u = user_findhandle( a->ic, l->data );
    834                         irc_usermsg( irc, format, l->data, u ? u->nick : "(none)" );
     753                        bee_user_t *bu = bee_user_by_handle( irc->b, a->ic, l->data );
     754                        irc_user_t *iu = bu ? bu->ui_data : NULL;
     755                        irc_usermsg( irc, format, l->data, iu ? iu->nick : "(none)" );
    835756                }
    836757                irc_usermsg( irc, "End of list." );
     
    840761        else if( !cmd[2] )
    841762        {
    842                 user_t *u = user_find( irc, cmd[1] );
    843                 if( !u || !u->ic )
     763                irc_user_t *iu = irc_user_by_name( irc, cmd[1] );
     764                if( !iu || !iu->bu )
    844765                {
    845766                        irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
    846767                        return;
    847768                }
    848                 ic = u->ic;
    849                 cmd[2] = u->handle;
    850         }
    851         else if( !( a = account_get( irc, cmd[1] ) ) )
     769                ic = iu->bu->ic;
     770                cmd[2] = iu->bu->handle;
     771        }
     772        else if( !( a = account_get( irc->b, cmd[1] ) ) )
    852773        {
    853774                irc_usermsg( irc, "Invalid account" );
     
    916837}
    917838
    918 static void cmd_save( irc_t *irc, char **cmd )
    919 {
    920         if( ( irc->status & USTATUS_IDENTIFIED ) == 0 )
    921                 irc_usermsg( irc, "Please create an account first" );
    922         else if( storage_save( irc, NULL, TRUE ) == STORAGE_OK )
    923                 irc_usermsg( irc, "Configuration saved" );
    924         else
    925                 irc_usermsg( irc, "Configuration could not be saved!" );
    926 }
    927 
    928839static void cmd_blist( irc_t *irc, char **cmd )
    929840{
    930841        int online = 0, away = 0, offline = 0;
    931         user_t *u;
     842        GSList *l;
    932843        char s[256];
    933844        char *format;
     
    950861                format = "%-16.16s  %-40.40s  %s";
    951862       
    952         irc_usermsg( irc, format, "Nick", "User/Host/Network", "Status" );
    953        
    954         for( u = irc->users; u; u = u->next ) if( u->ic && u->online && !u->away )
    955         {
     863        irc_usermsg( irc, format, "Nick", "Handle/Account", "Status" );
     864       
     865        for( l = irc->users; l; l = l->next )
     866        {
     867                irc_user_t *iu = l->data;
     868                bee_user_t *bu = iu->bu;
     869               
     870                if( !bu || ( bu->flags & ( BEE_USER_ONLINE | BEE_USER_AWAY ) ) != BEE_USER_ONLINE )
     871                        continue;
     872               
    956873                if( online == 1 )
    957874                {
    958875                        char st[256] = "Online";
    959876                       
    960                         if( u->status_msg )
    961                                 g_snprintf( st, sizeof( st ) - 1, "Online (%s)", u->status_msg );
     877                        if( bu->status_msg )
     878                                g_snprintf( st, sizeof( st ) - 1, "Online (%s)", bu->status_msg );
    962879                       
    963                         g_snprintf( s, sizeof( s ) - 1, "%s@%s %s(%s)", u->user, u->host, u->ic->acc->prpl->name, u->ic->acc->user );
    964                         irc_usermsg( irc, format, u->nick, s, st );
     880                        g_snprintf( s, sizeof( s ) - 1, "%s %s(%s)", bu->handle, bu->ic->acc->prpl->name, bu->ic->acc->user );
     881                        irc_usermsg( irc, format, iu->nick, s, st );
    965882                }
    966883               
     
    968885        }
    969886
    970         for( u = irc->users; u; u = u->next ) if( u->ic && u->online && u->away )
    971         {
     887        for( l = irc->users; l; l = l->next )
     888        {
     889                irc_user_t *iu = l->data;
     890                bee_user_t *bu = iu->bu;
     891               
     892                if( !bu || !( bu->flags & BEE_USER_ONLINE ) || !( bu->flags & BEE_USER_AWAY ) )
     893                        continue;
     894               
    972895                if( away == 1 )
    973896                {
    974                         g_snprintf( s, sizeof( s ) - 1, "%s@%s %s(%s)", u->user, u->host, u->ic->acc->prpl->name, u->ic->acc->user );
    975                         irc_usermsg( irc, format, u->nick, s, u->away );
     897                        g_snprintf( s, sizeof( s ) - 1, "%s %s(%s)", bu->handle, bu->ic->acc->prpl->name, bu->ic->acc->user );
     898                        irc_usermsg( irc, format, iu->nick, s, irc_user_get_away( iu ) );
    976899                }
    977900                n_away ++;
    978901        }
    979902       
    980         for( u = irc->users; u; u = u->next ) if( u->ic && !u->online )
    981         {
     903        for( l = irc->users; l; l = l->next )
     904        {
     905                irc_user_t *iu = l->data;
     906                bee_user_t *bu = iu->bu;
     907               
     908                if( !bu || bu->flags & BEE_USER_ONLINE )
     909                        continue;
     910               
    982911                if( offline == 1 )
    983912                {
    984                         g_snprintf( s, sizeof( s ) - 1, "%s@%s %s(%s)", u->user, u->host, u->ic->acc->prpl->name, u->ic->acc->user );
    985                         irc_usermsg( irc, format, u->nick, s, "Offline" );
     913                        g_snprintf( s, sizeof( s ) - 1, "%s %s(%s)", bu->handle, bu->ic->acc->prpl->name, bu->ic->acc->user );
     914                        irc_usermsg( irc, format, iu->nick, s, "Offline" );
    986915                }
    987916                n_offline ++;
     
    989918       
    990919        irc_usermsg( irc, "%d buddies (%d available, %d away, %d offline)", n_online + n_away + n_offline, n_online, n_away, n_offline );
    991 }
    992 
    993 static void cmd_nick( irc_t *irc, char **cmd )
    994 {
    995         account_t *a;
    996 
    997         if( !cmd[1] || !( a = account_get( irc, cmd[1] ) ) )
    998         {
    999                 irc_usermsg( irc, "Invalid account");
    1000         }
    1001         else if( !( a->ic && ( a->ic->flags & OPT_LOGGED_IN ) ) )
    1002         {
    1003                 irc_usermsg( irc, "That account is not on-line" );
    1004         }
    1005         else if ( !cmd[2] )
    1006         {
    1007                 irc_usermsg( irc, "Your name is `%s'" , a->ic->displayname ? a->ic->displayname : "NULL" );
    1008         }
    1009         else if ( !a->prpl->set_my_name )
    1010         {
    1011                 irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] );
    1012         }
    1013         else
    1014         {
    1015                 irc_usermsg( irc, "Setting your name to `%s'", cmd[2] );
    1016                
    1017                 a->prpl->set_my_name( a->ic, cmd[2] );
    1018         }
    1019920}
    1020921
     
    1039940}
    1040941
    1041 static void cmd_join_chat( irc_t *irc, char **cmd )
    1042 {
    1043         irc_usermsg( irc, "This command is now obsolete. "
    1044                           "Please try the `chat' command instead." );
    1045 }
    1046 
     942#if 0
    1047943static set_t **cmd_chat_set_findhead( irc_t *irc, char *id )
    1048944{
     
    11561052        }
    11571053}
    1158 
     1054#endif
     1055
     1056static void cmd_transfer( irc_t *irc, char **cmd )
     1057{
     1058        GSList *files = irc->file_transfers;
     1059        enum { LIST, REJECT, CANCEL };
     1060        int subcmd = LIST;
     1061        int fid;
     1062
     1063        if( !files )
     1064        {
     1065                irc_usermsg( irc, "No pending transfers" );
     1066                return;
     1067        }
     1068
     1069        if( cmd[1] && ( strcmp( cmd[1], "reject" ) == 0 ) )
     1070        {
     1071                subcmd = REJECT;
     1072        }
     1073        else if( cmd[1] && ( strcmp( cmd[1], "cancel" ) == 0 ) &&
     1074                 cmd[2] && ( sscanf( cmd[2], "%d", &fid ) == 1 ) )
     1075        {
     1076                subcmd = CANCEL;
     1077        }
     1078
     1079        for( ; files; files = g_slist_next( files ) )
     1080        {
     1081                file_transfer_t *file = files->data;
     1082               
     1083                switch( subcmd ) {
     1084                case LIST:
     1085                        if ( file->status == FT_STATUS_LISTENING )
     1086                                irc_usermsg( irc,
     1087                                        "Pending file(id %d): %s (Listening...)", file->local_id, file->file_name);
     1088                        else
     1089                        {
     1090                                int kb_per_s = 0;
     1091                                time_t diff = time( NULL ) - file->started ? : 1;
     1092                                if ( ( file->started > 0 ) && ( file->bytes_transferred > 0 ) )
     1093                                        kb_per_s = file->bytes_transferred / 1024 / diff;
     1094                                       
     1095                                irc_usermsg( irc,
     1096                                        "Pending file(id %d): %s (%10zd/%zd kb, %d kb/s)", file->local_id, file->file_name,
     1097                                        file->bytes_transferred/1024, file->file_size/1024, kb_per_s);
     1098                        }
     1099                        break;
     1100                case REJECT:
     1101                        if( file->status == FT_STATUS_LISTENING )
     1102                        {
     1103                                irc_usermsg( irc, "Rejecting file transfer for %s", file->file_name );
     1104                                imcb_file_canceled( file->ic, file, "Denied by user" );
     1105                        }
     1106                        break;
     1107                case CANCEL:
     1108                        if( file->local_id == fid )
     1109                        {
     1110                                irc_usermsg( irc, "Canceling file transfer for %s", file->file_name );
     1111                                imcb_file_canceled( file->ic, file, "Canceled by user" );
     1112                        }
     1113                        break;
     1114                }
     1115        }
     1116}
     1117
     1118/* IMPORTANT: Keep this list sorted! The short command logic needs that. */
    11591119const command_t commands[] = {
     1120        { "account",        1, cmd_account,        0 },
     1121        { "add",            2, cmd_add,            0 },
     1122        { "allow",          1, cmd_allow,          0 },
     1123        { "blist",          0, cmd_blist,          0 },
     1124        { "block",          1, cmd_block,          0 },
     1125        { "drop",           1, cmd_drop,           0 },
     1126        { "ft",             0, cmd_transfer,       0 },
    11601127        { "help",           0, cmd_help,           0 },
    11611128        { "identify",       1, cmd_identify,       0 },
     1129        { "info",           1, cmd_info,           0 },
     1130        { "no",             0, cmd_yesno,          0 },
     1131        { "qlist",          0, cmd_qlist,          0 },
    11621132        { "register",       1, cmd_register,       0 },
    1163         { "drop",           1, cmd_drop,           0 },
    1164         { "account",        1, cmd_account,        0 },
    1165         { "add",            2, cmd_add,            0 },
    1166         { "info",           1, cmd_info,           0 },
     1133        { "remove",         1, cmd_remove,         0 },
    11671134        { "rename",         2, cmd_rename,         0 },
    1168         { "remove",         1, cmd_remove,         0 },
    1169         { "block",          1, cmd_block,          0 },
    1170         { "allow",          1, cmd_allow,          0 },
    11711135        { "save",           0, cmd_save,           0 },
    11721136        { "set",            0, cmd_set,            0 },
     1137        { "transfer",       0, cmd_transfer,       0 },
    11731138        { "yes",            0, cmd_yesno,          0 },
    1174         { "no",             0, cmd_yesno,          0 },
    1175         { "blist",          0, cmd_blist,          0 },
    1176         { "nick",           1, cmd_nick,           0 },
    1177         { "qlist",          0, cmd_qlist,          0 },
    1178         { "join_chat",      2, cmd_join_chat,      0 },
     1139#if 0
    11791140        { "chat",           1, cmd_chat,           0 },
     1141#endif
    11801142        { NULL }
    11811143};
  • set.c

    r3742fb6 r3429b58  
    225225}
    226226
     227/*
    227228char *set_eval_ops( set_t *set, char *value )
    228229{
     
    246247        return value;
    247248}
     249*/
  • storage.c

    r3742fb6 r3429b58  
    2828#define BITLBEE_CORE
    2929#include "bitlbee.h"
    30 #include "crypting.h"
    3130
    3231extern storage_t storage_text;
     
    6665        storage_t *storage;
    6766       
    68         register_storage_backend(&storage_text);
    6967        register_storage_backend(&storage_xml);
    7068       
  • storage_xml.c

    r3742fb6 r3429b58  
    147147                                         arc_decode( pass_cr, pass_len, &password, xd->given_pass ) )
    148148                {
    149                         xd->current_account = account_add( irc, prpl, handle, password );
     149                        xd->current_account = account_add( irc->b, prpl, handle, password );
    150150                        if( server )
    151151                                set_setstr( &xd->current_account->set, "server", server );
     
    181181                                xd->current_set_head = &xd->current_account->set;
    182182                        else
    183                                 xd->current_set_head = &xd->irc->set;
     183                                xd->current_set_head = &xd->irc->b->set;
    184184                       
    185185                        xd->current_setting = g_strdup( setting );
     
    215215                if( xd->current_account && handle && channel )
    216216                {
    217                         xd->current_chat = chat_add( xd->irc, xd->current_account, handle, channel );
     217                        //xd->current_chat = chat_add( xd->irc, xd->current_account, handle, channel );
    218218                }
    219219                else
     
    353353static storage_status_t xml_load( irc_t *irc, const char *password )
    354354{
    355         return xml_load_real( irc, irc->nick, password, XML_PASS_UNKNOWN );
     355        return xml_load_real( irc, irc->user->nick, password, XML_PASS_UNKNOWN );
    356356}
    357357
     
    396396        md5_state_t md5_state;
    397397       
    398         path2 = g_strdup( irc->nick );
     398        path2 = g_strdup( irc->user->nick );
    399399        nick_lc( path2 );
    400400        g_snprintf( path, sizeof( path ) - 2, "%s%s%s", global.conf->configdir, path2, ".xml" );
     
    422422        pass_buf = base64_encode( pass_md5, 21 );
    423423       
    424         if( !xml_printf( fd, 0, "<user nick=\"%s\" password=\"%s\" version=\"%d\">\n", irc->nick, pass_buf, XML_FORMAT_VERSION ) )
     424        if( !xml_printf( fd, 0, "<user nick=\"%s\" password=\"%s\" version=\"%d\">\n", irc->user->nick, pass_buf, XML_FORMAT_VERSION ) )
    425425                goto write_error;
    426426       
    427427        g_free( pass_buf );
    428428       
    429         for( set = irc->set; set; set = set->next )
     429        for( set = irc->b->set; set; set = set->next )
    430430                if( set->value )
    431431                        if( !xml_printf( fd, 1, "<setting name=\"%s\">%s</setting>\n", set->key, set->value ) )
    432432                                goto write_error;
    433433       
    434         for( acc = irc->accounts; acc; acc = acc->next )
     434        for( acc = irc->b->accounts; acc; acc = acc->next )
    435435        {
    436436                unsigned char *pass_cr;
     
    470470                        goto write_error;
    471471               
     472#if 0
    472473                for( c = irc->chatrooms; c; c = c->next )
    473474                {
     
    488489                                goto write_error;
    489490                }
     491#endif
    490492               
    491493                if( !xml_printf( fd, 1, "</account>\n" ) )
  • win32.c

    r3742fb6 r3429b58  
    2727#include "bitlbee.h"
    2828#include "commands.h"
    29 #include "crypting.h"
    3029#include "protocols/nogaim.h"
    3130#include "help.h"
Note: See TracChangeset for help on using the changeset viewer.