Changes in / [f924563:6824fb3]


Ignore:
Files:
9 added
22 deleted
34 edited

Legend:

Unmodified
Added
Removed
  • Makefile

    rf924563 r6824fb3  
    1010
    1111# Program variables
    12 #objects = chat.o
    13 objects = 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)
    14 headers = 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
     12objects = account.o bitlbee.o chat.o crypting.o help.o ipc.o irc.o irc_commands.o nick.o query.o root_commands.o set.o storage.o $(STORAGE_OBJS) user.o
     13headers = 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
    1514subdirs = lib protocols
    1615
  • bitlbee.h

    rf924563 r6824fb3  
    126126#define CONF_FILE_DEF ETCDIR "bitlbee.conf"
    127127
    128 #include "bee.h"
    129128#include "irc.h"
    130129#include "storage.h"
     
    161160gboolean bitlbee_io_current_client_write( gpointer data, gint source, b_input_condition cond );
    162161
    163 void root_command_string( irc_t *irc, char *command );
     162void root_command_string( irc_t *irc, user_t *u, char *command, int flags );
    164163void root_command( irc_t *irc, char *command[] );
    165164gboolean bitlbee_shutdown( gpointer data, gint fd, b_input_condition cond );
  • conf.c

    rf924563 r6824fb3  
    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;
    6865        conf->protocols = NULL;
    6966        proxytype = 0;
     
    318315                                conf->user = g_strdup( ini->value );
    319316                        }
    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                         }
    344317                        else if( g_strcasecmp( ini->key, "protocols" ) == 0 )
    345318                        {
     
    376349                if( g_strcasecmp( ini->section, "defaults" ) == 0 )
    377350                {
    378                         set_t *s = set_find( &irc->b->set, ini->key );
     351                        set_t *s = set_find( &irc->set, ini->key );
    379352                       
    380353                        if( s )
  • conf.h

    rf924563 r6824fb3  
    5050        int ping_timeout;
    5151        char *user;
    52         size_t ft_max_size;
    53         int ft_max_kbps;
    54         char *ft_listen;
    5552        char **protocols;
    5653} conf_t;
  • configure

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

    rf924563 r6824fb3  
    11531153
    11541154        </bitlbee-command>
    1155        
    1156         <bitlbee-command name="transfers">
    1157                 <short-description>Monitor, cancel, or reject file transfers</short-description>
    1158                 <syntax>transfers [&lt;cancel&gt; id | &lt;reject&gt;]</syntax>
    1159                
    1160                 <description>
    1161                         <para>
    1162                                 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.
    1163                         </para>
    1164 
    1165                         <ircexample>
    1166                                 <ircline nick="ulim">transfers</ircline>
    1167                         </ircexample>
    1168                 </description>
    1169                
    1170                 <bitlbee-command name="cancel">
    1171                         <short-description>Cancels the file transfer with the given id</short-description>
    1172                         <syntax>transfers &lt;cancel&gt; id</syntax>
    1173 
    1174                         <description>
    1175                                 <para>Cancels the file transfer with the given id</para>
    1176                         </description>
    1177 
    1178                         <ircexample>
    1179                                 <ircline nick="ulim">transfers cancel 1</ircline>
    1180                                 <ircline nick="root">Canceling file transfer for test</ircline>
    1181                         </ircexample>
    1182                 </bitlbee-command>
    1183 
    1184                 <bitlbee-command name="reject">
    1185                         <short-description>Rejects all incoming transfers</short-description>
    1186                         <syntax>transfers &lt;reject&gt;</syntax>
    1187 
    1188                         <description>
    1189                                 <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>
    1190                         </description>
    1191 
    1192                         <ircexample>
    1193                                 <ircline nick="ulim">transfers reject</ircline>
    1194                         </ircexample>
    1195                 </bitlbee-command>
    1196         </bitlbee-command>
    1197        
    11981155</chapter>
  • ipc.c

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

    rf924563 r6824fb3  
    55  \********************************************************************/
    66
    7 /* The IRC-based UI (for now the only one)                              */
     7/* The big hairy IRCd part of the project                               */
    88
    99/*
     
    2424*/
    2525
     26#define BITLBEE_CORE
    2627#include "bitlbee.h"
     28#include "sock.h"
     29#include "crypting.h"
    2730#include "ipc.h"
    2831
    29 GSList *irc_connection_list;
    30 
    31 static gboolean irc_userping( gpointer _irc, gint fd, b_input_condition cond );
    32 static char *set_eval_charset( set_t *set, char *value );
     32static gboolean irc_userping( gpointer _irc, int fd, b_input_condition cond );
     33
     34GSList *irc_connection_list = NULL;
     35
     36static 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
     51static 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
     96static 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}
    33114
    34115irc_t *irc_new( int fd )
     
    37118        struct sockaddr_storage sock;
    38119        socklen_t socklen = sizeof( sock );
    39         char *host = NULL, *myhost = NULL;
    40         irc_user_t *iu;
    41120        set_t *s;
    42         bee_t *b;
    43121       
    44122        irc = g_new0( irc_t, 1 );
     
    52130        irc->last_pong = gettime();
    53131       
    54         irc->nick_user_hash = g_hash_table_new( g_str_hash, g_str_equal );
     132        irc->userhash = g_hash_table_new( g_str_hash, g_str_equal );
    55133        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 );
    56138       
    57139        irc->iconv = (GIConv) -1;
     
    60142        if( global.conf->hostname )
    61143        {
    62                 myhost = g_strdup( global.conf->hostname );
     144                irc->myhost = g_strdup( global.conf->hostname );
    63145        }
    64146        else if( getsockname( irc->fd, (struct sockaddr*) &sock, &socklen ) == 0 )
     
    69151                                 NI_MAXHOST, NULL, 0, 0 ) == 0 )
    70152                {
    71                         myhost = g_strdup( ipv6_unwrap( buf ) );
     153                        irc->myhost = g_strdup( ipv6_unwrap( buf ) );
    72154                }
    73155        }
     
    80162                                 NI_MAXHOST, NULL, 0, 0 ) == 0 )
    81163                {
    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" );
     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" );
    90172       
    91173        if( global.conf->ping_interval > 0 && global.conf->ping_timeout > 0 )
    92174                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" );
    93177
    94178        irc_connection_list = g_slist_append( irc_connection_list, irc );
    95179       
    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 );
     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 );
    131211       
    132212        conf_loaddefaults( irc );
    133213       
    134214        /* Evaluator sets the iconv/oconv structures. */
    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;
     215        set_eval_charset( set_find( &irc->set, "charset" ), set_getstr( &irc->set, "charset" ) );
     216       
     217        return( irc );
    143218}
    144219
     
    161236               
    162237                ipc_to_master_str( "OPERMSG :Client exiting: %s@%s [%s]\r\n",
    163                                    irc->user->nick ? irc->user->nick : "(NONE)", irc->root->host, reason );
     238                                   irc->nick ? irc->nick : "(NONE)", irc->host, reason );
    164239               
    165240                g_free( reason );
     
    171246               
    172247                ipc_to_master_str( "OPERMSG :Client exiting: %s@%s [%s]\r\n",
    173                                    irc->user->nick ? irc->user->nick : "(NONE)", irc->root->host, "No reason given" );
     248                                   irc->nick ? irc->nick : "(NONE)", irc->host, "No reason given" );
    174249        }
    175250       
     
    192267}
    193268
    194 static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data );
    195 
     269static 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 */
    196277void irc_free( irc_t * irc )
    197278{
     279        user_t *user, *usertmp;
     280       
    198281        log_message( LOGLVL_INFO, "Destroying connection with fd %d", irc->fd );
    199282       
    200         if( irc->status & USTATUS_IDENTIFIED && set_getbool( &irc->b->set, "save_on_quit" ) )
     283        if( irc->status & USTATUS_IDENTIFIED && set_getbool( &irc->set, "save_on_quit" ) )
    201284                if( storage_save( irc, NULL, TRUE ) != STORAGE_OK )
    202                         log_message( LOGLVL_WARNING, "Error while saving settings for user %s", irc->user->nick );
     285                        irc_usermsg( irc, "Error while saving settings!" );
    203286       
    204287        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        }
    205303       
    206304        while( irc->queries != NULL )
    207305                query_del( irc, irc->queries );
    208306       
    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 );
     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        }
    219328       
    220329        if( irc->ping_source_id > 0 )
     
    228337        irc->fd = -1;
    229338       
    230         g_hash_table_foreach_remove( irc->nick_user_hash, irc_free_hashkey, NULL );
    231         g_hash_table_destroy( irc->nick_user_hash );
     339        g_hash_table_foreach_remove( irc->userhash, irc_free_hashkey, NULL );
     340        g_hash_table_destroy( irc->userhash );
    232341       
    233342        g_hash_table_foreach_remove( irc->watches, irc_free_hashkey, NULL );
     
    241350        g_free( irc->sendbuffer );
    242351        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 );
    243357        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 );
    244365       
    245366        g_free( irc );
     
    253374}
    254375
    255 static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data )
    256 {
    257         g_free( key );
    258        
    259         return( TRUE );
    260 }
    261 
    262376/* USE WITH CAUTION!
    263377   Sets pass without checking */
    264 void irc_setpass (irc_t *irc, const char *pass)
     378void irc_setpass (irc_t *irc, const char *pass) 
    265379{
    266380        g_free (irc->password);
     
    273387}
    274388
    275 static char **irc_splitlines( char *buffer );
    276 
    277389void irc_process( irc_t *irc )
    278390{
     
    282394        if( irc->readbuffer != NULL )
    283395        {
    284                 lines = irc_splitlines( irc->readbuffer );
     396                lines = irc_tokenize( irc->readbuffer );
    285397               
    286398                for( i = 0; *lines[i] != '\0'; i ++ )
     
    319431                                                                  "`help set charset' for more information. Your "
    320432                                                                  "message was ignored.",
    321                                                                   set_getstr( &irc->b->set, "charset" ) );
     433                                                                  set_getstr( &irc->set, "charset" ) );
    322434                                               
    323435                                                g_free( conv );
     
    326438                                        else
    327439                                        {
    328                                                 irc_write( irc, ":%s NOTICE AUTH :%s", irc->root->host,
     440                                                irc_write( irc, ":%s NOTICE AUTH :%s", irc->myhost,
    329441                                                           "Warning: invalid characters received at login time." );
    330442                                               
     
    364476}
    365477
    366 /* Splits a long string into separate lines. The array is NULL-terminated
    367    and, unless the string contains an incomplete line at the end, ends with
    368    an empty string. Could use g_strsplit() but this one does it in-place.
    369    (So yes, it's destructive.) */
    370 static char **irc_splitlines( char *buffer )
     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. */
     480char **irc_tokenize( char *buffer )
    371481{
    372482        int i, j, n = 3;
     
    499609}
    500610
     611void 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
     624int 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
    501641void irc_write( irc_t *irc, char *format, ... )
    502642{
     
    509649        return;
    510650}
    511 
    512 void irc_write_all( int now, char *format, ... )
    513 {
    514         va_list params;
    515         GSList *temp;   
    516        
    517         va_start( params, format );
    518        
    519         temp = irc_connection_list;
    520         while( temp != NULL )
    521         {
    522                 irc_t *irc = temp->data;
    523                
    524                 if( now )
    525                 {
    526                         g_free( irc->sendbuffer );
    527                         irc->sendbuffer = g_strdup( "\r\n" );
    528                 }
    529                 irc_vawrite( temp->data, format, params );
    530                 if( now )
    531                 {
    532                         bitlbee_io_current_client_write( irc, irc->fd, GAIM_INPUT_WRITE );
    533                 }
    534                 temp = temp->next;
    535         }
    536        
    537         va_end( params );
    538         return;
    539 }
    540651
    541652void irc_vawrite( irc_t *irc, char *format, va_list params )
     
    594705}
    595706
     707void 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
     736void 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 )
     751                        {
     752                                irc_reply( irc, 353, "= %s :%s", channel, namelist );
     753                                *namelist = 0;
     754                        }
     755                       
     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
    596794int irc_check_login( irc_t *irc )
    597795{
    598         if( irc->user->user && irc->user->nick )
     796        if( irc->user && irc->nick )
    599797        {
    600798                if( global.conf->authmode == AUTHMODE_CLOSED && !( irc->status & USTATUS_AUTHORIZED ) )
    601799                {
    602                         irc_send_num( irc, 464, ":This server is password-protected." );
     800                        irc_reply( irc, 464, ":This server is password-protected." );
    603801                        return 0;
    604802                }
    605803                else
    606804                {
    607                         irc_channel_t *ic;
    608                         irc_user_t *iu = irc->user;
    609                        
    610                         irc->user = irc_user_new( irc, iu->nick );
    611                         irc->user->user = iu->user;
    612                         irc->user->host = iu->host;
    613                         irc->user->fullname = iu->fullname;
    614                         irc->user->f = &irc_user_self_funcs;
    615                         g_free( iu->nick );
    616                         g_free( iu );
    617                        
    618                         if( global.conf->runmode == RUNMODE_FORKDAEMON || global.conf->runmode == RUNMODE_DAEMON )
    619                                 ipc_to_master_str( "CLIENT %s %s :%s\r\n", irc->user->host, irc->user->nick, irc->user->fullname );
    620                        
    621                         irc->status |= USTATUS_LOGGED_IN;
    622                        
    623                         /* This is for bug #209 (use PASS to identify to NickServ). */
    624                         if( irc->password != NULL )
    625                         {
    626                                 char *send_cmd[] = { "identify", g_strdup( irc->password ), NULL };
    627                                
    628                                 /*irc_setpass( irc, NULL );*/
    629                                 /*root_command( irc, send_cmd );*/
    630                                 g_free( send_cmd[1] );
    631                         }
    632                        
    633                         irc_send_login( irc );
    634                        
    635                         irc->umode[0] = '\0';
    636                         irc_umode_set( irc, "+" UMODE, TRUE );
    637                        
    638                         ic = irc_channel_new( irc, ROOT_CHAN );
    639                         irc_channel_set_topic( ic, CONTROL_TOPIC, irc->root );
    640                         irc_channel_add_user( ic, irc->user );
    641                        
    642                         if( strcmp( set_getstr( &irc->b->set, "ops" ), "both" ) == 0 ||
    643                             strcmp( set_getstr( &irc->b->set, "ops" ), "user" ) == 0 )
    644                                 irc_channel_user_set_mode( ic, irc->user, IRC_CHANNEL_USER_OP );
    645                        
    646                         irc->last_root_cmd = g_strdup( ROOT_CHAN );
    647                        
    648                         irc_send_msg( irc->root, "PRIVMSG", ROOT_CHAN,
    649                                       "Welcome to the BitlBee gateway!\n\n"
    650                                       "If you've never used BitlBee before, please do read the help "
    651                                       "information using the \x02help\x02 command. Lots of FAQs are "
    652                                       "answered there.\n"
    653                                       "If you already have an account on this server, just use the "
    654                                       "\x02identify\x02 command to identify yourself.", NULL );
    655                        
     805                        irc_login( irc );
    656806                        return 1;
    657807                }
     
    664814}
    665815
    666 void irc_umode_set( irc_t *irc, const char *s, gboolean allow_priv )
     816void 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
     876void 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
     928void 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
     940void irc_umode_set( irc_t *irc, char *s, int allow_priv )
    667941{
    668942        /* allow_priv: Set to 0 if s contains user input, 1 if you want
    669943           to set a "privileged" mode (+o, +R, etc). */
    670         char m[128], st = 1;
    671         const char *t;
     944        char m[256], st = 1, *t;
    672945        int i;
    673946        char changes[512], *p, st2 = 2;
     
    677950       
    678951        for( t = irc->umode; *t; t ++ )
    679                 if( *t < sizeof( m ) )
    680                         m[(int)*t] = 1;
    681        
     952                m[(int)*t] = 1;
     953
    682954        p = changes;
    683955        for( t = s; *t; t ++ )
     
    685957                if( *t == '+' || *t == '-' )
    686958                        st = *t == '+';
    687                 else if( ( st == 0 && ( !strchr( UMODES_KEEP, *t ) || allow_priv ) ) ||
    688                          ( st == 1 && strchr( UMODES, *t ) ) ||
    689                          ( st == 1 && allow_priv && strchr( UMODES_PRIV, *t ) ) )
     959                else if( st == 0 || ( strchr( UMODES, *t ) || ( allow_priv && strchr( UMODES_PRIV, *t ) ) ) )
    690960                {
    691961                        if( m[(int)*t] != st)
     
    704974        memset( irc->umode, 0, sizeof( irc->umode ) );
    705975       
    706         for( i = 'A'; i <= 'z' && strlen( irc->umode ) < ( sizeof( irc->umode ) - 1 ); i ++ )
     976        for( i = 0; i < 256 && strlen( irc->umode ) < ( sizeof( irc->umode ) - 1 ); i ++ )
    707977                if( m[i] )
    708978                        irc->umode[strlen(irc->umode)] = i;
    709979       
    710980        if( badflag )
    711                 irc_send_num( irc, 501, ":Unknown MODE flag" );
     981                irc_reply( irc, 501, ":Unknown MODE flag" );
     982        /* Deliberately no !user@host on the prefix here */
    712983        if( *changes )
    713                 irc_write( irc, ":%s!%s@%s MODE %s :%s", irc->user->nick,
    714                            irc->user->user, irc->user->host, irc->user->nick,
    715                            changes );
    716 }
    717 
     984                irc_write( irc, ":%s MODE %s %s", irc->nick, irc->nick, changes );
     985}
     986
     987void irc_spawn( irc_t *irc, user_t *u )
     988{
     989        irc_join( irc, u, irc->channel );
     990}
     991
     992void 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
     1015void 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
     1020void 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
     1025void 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
     1062int 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
     1163static 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
     1183void 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
     1228int 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
     1267int 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
     1290int 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}
    7181299
    7191300/* Returns 0 if everything seems to be okay, a number >0 when there was a
     
    7531334}
    7541335
    755 static char *set_eval_charset( set_t *set, char *value )
    756 {
    757         irc_t *irc = (irc_t*) set->data;
    758         char *test;
    759         gsize test_bytes = 0;
    760         GIConv ic, oc;
    761 
    762         if( g_strcasecmp( value, "none" ) == 0 )
    763                 value = g_strdup( "utf-8" );
    764 
    765         if( ( oc = g_iconv_open( value, "utf-8" ) ) == (GIConv) -1 )
    766         {
    767                 return NULL;
    768         }
    769        
    770         /* Do a test iconv to see if the user picked an IRC-compatible
    771            charset (for example utf-16 goes *horribly* wrong). */
    772         if( ( test = g_convert_with_iconv( " ", 1, oc, NULL, &test_bytes, NULL ) ) == NULL ||
    773             test_bytes > 1 )
    774         {
    775                 g_free( test );
    776                 g_iconv_close( oc );
    777                 irc_usermsg( irc, "Unsupported character set: The IRC protocol "
    778                                   "only supports 8-bit character sets." );
    779                 return NULL;
    780         }
    781         g_free( test );
    782        
    783         if( ( ic = g_iconv_open( "utf-8", value ) ) == (GIConv) -1 )
    784         {
    785                 g_iconv_close( oc );
    786                 return NULL;
    787         }
    788        
    789         if( irc->iconv != (GIConv) -1 )
    790                 g_iconv_close( irc->iconv );
    791         if( irc->oconv != (GIConv) -1 )
    792                 g_iconv_close( irc->oconv );
    793        
    794         irc->iconv = ic;
    795         irc->oconv = oc;
    796 
    797         return value;
    798 }
     1336struct 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}
  • irc.h

    rf924563 r6824fb3  
    55  \********************************************************************/
    66
    7 /* The IRC-based UI (for now the only one)                              */
     7/* The big hairy IRCd part of the project                               */
    88
    99/*
     
    3333#define IRC_PING_STRING "PinglBee"
    3434
    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 */
     35#define UMODES "abisw"
     36#define UMODES_PRIV "Ro"
     37#define CMODES "nt"
     38#define CMODE "t"
     39#define UMODE "s"
     40#define CTYPES "&#"
    4341
    4442typedef enum
     
    5048        USTATUS_SHUTDOWN = 8
    5149} irc_status_t;
    52 
    53 struct irc_user;
    5450
    5551typedef struct irc
     
    6359        GIConv iconv, oconv;
    6460
    65         struct irc_user *root;
    66         struct irc_user *user;
    67        
    68         char *last_root_cmd;
     61        int sentbytes;
     62        time_t oldtime;
    6963
     64        char *nick;
     65        char *user;
     66        char *host;
     67        char *realname;
    7068        char *password; /* HACK: Used to save the user's password, but before
    7169                           logging in, this may contain a password we should
     
    7472        char umode[8];
    7573       
     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       
    7683        struct query *queries;
    77         GSList *file_transfers;
     84        struct account *accounts;
     85        struct chat *chatrooms;
    7886       
    79         GSList *users, *channels;
    80         GHashTable *nick_user_hash;
     87        struct __USER *users;
     88        GHashTable *userhash;
    8189        GHashTable *watches;
     90        struct __NICK *nicks;
     91        struct set *set;
    8292
    8393        gint r_watch_source_id;
    8494        gint w_watch_source_id;
    8595        gint ping_source_id;
    86        
    87         struct bee *b;
    8896} irc_t;
    8997
    90 typedef enum
    91 {
    92         IRC_USER_PRIVATE = 1,
    93 } irc_user_flags_t;
     98#include "user.h"
    9499
    95 typedef struct irc_user
    96 {
    97         irc_t *irc;
    98        
    99         char *nick;
    100         char *user;
    101         char *host;
    102         char *fullname;
    103        
    104         /* Nickname in lowercase for case sensitive searches */
    105         char *key;
    106        
    107         irc_user_flags_t flags;
    108        
    109         char *sendbuf;
    110         int sendbuf_len;
    111         guint sendbuf_timer;
    112         //int sendbuf_flags;
    113        
    114         struct bee_user *bu;
    115        
    116         const struct irc_user_funcs *f;
    117 } irc_user_t;
    118 
    119 struct irc_user_funcs
    120 {
    121         gboolean (*privmsg)( irc_user_t *iu, const char *msg );
    122         gboolean (*ctcp)( irc_user_t *iu, char * const* ctcp );
    123 };
    124 
    125 extern const struct irc_user_funcs irc_user_root_funcs;
    126 extern const struct irc_user_funcs irc_user_self_funcs;
    127 
    128 typedef enum
    129 {
    130         IRC_CHANNEL_JOINED = 1,
    131 } irc_channel_flags_t;
    132 
    133 typedef struct irc_channel
    134 {
    135         irc_t *irc;
    136         char *name;
    137         char mode[8];
    138         int flags;
    139        
    140         char *topic;
    141         char *topic_who;
    142         time_t topic_time;
    143        
    144         GSList *users;
    145         struct set *set;
    146        
    147         const struct irc_channel_funcs *f;
    148 } irc_channel_t;
    149 
    150 struct irc_channel_funcs
    151 {
    152         gboolean (*privmsg)( irc_channel_t *iu, const char *msg );
    153 };
    154 
    155 typedef enum
    156 {
    157         IRC_CHANNEL_USER_OP = 1,
    158         IRC_CHANNEL_USER_HALFOP = 2,
    159         IRC_CHANNEL_USER_VOICE = 4,
    160 } irc_channel_user_flags_t;
    161 
    162 typedef struct irc_channel_user
    163 {
    164         irc_user_t *iu;
    165         int flags;
    166 } irc_channel_user_t;
    167 
    168 extern const struct bee_ui_funcs irc_ui_funcs;
    169 
    170 /* irc.c */
    171100extern GSList *irc_connection_list;
    172101
     
    174103void irc_abort( irc_t *irc, int immed, char *format, ... ) G_GNUC_PRINTF( 3, 4 );
    175104void irc_free( irc_t *irc );
    176 void irc_setpass (irc_t *irc, const char *pass);
    177105
     106void irc_exec( irc_t *irc, char **cmd );
    178107void irc_process( irc_t *irc );
    179108char **irc_parse_line( char *line );
    180109char *irc_build_line( char **cmd );
    181110
     111void irc_vawrite( irc_t *irc, char *format, va_list params );
    182112void irc_write( irc_t *irc, char *format, ... ) G_GNUC_PRINTF( 2, 3 );
    183113void irc_write_all( int now, char *format, ... ) G_GNUC_PRINTF( 2, 3 );
    184 void irc_vawrite( irc_t *irc, char *format, va_list params );
     114void irc_reply( irc_t *irc, int code, char *format, ... ) G_GNUC_PRINTF( 3, 4 );
     115G_MODULE_EXPORT int irc_usermsg( irc_t *irc, char *format, ... ) G_GNUC_PRINTF( 2, 3 );
     116char **irc_tokenize( char *buffer );
    185117
     118void irc_login( irc_t *irc );
    186119int irc_check_login( irc_t *irc );
     120void irc_motd( irc_t *irc );
     121void irc_names( irc_t *irc, char *channel );
     122void irc_topic( irc_t *irc, char *channel );
     123void irc_umode_set( irc_t *irc, char *s, int allow_priv );
     124void irc_who( irc_t *irc, char *channel );
     125void irc_spawn( irc_t *irc, user_t *u );
     126void irc_join( irc_t *irc, user_t *u, char *channel );
     127void irc_part( irc_t *irc, user_t *u, char *channel );
     128void irc_kick( irc_t *irc, user_t *u, char *channel, user_t *kicker );
     129void irc_kill( irc_t *irc, user_t *u );
     130void irc_invite( irc_t *irc, char *nick, char *channel );
     131void irc_whois( irc_t *irc, char *nick );
     132void irc_setpass( irc_t *irc, const char *pass ); /* USE WITH CAUTION! */
    187133
    188 void irc_umode_set( irc_t *irc, const char *s, gboolean allow_priv );
     134int irc_send( irc_t *irc, char *nick, char *s, int flags );
     135int irc_privmsg( irc_t *irc, user_t *u, char *type, char *to, char *prefix, char *msg );
     136int irc_msgfrom( irc_t *irc, char *nick, char *msg );
     137int irc_noticefrom( irc_t *irc, char *nick, char *msg );
    189138
    190 /* irc_channel.c */
    191 irc_channel_t *irc_channel_new( irc_t *irc, const char *name );
    192 irc_channel_t *irc_channel_by_name( irc_t *irc, const char *name );
    193 int irc_channel_free( irc_channel_t *ic );
    194 int irc_channel_add_user( irc_channel_t *ic, irc_user_t *iu );
    195 int irc_channel_del_user( irc_channel_t *ic, irc_user_t *iu );
    196 irc_channel_user_t *irc_channel_has_user( irc_channel_t *ic, irc_user_t *iu );
    197 int irc_channel_set_topic( irc_channel_t *ic, const char *topic, const irc_user_t *who );
    198 void irc_channel_user_set_mode( irc_channel_t *ic, irc_user_t *iu, irc_channel_user_flags_t flags );
    199 gboolean irc_channel_name_ok( const char *name );
    200 
    201 /* irc_commands.c */
    202 void irc_exec( irc_t *irc, char **cmd );
    203 
    204 /* irc_send.c */
    205 void irc_send_num( irc_t *irc, int code, char *format, ... ) G_GNUC_PRINTF( 3, 4 );
    206 void irc_send_login( irc_t *irc );
    207 void irc_send_motd( irc_t *irc );
    208 void irc_usermsg( irc_t *irc, char *format, ... );
    209 void irc_send_join( irc_channel_t *ic, irc_user_t *iu );
    210 void irc_send_part( irc_channel_t *ic, irc_user_t *iu, const char *reason );
    211 void irc_send_names( irc_channel_t *ic );
    212 void irc_send_topic( irc_channel_t *ic, gboolean topic_change );
    213 void irc_send_whois( irc_user_t *iu );
    214 void irc_send_who( irc_t *irc, GSList *l, const char *channel );
    215 void irc_send_msg( irc_user_t *iu, const char *type, const char *dst, const char *msg, const char *prefix );
    216 void irc_send_msg_raw( irc_user_t *iu, const char *type, const char *dst, const char *msg );
    217 void irc_send_msg_f( irc_user_t *iu, const char *type, const char *dst, const char *format, ... ) G_GNUC_PRINTF( 4, 5 );
    218 void irc_send_nick( irc_user_t *iu, const char *new );
    219 void irc_send_channel_user_mode_diff( irc_channel_t *ic, irc_user_t *iu,
    220                                       irc_channel_user_flags_t old, irc_channel_user_flags_t new );
    221 
    222 /* irc_user.c */
    223 irc_user_t *irc_user_new( irc_t *irc, const char *nick );
    224 int irc_user_free( irc_t *irc, irc_user_t *iu );
    225 irc_user_t *irc_user_by_name( irc_t *irc, const char *nick );
    226 int irc_user_set_nick( irc_user_t *iu, const char *new );
    227 gint irc_user_cmp( gconstpointer a_, gconstpointer b_ );
    228 const char *irc_user_get_away( irc_user_t *iu );
    229 
    230 /* irc_util.c */
    231 char *set_eval_timezone( struct set *set, char *value );
    232 char *irc_format_timestamp( irc_t *irc, time_t msg_ts );
     139void buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags );
     140struct groupchat *irc_chat_by_channel( irc_t *irc, char *channel );
    233141
    234142#endif
  • irc_commands.c

    rf924563 r6824fb3  
    22  * BitlBee -- An IRC to other IM-networks gateway                     *
    33  *                                                                    *
    4   * Copyright 2002-2010 Wilmer van der Gaast and others                *
     4  * Copyright 2002-2006 Wilmer van der Gaast and others                *
    55  \********************************************************************/
    66
     
    5353        else if( global.conf->auth_pass )
    5454        {
    55                 irc_send_num( irc, 464, ":Incorrect password" );
     55                irc_reply( 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->user = g_strdup( cmd[1] );
    68         irc->user->fullname = g_strdup( cmd[4] );
     67        irc->user = g_strdup( cmd[1] );
     68        irc->realname = g_strdup( cmd[4] );
    6969       
    7070        irc_check_login( irc );
     
    7373static void irc_cmd_nick( irc_t *irc, char **cmd )
    7474{
    75         if( irc_user_by_name( irc, cmd[1] ) )
    76         {
    77                 irc_send_num( irc, 433, ":This nick is already in use" );
     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" );
    7883        }
    7984        else if( !nick_ok( cmd[1] ) )
    8085        {
    8186                /* [SH] Invalid characters. */
    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] );
     87                irc_reply( irc, 432, ":This nick contains invalid characters" );
     88        }
     89        else
     90        {
     91                irc->nick = g_strdup( cmd[1] );
    9892               
    9993                irc_check_login( irc );
     
    111105static void irc_cmd_ping( irc_t *irc, char **cmd )
    112106{
    113         irc_write( irc, ":%s PONG %s :%s", irc->root->host,
    114                    irc->root->host, cmd[1]?cmd[1]:irc->root->host );
    115 }
    116 
    117 static 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 
    125 static 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 
    145 static 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 
    163 static 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                 irc_send_num( irc, 442, "%s :You're not on that channel", cmd[1] );
    174         }
    175 }
    176 
    177 static void irc_cmd_whois( irc_t *irc, char **cmd )
    178 {
    179         char *nick = cmd[1];
    180         irc_user_t *iu = irc_user_by_name( irc, nick );
    181        
    182         if( iu )
    183                 irc_send_whois( iu );
    184         else
    185                 irc_send_num( irc, 401, "%s :Nick does not exist", nick );
    186 }
    187 
    188 static void irc_cmd_whowas( irc_t *irc, char **cmd )
    189 {
    190         /* For some reason irssi tries a whowas when whois fails. We can
    191            ignore this, but then the user never gets a "user not found"
    192            message from irssi which is a bit annoying. So just respond
    193            with not-found and irssi users will get better error messages */
    194        
    195         irc_send_num( irc, 406, "%s :Nick does not exist", cmd[1] );
    196         irc_send_num( irc, 369, "%s :End of WHOWAS", cmd[1] );
    197 }
    198 
    199 static void irc_cmd_motd( irc_t *irc, char **cmd )
    200 {
    201         irc_send_motd( irc );
     107        irc_write( irc, ":%s PONG %s :%s", irc->myhost, irc->myhost, cmd[1]?cmd[1]:irc->myhost );
     108}
     109
     110static 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        }
    202124}
    203125
    204126static void irc_cmd_mode( irc_t *irc, char **cmd )
    205127{
    206         if( irc_channel_name_ok( cmd[1] ) )
    207         {
    208                 irc_channel_t *ic;
    209                
    210                 if( ( ic = irc_channel_by_name( irc, cmd[1] ) ) == NULL )
    211                         irc_send_num( irc, 403, "%s :No such channel", cmd[1] );
    212                 else if( cmd[2] )
     128        if( strchr( CTYPES, *cmd[1] ) )
     129        {
     130                if( cmd[2] )
    213131                {
    214132                        if( *cmd[2] == '+' || *cmd[2] == '-' )
    215                                 irc_send_num( irc, 477, "%s :Can't change channel modes", cmd[1] );
     133                                irc_reply( irc, 477, "%s :Can't change channel modes", cmd[1] );
    216134                        else if( *cmd[2] == 'b' )
    217                                 irc_send_num( irc, 368, "%s :No bans possible", cmd[1] );
     135                                irc_reply( irc, 368, "%s :No bans possible", cmd[1] );
    218136                }
    219137                else
    220                         irc_send_num( irc, 324, "%s +%s", cmd[1], ic->mode );
    221         }
    222         else
    223         {
    224                 if( nick_cmp( cmd[1], irc->user->nick ) == 0 )
     138                        irc_reply( irc, 324, "%s +%s", cmd[1], CMODE );
     139        }
     140        else
     141        {
     142                if( nick_cmp( cmd[1], irc->nick ) == 0 )
    225143                {
    226144                        if( cmd[2] )
    227145                                irc_umode_set( irc, cmd[2], 0 );
    228146                        else
    229                                 irc_send_num( irc, 221, "+%s", irc->umode );
     147                                irc_reply( irc, 221, "+%s", irc->umode );
    230148                }
    231149                else
    232                         irc_send_num( irc, 502, ":Don't touch their modes" );
    233         }
    234 }
    235 
    236 static void irc_cmd_who( irc_t *irc, char **cmd )
    237 {
    238         char *channel = cmd[1];
    239         irc_channel_t *ic;
    240        
    241         if( !channel || *channel == '0' || *channel == '*' || !*channel )
    242                 irc_send_who( irc, irc->users, "**" );
    243         else if( ( ic = irc_channel_by_name( irc, channel ) ) )
    244                 irc_send_who( irc, ic->users, channel );
    245         else
    246                 irc_send_num( irc, 403, "%s :No such channel", channel );
     150                        irc_reply( irc, 502, ":Don't touch their modes" );
     151        }
     152}
     153
     154static void irc_cmd_names( irc_t *irc, char **cmd )
     155{
     156        irc_names( irc, cmd[1]?cmd[1]:irc->channel );
     157}
     158
     159static 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
     189static 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
     207static 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 );
    247222}
    248223
    249224static void irc_cmd_privmsg( irc_t *irc, char **cmd )
    250225{
    251         irc_channel_t *ic;
    252         irc_user_t *iu;
    253        
    254         if( !cmd[2] )
    255         {
    256                 irc_send_num( irc, 412, ":No text to send" );
    257                 return;
    258         }
    259        
    260         /* Don't treat CTCP actions as real CTCPs, just convert them right now. */
    261         if( g_strncasecmp( cmd[2], "\001ACTION", 7 ) == 0 )
    262         {
    263                 cmd[2] += 4;
    264                 strcpy( cmd[2], "/me" );
    265                 if( cmd[2][strlen(cmd[2])-1] == '\001' )
    266                         cmd[2][strlen(cmd[2])-1] = '\0';
    267         }
    268        
    269         if( irc_channel_name_ok( cmd[1] ) &&
    270             ( ic = irc_channel_by_name( irc, cmd[1] ) ) )
    271         {
    272                 if( ic->f->privmsg )
    273                         ic->f->privmsg( ic, cmd[2] );
    274         }
    275         else if( ( iu = irc_user_by_name( irc, cmd[1] ) ) )
    276         {
    277                 if( cmd[2][0] == '\001' )
    278                 {
    279                         char **ctcp;
    280                        
    281                         if( iu->f->ctcp == NULL )
    282                                 return;
    283                         if( cmd[2][strlen(cmd[2])-1] == '\001' )
    284                                 cmd[2][strlen(cmd[2])-1] = '\0';
    285                        
    286                         ctcp = split_command_parts( cmd[2] + 1 );
    287                         iu->f->ctcp( iu, ctcp );
    288                 }
    289                 else if( iu->f->privmsg )
    290                 {
    291                         iu->flags |= IRC_USER_PRIVATE;
    292                         iu->f->privmsg( iu, cmd[2] );
    293                 }
    294         }
    295         else
    296         {
    297                 irc_send_num( irc, 401, "%s :No such nick/channel", cmd[1] );
    298         }
    299 
    300 
    301 #if 0
    302         else if( irc->nick && g_strcasecmp( cmd[1], irc->nick ) == 0 )
    303         {
     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] );
    304233        }
    305234        else
     
    342271                irc_send( irc, cmd[1], cmd[2], ( g_strcasecmp( cmd[0], "NOTICE" ) == 0 ) ? OPT_AWAY : 0 );
    343272        }
    344 #endif
    345 }
    346 
    347 static void irc_cmd_nickserv( irc_t *irc, char **cmd )
    348 {
    349         /* [SH] This aliases the NickServ command to PRIVMSG root */
    350         /* [TV] This aliases the NS command to PRIVMSG root as well */
    351         root_command( irc, cmd + 1 );
    352 }
    353 
    354 
    355 
    356 static void irc_cmd_oper( irc_t *irc, char **cmd )
    357 {
    358         if( global.conf->oper_pass &&
    359             ( strncmp( global.conf->oper_pass, "md5:", 4 ) == 0 ?
    360                 md5_verify_password( cmd[2], global.conf->oper_pass + 4 ) == 0 :
    361                 strcmp( cmd[2], global.conf->oper_pass ) == 0 ) )
    362         {
    363                 irc_umode_set( irc, "+o", 1 );
    364                 irc_send_num( irc, 381, ":Password accepted" );
    365         }
    366         else
    367         {
    368                 irc_send_num( irc, 432, ":Incorrect password" );
    369         }
    370 }
    371 
    372 #if 0
    373 static void irc_cmd_invite( irc_t *irc, char **cmd )
    374 {
    375         char *nick = cmd[1], *channel = cmd[2];
    376         struct groupchat *c = irc_chat_by_channel( irc, channel );
    377         user_t *u = user_find( irc, nick );
    378        
    379         if( u && c && ( u->ic == c->ic ) )
    380                 if( c->ic && c->ic->acc->prpl->chat_invite )
    381                 {
    382                         c->ic->acc->prpl->chat_invite( c, u->handle, NULL );
    383                         irc_send_num( irc, 341, "%s %s", nick, channel );
    384                         return;
    385                 }
    386        
    387         irc_send_num( irc, 482, "%s :Invite impossible; User/Channel non-existent or incompatible", channel );
    388 }
    389 #endif
     273}
     274
     275static 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:"**" );
     305}
    390306
    391307static void irc_cmd_userhost( irc_t *irc, char **cmd )
    392308{
     309        user_t *u;
    393310        int i;
    394311       
     
    400317       
    401318        for( i = 1; cmd[i]; i ++ )
    402         {
    403                 irc_user_t *iu = irc_user_by_name( irc, cmd[i] );
    404                
    405                 if( iu )
    406                         irc_send_num( irc, 302, ":%s=%c%s@%s", iu->nick,
    407                                       irc_user_get_away( iu ) ? '-' : '+',
    408                                       iu->user, iu->host );
    409         }
     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                }
    410326}
    411327
    412328static void irc_cmd_ison( irc_t *irc, char **cmd )
    413329{
     330        user_t *u;
    414331        char buff[IRC_MAX_LINE];
    415332        int lenleft, i;
     
    427344                while( *this )
    428345                {
    429                         irc_user_t *iu;
    430                        
    431346                        if( ( next = strchr( this, ' ' ) ) )
    432347                                *next = 0;
    433348                       
    434                         if( ( iu = irc_user_by_name( irc, this ) ) &&
    435                             iu->bu && iu->bu->flags & BEE_USER_ONLINE )
    436                         {
    437                                 lenleft -= strlen( iu->nick ) + 1;
     349                        if( ( u = user_find( irc, this ) ) && u->online )
     350                        {
     351                                lenleft -= strlen( u->nick ) + 1;
    438352                               
    439353                                if( lenleft < 0 )
    440354                                        break;
    441355                               
    442                                 strcat( buff, iu->nick );
     356                                strcat( buff, u->nick );
    443357                                strcat( buff, " " );
    444358                        }
     
    463377                buff[strlen(buff)-1] = '\0';
    464378       
    465         irc_send_num( irc, 303, ":%s", buff );
     379        irc_reply( irc, 303, ":%s", buff );
    466380}
    467381
     
    476390        {
    477391                char *nick;
    478                 irc_user_t *iu;
     392                user_t *u;
    479393               
    480394                if( !cmd[i][0] || !cmd[i][1] )
     
    484398                nick_lc( nick );
    485399               
    486                 iu = irc_user_by_name( irc, nick );
     400                u = user_find( irc, nick );
    487401               
    488402                if( cmd[i][0] == '+' )
     
    491405                                g_hash_table_insert( irc->watches, nick, nick );
    492406                       
    493                         if( iu && iu->bu && iu->bu->flags & BEE_USER_ONLINE )
    494                                 irc_send_num( irc, 604, "%s %s %s %d :%s", iu->nick, iu->user,
    495                                               iu->host, (int) time( NULL ), "is online" );
     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" );
    496409                        else
    497                                 irc_send_num( irc, 605, "%s %s %s %d :%s", nick, "*", "*",
    498                                               (int) time( NULL ), "is offline" );
     410                                irc_reply( irc, 605, "%s %s %s %d :%s", nick, "*", "*", (int) time( NULL ), "is offline" );
    499411                }
    500412                else if( cmd[i][0] == '-' )
     
    507419                                g_free( okey );
    508420                               
    509                                 irc_send_num( irc, 602, "%s %s %s %d :%s", nick, "*", "*", 0, "Stopped watching" );
    510                         }
    511                 }
    512         }
    513 }
    514 
    515 #if 0
     421                                irc_reply( irc, 602, "%s %s %s %d :%s", nick, "*", "*", 0, "Stopped watching" );
     422                        }
     423                }
     424        }
     425}
     426
    516427static void irc_cmd_topic( irc_t *irc, char **cmd )
    517428{
     
    532443        }
    533444}
    534 #endif
    535445
    536446static void irc_cmd_away( irc_t *irc, char **cmd )
    537447{
    538         char *set;
    539        
    540         if( cmd[1] && *cmd[1] )
    541         {
    542                 char away[strlen(cmd[1])+1];
     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        {
    543455                int i, j;
    544456               
    545457                /* Copy away string, but skip control chars. Mainly because
    546458                   Jabber really doesn't like them. */
    547                 for( i = j = 0; cmd[1][i]; i ++ )
    548                         if( ( away[j] = cmd[1][i] ) >= ' ' )
     459                u->away = g_malloc( strlen( away ) + 1 );
     460                for( i = j = 0; away[i]; i ++ )
     461                        if( ( u->away[j] = away[i] ) >= ' ' )
    549462                                j ++;
    550                 away[j] = '\0';
    551                
    552                 irc_send_num( irc, 306, ":You're now away: %s", away );
    553                 set = away;
    554         }
    555         else
    556         {
    557                 irc_send_num( irc, 305, ":Welcome back" );
    558                 set = NULL;
    559         }
    560        
    561         set_setstr( &irc->b->set, "away", set );
     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
     479static 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
     510static 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
     521static 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
     528static void irc_cmd_motd( irc_t *irc, char **cmd )
     529{
     530        irc_motd( irc );
     531}
     532
     533static 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;
    562539}
    563540
    564541static void irc_cmd_version( irc_t *irc, char **cmd )
    565542{
    566         irc_send_num( irc, 351, "bitlbee-%s. %s :%s/%s ",
    567                       BITLBEE_VERSION, irc->root->host, ARCH, CPU );
     543        irc_reply( irc, 351, "bitlbee-%s. %s :%s/%s ", BITLBEE_VERSION, irc->myhost, ARCH, CPU );
    568544}
    569545
    570546static void irc_cmd_completions( irc_t *irc, char **cmd )
    571547{
     548        user_t *u = user_find( irc, irc->mynick );
    572549        help_t *h;
    573550        set_t *s;
    574551        int i;
    575552       
    576         irc_send_msg_raw( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS OK" );
     553        irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", "OK" );
    577554       
    578555        for( i = 0; commands[i].command; i ++ )
    579                 irc_send_msg_f( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS %s", commands[i].command );
     556                irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", commands[i].command );
    580557       
    581558        for( h = global.help; h; h = h->next )
    582                 irc_send_msg_f( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS help %s", h->title );
    583        
    584         for( s = irc->b->set; s; s = s->next )
    585                 irc_send_msg_f( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS set %s", s->key );
    586        
    587         irc_send_msg_raw( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS END" );
     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" );
    588565}
    589566
     
    595572                ipc_to_master( cmd );
    596573       
    597         irc_send_num( irc, 382, "%s :Rehashing", global.conf_file );
     574        irc_reply( irc, 382, "%s :Rehashing", global.conf_file );
    598575}
    599576
     
    604581        { "quit",        0, irc_cmd_quit,        0 },
    605582        { "ping",        0, irc_cmd_ping,        0 },
    606         { "pong",        0, irc_cmd_pong,        IRC_CMD_LOGGED_IN },
     583        { "oper",        2, irc_cmd_oper,        IRC_CMD_LOGGED_IN },
     584        { "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 },
    607587        { "join",        1, irc_cmd_join,        IRC_CMD_LOGGED_IN },
    608         { "names",       1, irc_cmd_names,       IRC_CMD_LOGGED_IN },
    609         { "part",        1, irc_cmd_part,        IRC_CMD_LOGGED_IN },
    610         { "whois",       1, irc_cmd_whois,       IRC_CMD_LOGGED_IN },
    611         { "whowas",      1, irc_cmd_whowas,      IRC_CMD_LOGGED_IN },
    612         { "motd",        0, irc_cmd_motd,        IRC_CMD_LOGGED_IN },
    613         { "mode",        1, irc_cmd_mode,        IRC_CMD_LOGGED_IN },
     588        { "invite",      2, irc_cmd_invite,      IRC_CMD_LOGGED_IN },
     589        { "privmsg",     1, irc_cmd_privmsg,     IRC_CMD_LOGGED_IN },
     590        { "notice",      1, irc_cmd_privmsg,     IRC_CMD_LOGGED_IN },
    614591        { "who",         0, irc_cmd_who,         IRC_CMD_LOGGED_IN },
    615         { "privmsg",     1, irc_cmd_privmsg,     IRC_CMD_LOGGED_IN },
    616         { "nickserv",    1, irc_cmd_nickserv,    IRC_CMD_LOGGED_IN },
    617         { "ns",          1, irc_cmd_nickserv,    IRC_CMD_LOGGED_IN },
    618         { "away",        0, irc_cmd_away,        IRC_CMD_LOGGED_IN },
    619         { "version",     0, irc_cmd_version,     IRC_CMD_LOGGED_IN },
    620         { "completions", 0, irc_cmd_completions, IRC_CMD_LOGGED_IN },
    621592        { "userhost",    1, irc_cmd_userhost,    IRC_CMD_LOGGED_IN },
    622593        { "ison",        1, irc_cmd_ison,        IRC_CMD_LOGGED_IN },
    623594        { "watch",       1, irc_cmd_watch,       IRC_CMD_LOGGED_IN },
    624 #if 0
    625         { "invite",      2, irc_cmd_invite,      IRC_CMD_LOGGED_IN },
    626         { "notice",      1, irc_cmd_privmsg,     IRC_CMD_LOGGED_IN },
    627595        { "topic",       1, irc_cmd_topic,       IRC_CMD_LOGGED_IN },
    628 #endif
    629         { "oper",        2, irc_cmd_oper,        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 },
    630605        { "die",         0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
    631606        { "deaf",        0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
     
    653628                        if( irc_commands[i].flags & IRC_CMD_PRE_LOGIN && irc->status & USTATUS_LOGGED_IN )
    654629                        {
    655                                 irc_send_num( irc, 462, ":Only allowed before logging in" );
     630                                irc_reply( irc, 462, ":Only allowed before logging in" );
    656631                        }
    657632                        else if( irc_commands[i].flags & IRC_CMD_LOGGED_IN && !( irc->status & USTATUS_LOGGED_IN ) )
    658633                        {
    659                                 irc_send_num( irc, 451, ":Register first" );
     634                                irc_reply( irc, 451, ":Register first" );
    660635                        }
    661636                        else if( irc_commands[i].flags & IRC_CMD_OPER_ONLY && !strchr( irc->umode, 'o' ) )
    662637                        {
    663                                 irc_send_num( irc, 481, ":Permission denied - You're not an IRC operator" );
     638                                irc_reply( irc, 481, ":Permission denied - You're not an IRC operator" );
    664639                        }
    665640                        else if( n_arg < irc_commands[i].required_parameters )
    666641                        {
    667                                 irc_send_num( irc, 461, "%s :Need more parameters", cmd[0] );
     642                                irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
    668643                        }
    669644                        else if( irc_commands[i].flags & IRC_CMD_TO_MASTER )
     
    682657       
    683658        if( irc->status >= USTATUS_LOGGED_IN )
    684                 irc_send_num( irc, 421, "%s :Unknown command", cmd[0] );
    685 }
     659                irc_reply( irc, 421, "%s :Unknown command", cmd[0] );
     660}
  • lib/Makefile

    rf924563 r6824fb3  
    1010
    1111# [SH] Program variables
    12 objects = arc.o base64.o $(EVENT_HANDLER) ftutil.o http_client.o ini.o md5.o misc.o oauth.o proxy.o sha1.o $(SSL_CLIENT) url.o xmltree.o
     12objects = 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
    1313
    1414CFLAGS += -Wall
  • lib/misc.c

    rf924563 r6824fb3  
    648648        return ret;
    649649}
    650 
    651 char **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

    rf924563 r6824fb3  
    6969G_MODULE_EXPORT int md5_verify_password( char *password, char *hash );
    7070
    71 G_MODULE_EXPORT char **split_command_parts( char *command );
    72 
    7371#endif
  • nick.c

    rf924563 r6824fb3  
    7878               
    7979                nick_strip( nick );
    80                 if( set_getbool( &acc->bee->set, "lcnicks" ) )
     80                if( set_getbool( &acc->irc->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;
    9594        int inf_protection = 256;
    9695       
    9796        /* Now, find out if the nick is already in use at the moment, and make
    9897           subtle changes to make it unique. */
    99         while( !nick_ok( nick ) || irc_user_by_name( irc, nick ) )
     98        while( !nick_ok( nick ) || user_find( acc->irc, nick ) )
    10099        {
    101100                if( strlen( nick ) < ( MAX_NICK_LENGTH - 1 ) )
     
    113112                        int i;
    114113                       
    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 );
     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 );
    122121                        for( i = 0; i < MAX_NICK_LENGTH; i ++ )
    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" );
     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" );
    128127                       
    129128                        g_snprintf( nick, MAX_NICK_LENGTH + 1, "xx%x", rand() );
  • protocols/Makefile

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

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

    rf924563 r6824fb3  
    9191                        pack = 0;
    9292                }
    93                 else if( strcmp( s, XMLNS_DISCO_INFO ) == 0 )
    94                 {
    95                         const char *features[] = { XMLNS_DISCO_INFO,
     93                else if( strcmp( s, XMLNS_DISCOVER ) == 0 )
     94                {
     95                        const char *features[] = { XMLNS_DISCOVER,
    9696                                                   XMLNS_VERSION,
    9797                                                   XMLNS_TIME,
     
    9999                                                   XMLNS_MUC,
    100100                                                   XMLNS_PING,
    101                                                    XMLNS_SI,
    102                                                    XMLNS_BYTESTREAMS,
    103                                                    XMLNS_FILETRANSFER,
    104101                                                   NULL };
    105102                        const char **f;
     
    121118                {
    122119                        xt_free_node( reply );
    123                         reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel", NULL );
     120                        reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel" );
    124121                        pack = 0;
    125122                }
     
    127124        else if( strcmp( type, "set" ) == 0 )
    128125        {
    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" ) ) )
     126                if( !( c = xt_find_node( node->children, "query" ) ) ||
     127                    !( s = xt_find_attr( c, "xmlns" ) ) )
    137128                {
    138129                        imcb_log( ic, "Warning: Received incomplete IQ-%s packet", type );
    139130                        return XT_HANDLED;
    140131                }
    141                 else if( strcmp( s, XMLNS_ROSTER ) == 0 )
    142                 {
     132               
    143133                /* This is a roster push. XMPP servers send this when someone
    144134                   was added to (or removed from) the buddy list. AFAIK they're
    145135                   sent even if we added this buddy in our own session. */
     136                if( strcmp( s, XMLNS_ROSTER ) == 0 )
     137                {
    146138                        int bare_len = strlen( ic->acc->user );
    147139                       
     
    160152                               
    161153                                xt_free_node( reply );
    162                                 reply = jabber_make_error_packet( node, "not-allowed", "cancel", NULL );
     154                                reply = jabber_make_error_packet( node, "not-allowed", "cancel" );
    163155                                pack = 0;
    164156                        }
    165157                }
    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                 }
    171158                else
    172159                {
    173160                        xt_free_node( reply );
    174                         reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel", NULL );
     161                        reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel" );
    175162                        pack = 0;
    176163                }
     
    392379                        if( ( strcmp( sub, "both" ) == 0 || strcmp( sub, "to" ) == 0 ) )
    393380                        {
    394                                 if( initial || bee_user_by_handle( ic->bee, ic, jid ) == NULL )
     381                                if( initial || imcb_find_buddy( ic, jid ) == NULL )
    395382                                        imcb_add_buddy( ic, jid, ( group && group->text_len ) ?
    396383                                                                   group->text : NULL );
     
    590577            strcmp( s, "result" ) == 0 )
    591578        {
    592                 if( bee_user_by_handle( ic->bee, ic, jid ) == NULL )
     579                if( imcb_find_buddy( ic, jid ) == NULL )
    593580                        imcb_add_buddy( ic, jid, NULL );
    594581        }
     
    622609        return st;
    623610}
    624 
    625 xt_status jabber_iq_parse_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
    626 
    627 xt_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 
    657 xt_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 
    690 xt_status jabber_iq_parse_server_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
    691 
    692 xt_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  */
    715 xt_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

    rf924563 r6824fb3  
    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 );
    6967       
    7068        s = set_add( &acc->set, "resource", "BitlBee", NULL, acc );
     
    266264        struct jabber_data *jd = ic->proto_data;
    267265       
    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 
    280266        if( jd->fd >= 0 )
    281267                jabber_end_stream( ic );
     
    558544        ret->send_typing = jabber_send_typing;
    559545        ret->handle_cmp = g_strcasecmp;
    560         ret->transfer_request = jabber_si_transfer_request;
    561546
    562547        register_protocol( ret );
  • protocols/jabber/jabber.h

    rf924563 r6824fb3  
    6161} jabber_buddy_flags_t;
    6262
    63 /* Stores a streamhost's (a.k.a. proxy) data */
    64 typedef struct
    65 {
    66         char *jid;
    67         char *host;
    68         char port[6];
    69 } jabber_streamhost_t;
    70 
    7163typedef enum
    7264{
     
    9991        GHashTable *node_cache;
    10092        GHashTable *buddies;
    101 
    102         GSList *filetransfers;
    103         GSList *streamhosts;
    104         int have_streamhosts;
    10593};
    10694
     
    139127        struct jabber_away_state *away_state;
    140128        char *away_message;
    141         GSList *features;
    142129       
    143130        time_t last_msg;
     
    153140        char *my_full_jid; /* Separate copy because of case sensitivity. */
    154141        struct jabber_buddy *me;
    155 };
    156 
    157 struct 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;
    185142};
    186143
     
    210167
    211168/* Some supported extensions/legacy stuff */
    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 */
     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 */
    230180
    231181/* iq.c */
     
    237187int jabber_add_to_roster( struct im_connection *ic, char *handle, char *name );
    238188int jabber_remove_from_roster( struct im_connection *ic, char *handle );
    239 xt_status jabber_iq_query_features( struct im_connection *ic, char *bare_jid );
    240 xt_status jabber_iq_query_server( struct im_connection *ic, char *jid, char *xmlns );
    241 
    242 /* si.c */
    243 int jabber_si_handle_request( struct im_connection *ic, struct xt_node *node, struct xt_node *sinode );
    244 void jabber_si_transfer_request( struct im_connection *ic, file_transfer_t *ft, char *who );
    245 void jabber_si_free_transfer( file_transfer_t *ft);
    246 
    247 /* s5bytestream.c */
    248 int jabber_bs_recv_request( struct im_connection *ic, struct xt_node *node, struct xt_node *qnode);
    249 gboolean jabber_bs_send_start( struct jabber_transfer *tf );
    250 gboolean jabber_bs_send_write( file_transfer_t *ft, char *buffer, unsigned int len );
    251189
    252190/* message.c */
     
    262200char *set_eval_tls( set_t *set, char *value );
    263201struct xt_node *jabber_make_packet( char *name, char *type, char *to, struct xt_node *children );
    264 struct xt_node *jabber_make_error_packet( struct xt_node *orig, char *err_cond, char *err_type, char *err_code );
     202struct xt_node *jabber_make_error_packet( struct xt_node *orig, char *err_cond, char *err_type );
    265203void jabber_cache_add( struct im_connection *ic, struct xt_node *node, jabber_cache_event func );
    266204struct xt_node *jabber_cache_get( struct im_connection *ic, char *id );
  • protocols/jabber/jabber_util.c

    rf924563 r6824fb3  
    9999}
    100100
    101 struct xt_node *jabber_make_error_packet( struct xt_node *orig, char *err_cond, char *err_type, char *err_code )
     101struct xt_node *jabber_make_error_packet( struct xt_node *orig, char *err_cond, char *err_type )
    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 );
    117113       
    118114        /* To make the actual error packet, we copy the original packet and
     
    279275        presence_send_request( bla->ic, bla->handle, "subscribed" );
    280276       
    281         imcb_ask_add( bla->ic, bla->handle, NULL );
     277        if( imcb_find_buddy( bla->ic, bla->handle ) == NULL )
     278                imcb_ask_add( bla->ic, bla->handle, NULL );
    282279       
    283280        g_free( bla->handle );
     
    461458               
    462459                if( bud == NULL && ( flags & GET_BUDDY_CREAT ) &&
    463                     ( bare_exists || bee_user_by_handle( ic->bee, ic, jid ) ) )
     460                    ( bare_exists || imcb_find_buddy( ic, jid ) ) )
    464461                {
    465462                        *s = '/';
     
    482479                if( bud == NULL )
    483480                        /* No match. Create it now? */
    484                         return ( ( flags & GET_BUDDY_CREAT ) &&
    485                                  bee_user_by_handle( ic->bee, ic, jid_ ) ) ?
     481                        return ( ( flags & GET_BUDDY_CREAT ) && imcb_find_buddy( ic, jid_ ) ) ?
    486482                                   jabber_buddy_add( ic, jid_ ) : NULL;
    487483                else if( bud->resource && ( flags & GET_BUDDY_EXACT ) )
  • protocols/msn/msn.c

    rf924563 r6824fb3  
    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                
    8781                if( md->fd >= 0 )
    8882                        closesocket( md->fd );
     
    334328        ret->send_typing = msn_send_typing;
    335329        ret->handle_cmp = g_strcasecmp;
    336         //ret->transfer_request = msn_ftp_transfer_request;
    337330
    338331        register_protocol(ret);
  • protocols/msn/msn.h

    rf924563 r6824fb3  
    7474        int sb_failures;
    7575        time_t first_sb_failure;
    76         GSList *filetransfers;
    7776       
    7877        const struct msn_away_state *away_state;
     
    190189void msn_sb_stop_keepalives( struct msn_switchboard *sb );
    191190
    192 /* invitation.c */
    193 void msn_ftp_transfer_request( struct im_connection *ic, file_transfer_t *ft, char *who );
    194 
    195191#endif //_MSN_H
  • protocols/msn/msn_util.c

    rf924563 r6824fb3  
    9696        msn_buddy_list_add( bla->ic, "AL", bla->handle, bla->realname );
    9797       
    98         imcb_ask_add( bla->ic, bla->handle, NULL );
     98        if( imcb_find_buddy( bla->ic, bla->handle ) == NULL )
     99                imcb_ask_add( bla->ic, bla->handle, NULL );
    99100       
    100101        g_free( bla->handle );
  • protocols/msn/sb.c

    rf924563 r6824fb3  
    2929#include "passport.h"
    3030#include "md5.h"
    31 #include "invitation.h"
    3231
    3332static gboolean msn_sb_callback( gpointer data, gint source, b_input_condition cond );
     
    178177                {
    179178                        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 );
    185179                        i = strlen( buf );
    186180                }
     
    703697                        }
    704698                }
    705 #if 0
    706                 // Disable MSN ft support for now.
    707699                else if( g_strncasecmp( ct, "text/x-msmsgsinvite", 19 ) == 0 )
    708700                {
    709                         char *command = msn_findheader( body, "Invitation-Command:", blen );
    710                         char *cookie = msn_findheader( body, "Invitation-Cookie:", blen );
    711                         unsigned int icookie;
     701                        char *itype = msn_findheader( body, "Application-GUID:", blen );
     702                        char buf[1024];
    712703                       
    713704                        g_free( ct );
    714705                       
    715                         /* Every invite should have both a Command and Cookie header */
    716                         if( !command || !cookie ) {
    717                                 g_free( command );
    718                                 g_free( cookie );
    719                                 imcb_log( ic, "Warning: No command or cookie from %s", sb->who );
    720                                 return 1;
    721                         }
    722                        
    723                         icookie = strtoul( cookie, NULL, 10 );
    724                         g_free( cookie );
    725                        
    726                         if( g_strncasecmp( command, "INVITE", 6 ) == 0 ) {
    727                                 msn_invitation_invite( sb, cmd[1], icookie, body, blen );
    728                         } else if( g_strncasecmp( command, "ACCEPT", 6 ) == 0 ) {
    729                                 msn_invitation_accept( sb, cmd[1], icookie, body, blen );
    730                         } else if( g_strncasecmp( command, "CANCEL", 6 ) == 0 ) {
    731                                 msn_invitation_cancel( sb, cmd[1], icookie, body, blen );
    732                         } else {
    733                                 imcb_log( ic, "Warning: Received invalid invitation with "
    734                                                 "command %s from %s", command, sb->who );
    735                         }
    736                        
    737                         g_free( command );
    738                 }
    739 #endif
    740                 else if( g_strncasecmp( ct, "application/x-msnmsgrp2p", 24 ) == 0 )
    741                 {
    742                         imcb_error( sb->ic, "Cannot receive file from %s: BitlBee does not "
    743                                         "support msnmsgrp2p yet.", sb->who );
    744                         g_free( ct );
     706                        *buf = 0;
     707                       
     708                        if( !itype )
     709                                return( 1 );
     710                       
     711                        /* File transfer. */
     712                        if( strcmp( itype, "{5D3E02AB-6190-11d3-BBBB-00C04F795683}" ) == 0 )
     713                        {
     714                                char *name = msn_findheader( body, "Application-File:", blen );
     715                                char *size = msn_findheader( body, "Application-FileSize:", blen );
     716                               
     717                                if( name && size )
     718                                {
     719                                        g_snprintf( buf, sizeof( buf ), "<< \x02""BitlBee\x02"" - Filetransfer: `%s', %s bytes >>\n"
     720                                                    "Filetransfers are not supported by BitlBee for now...", name, size );
     721                                }
     722                                else
     723                                {
     724                                        strcpy( buf, "<< \x02""BitlBee\x02"" - Corrupted MSN filetransfer invitation message >>" );
     725                                }
     726                               
     727                                if( name ) g_free( name );
     728                                if( size ) g_free( size );
     729                        }
     730                        else
     731                        {
     732                                char *iname = msn_findheader( body, "Application-Name:", blen );
     733                               
     734                                g_snprintf( buf, sizeof( buf ), "<< \x02""BitlBee\x02"" - Unknown MSN invitation - %s (%s) >>",
     735                                                                itype, iname ? iname : "no name" );
     736                               
     737                                if( iname ) g_free( iname );
     738                        }
     739                       
     740                        g_free( itype );
     741                       
     742                        if( !*buf )
     743                                return( 1 );
     744                       
     745                        if( sb->who )
     746                        {
     747                                imcb_buddy_msg( ic, cmd[1], buf, 0, 0 );
     748                        }
     749                        else if( sb->chat )
     750                        {
     751                                imcb_chat_msg( sb->chat, cmd[1], buf, 0, 0 );
     752                        }
     753                        else
     754                        {
     755                                /* PANIC! */
     756                        }
    745757                }
    746758                else if( g_strncasecmp( ct, "text/x-msmsgscontrol", 20 ) == 0 )
     
    773785void msn_sb_start_keepalives( struct msn_switchboard *sb, gboolean initial )
    774786{
    775         bee_user_t *bu;
     787        struct buddy *b;
    776788       
    777789        if( sb && sb->who && sb->keepalive == 0 &&
    778             ( bu = bee_user_by_handle( sb->ic->bee, sb->ic, sb->who ) ) &&
    779             !( bu->flags & BEE_USER_ONLINE ) &&
     790            ( b = imcb_find_buddy( sb->ic, sb->who ) ) && !b->present &&
    780791            set_getbool( &sb->ic->acc->set, "switchboard_keepalives" ) )
    781792        {
  • protocols/nogaim.c

    rf924563 r6824fb3  
    3838#include "chat.h"
    3939
     40static int remove_chat_buddy_silent( struct groupchat *b, const char *handle );
     41static char *format_timestamp( irc_t *irc, time_t msg_ts );
     42
    4043GSList *connections;
    4144
     
    8992}
    9093#endif
     94
     95/* nogaim.c */
    9196
    9297GList *protocols = NULL;
     
    121126}
    122127
     128/* nogaim.c */
    123129void nogaim_init()
    124130{
     
    156162GSList *get_connections() { return connections; }
    157163
     164/* multi.c */
     165
    158166struct im_connection *imcb_new( account_t *acc )
    159167{
     
    162170        ic = g_new0( struct im_connection, 1 );
    163171       
    164         ic->bee = acc->bee;
     172        ic->irc = acc->irc;
    165173        ic->acc = acc;
    166174        acc->ic = ic;
     
    176184       
    177185        /* Destroy the pointer to this connection from the account list */
    178         for( a = ic->bee->accounts; a; a = a->next )
     186        for( a = ic->irc->accounts; a; a = a->next )
    179187                if( a->ic == ic )
    180188                {
     
    197205        va_end( params );
    198206
    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" ) ) )
     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" ) ) )
    201209                strip_html( text );
    202210       
    203211        /* Try to find a different connection on the same protocol. */
    204         for( a = ic->bee->accounts; a; a = a->next )
     212        for( a = ic->irc->accounts; a; a = a->next )
    205213                if( a->prpl == ic->acc->prpl && a->ic != ic )
    206214                        break;
     
    208216        /* If we found one, include the screenname in the message. */
    209217        if( a )
    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 );
     218                irc_usermsg( ic->irc, "%s(%s) - %s", ic->acc->prpl->name, ic->acc->user, text );
    212219        else
    213                 irc_usermsg( ic->bee->ui_data, "%s - %s", ic->acc->prpl->name, text );
     220                irc_usermsg( ic->irc, "%s - %s", ic->acc->prpl->name, text );
    214221       
    215222        g_free( text );
     
    262269void imcb_connected( struct im_connection *ic )
    263270{
     271        irc_t *irc = ic->irc;
     272        struct chat *c;
     273        user_t *u;
     274       
    264275        /* MSN servers sometimes redirect you to a different server and do
    265276           the whole login sequence again, so these "late" calls to this
     
    268279                return;
    269280       
     281        u = user_find( ic->irc, ic->irc->nick );
     282       
    270283        imcb_log( ic, "Logged in" );
    271284       
     
    280293        ic->acc->auto_reconnect_delay = 0;
    281294       
    282         /*
    283295        for( c = irc->chatrooms; c; c = c->next )
    284296        {
     
    289301                        chat_join( irc, c, NULL );
    290302        }
    291         */
    292303}
    293304
     
    297308       
    298309        a->reconnect = 0;
    299         account_on( a->bee, a );
     310        account_on( a->irc, a );
    300311       
    301312        return( FALSE );        /* Only have to run the timeout once */
     
    310321void imc_logout( struct im_connection *ic, int allow_reconnect )
    311322{
    312         bee_t *bee = ic->bee;
     323        irc_t *irc = ic->irc;
     324        user_t *t, *u;
    313325        account_t *a;
    314         GSList *l;
    315326        int delay;
    316327       
     
    332343        ic->away = NULL;
    333344       
    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( ic->irc, ic );
    346        
    347         for( a = bee->accounts; a; a = a->next )
     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 )
    348361                if( a->ic == ic )
    349362                        break;
     
    353366                /* Uhm... This is very sick. */
    354367        }
    355         else if( allow_reconnect && set_getbool( &bee->set, "auto_reconnect" ) &&
     368        else if( allow_reconnect && set_getbool( &irc->set, "auto_reconnect" ) &&
    356369                 set_getbool( &a->set, "auto_reconnect" ) &&
    357370                 ( delay = account_reconnect_delay( a ) ) > 0 )
     
    364377}
    365378
     379
     380/* dialogs.c */
     381
    366382void imcb_ask( struct im_connection *ic, char *msg, void *data,
    367383               query_callback doit, query_callback dont )
    368384{
    369         query_add( (irc_t *) ic->bee->ui_data, ic, msg, doit, dont, data );
    370 }
     385        query_add( ic->irc, ic, msg, doit, dont, data );
     386}
     387
     388
     389/* list.c */
    371390
    372391void imcb_add_buddy( struct im_connection *ic, const char *handle, const char *group )
    373392{
    374         bee_user_t *bu;
    375         bee_t *bee = ic->bee;
    376        
    377         if( bee_user_by_handle( bee, ic, handle ) )
    378         {
    379                 if( set_getbool( &bee->set, "debug" ) )
     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" ) )
    380400                        imcb_log( ic, "User already exists, ignoring add request: %s", handle );
    381401               
     
    388408        }
    389409       
    390         bu = bee_user_new( bee, ic, handle );
    391         bu->group = g_strdup( group );
    392 }
    393 
    394 void imcb_rename_buddy( struct im_connection *ic, const char *handle, const char *fullname )
    395 {
    396         bee_t *bee = ic->bee;
    397         bee_user_t *bu = bee_user_by_handle( bee, ic, handle );
    398        
    399         if( !bu || !fullname ) return;
    400        
    401         if( !bu->fullname || strcmp( bu->fullname, fullname ) != 0 )
    402         {
    403                 g_free( bu->fullname );
    404                 bu->fullname = g_strdup( fullname );
    405                
    406                 if( bee->ui->user_fullname )
    407                         bee->ui->user_fullname( bee, bu );
     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
     446struct 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
     465void 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 );
    408497        }
    409498}
     
    411500void imcb_remove_buddy( struct im_connection *ic, const char *handle, char *group )
    412501{
    413         bee_user_free( ic->bee, bee_user_by_handle( ic->bee, ic, handle ) );
     502        user_t *u;
     503       
     504        if( ( u = user_findhandle( ic, handle ) ) )
     505                user_del( ic->irc, u->nick );
    414506}
    415507
     
    418510void imcb_buddy_nick_hint( struct im_connection *ic, const char *handle, const char *nick )
    419511{
    420 #if 0
    421512        user_t *u = user_findhandle( ic, handle );
    422513        char newnick[MAX_NICK_LENGTH+1], *orig_nick;
     
    433524                /* Some processing to make sure this string is a valid IRC nickname. */
    434525                nick_strip( newnick );
    435                 if( set_getbool( &ic->bee->set, "lcnicks" ) )
     526                if( set_getbool( &ic->irc->set, "lcnicks" ) )
    436527                        nick_lc( newnick );
    437528               
     
    450541                }
    451542        }
    452 #endif
    453543}
    454544
     
    495585        data->ic = ic;
    496586        data->handle = g_strdup( handle );
    497         query_add( (irc_t *) ic->bee->ui_data, ic, s,
    498                    imcb_ask_auth_cb_yes, imcb_ask_auth_cb_no, data );
     587        query_add( ic->irc, ic, s, imcb_ask_auth_cb_yes, imcb_ask_auth_cb_no, data );
    499588}
    500589
     
    521610       
    522611        /* TODO: Make a setting for this! */
    523         if( bee_user_by_handle( ic->bee, ic, handle ) != NULL )
     612        if( user_findhandle( ic, handle ) != NULL )
    524613                return;
    525614       
     
    528617        data->ic = ic;
    529618        data->handle = g_strdup( handle );
    530         query_add( (irc_t *) ic->bee->ui_data, ic, s,
    531                    imcb_ask_add_cb_yes, imcb_ask_add_cb_no, data );
    532 }
    533 
    534 struct bee_user *imcb_buddy_by_handle( struct im_connection *ic, const char *handle )
    535 {
    536         return bee_user_by_handle( ic->bee, ic, 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
     625void 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
     781void 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
     841void 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        }
    537855}
    538856
    539857struct groupchat *imcb_chat_new( struct im_connection *ic, const char *handle )
    540858{
    541 #if 0
    542859        struct groupchat *c;
    543860       
     
    557874        c->topic = g_strdup_printf( "BitlBee groupchat: \"%s\". Please keep in mind that root-commands won't work here. Have fun!", c->title );
    558875       
    559         if( set_getbool( &ic->bee->set, "debug" ) )
     876        if( set_getbool( &ic->irc->set, "debug" ) )
    560877                imcb_log( ic, "Creating new conversation: (id=%p,handle=%s)", c, handle );
    561878       
    562879        return c;
    563 #endif
    564         return NULL;
    565880}
    566881
    567882void imcb_chat_name_hint( struct groupchat *c, const char *name )
    568883{
    569 #if 0
    570884        if( !c->joined )
    571885        {
     
    593907                }
    594908        }
    595 #endif
    596909}
    597910
    598911void imcb_chat_free( struct groupchat *c )
    599912{
    600 #if 0
    601913        struct im_connection *ic = c->ic;
    602914        struct groupchat *l;
    603915        GList *ir;
    604916       
    605         if( set_getbool( &ic->bee->set, "debug" ) )
     917        if( set_getbool( &ic->irc->set, "debug" ) )
    606918                imcb_log( ic, "You were removed from conversation %p", c );
    607919       
     
    636948                g_free( c );
    637949        }
    638 #endif
    639950}
    640951
    641952void imcb_chat_msg( struct groupchat *c, const char *who, char *msg, uint32_t flags, time_t sent_at )
    642953{
    643 #if 0
    644954        struct im_connection *ic = c->ic;
    645955        char *wrapped;
     
    652962        u = user_findhandle( ic, who );
    653963       
    654         if( ( g_strcasecmp( set_getstr( &ic->bee->set, "strip_html" ), "always" ) == 0 ) ||
    655             ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->bee->set, "strip_html" ) ) )
     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" ) ) )
    656966                strip_html( msg );
    657967       
     
    670980        }
    671981        g_free( wrapped );
    672 #endif
    673982}
    674983
    675984void imcb_chat_log( struct groupchat *c, char *format, ... )
    676985{
    677 #if 0
    678986        irc_t *irc = c->ic->irc;
    679987        va_list params;
     
    690998       
    691999        g_free( text );
    692 #endif
    6931000}
    6941001
    6951002void imcb_chat_topic( struct groupchat *c, char *who, char *topic, time_t set_at )
    6961003{
    697 #if 0
    6981004        struct im_connection *ic = c->ic;
    6991005        user_t *u = NULL;
     
    7061012                u = user_findhandle( ic, who );
    7071013       
    708         if( ( g_strcasecmp( set_getstr( &ic->bee->set, "strip_html" ), "always" ) == 0 ) ||
    709             ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->bee->set, "strip_html" ) ) )
     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" ) ) )
    7101016                strip_html( topic );
    7111017       
     
    7151021        if( c->joined && u )
    7161022                irc_write( ic->irc, ":%s!%s@%s TOPIC %s :%s", u->nick, u->user, u->host, c->channel, topic );
    717 #endif
    718 }
     1023}
     1024
     1025
     1026/* buddy_chat.c */
    7191027
    7201028void imcb_chat_add_buddy( struct groupchat *b, const char *handle )
    7211029{
    722 #if 0
    7231030        user_t *u = user_findhandle( b->ic, handle );
    7241031        int me = 0;
    7251032       
    726         if( set_getbool( &b->ic->bee->set, "debug" ) )
     1033        if( set_getbool( &b->ic->irc->set, "debug" ) )
    7271034                imcb_log( b->ic, "User %s added to conversation %p", handle, b );
    7281035       
     
    7511058                b->in_room = g_list_append( b->in_room, g_strdup( handle ) );
    7521059        }
    753 #endif
    7541060}
    7551061
     
    7571063void imcb_chat_remove_buddy( struct groupchat *b, const char *handle, const char *reason )
    7581064{
    759 #if 0
    7601065        user_t *u;
    7611066        int me = 0;
    7621067       
    763         if( set_getbool( &b->ic->bee->set, "debug" ) )
     1068        if( set_getbool( &b->ic->irc->set, "debug" ) )
    7641069                imcb_log( b->ic, "User %s removed from conversation %p (%s)", handle, b, reason ? reason : "" );
    7651070       
     
    7811086        if( me || ( remove_chat_buddy_silent( b, handle ) && b->joined && u ) )
    7821087                irc_part( b->ic->irc, u, b->channel );
    783 #endif
    784 }
    785 
    786 #if 0
     1088}
     1089
    7871090static int remove_chat_buddy_silent( struct groupchat *b, const char *handle )
    7881091{
     
    8031106        }
    8041107       
    805         return 0;
    806 }
    807 #endif
     1108        return( 0 );
     1109}
    8081110
    8091111
    8101112/* Misc. BitlBee stuff which shouldn't really be here */
    811 #if 0
     1113
    8121114char *set_eval_away_devoice( set_t *set, char *value )
    8131115{
     
    8221124        /* Horror.... */
    8231125       
    824         if( st != set_getbool( &irc->b->set, "away_devoice" ) )
     1126        if( st != set_getbool( &irc->set, "away_devoice" ) )
    8251127        {
    8261128                char list[80] = "";
     
    8641166        return value;
    8651167}
    866 #endif
     1168
     1169char *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
     1207static 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}
    8671257
    8681258/* The plan is to not allow straight calls to prpl functions anymore, but do
    8691259   them all from some wrappers. We'll start to define some down here: */
     1260
     1261int 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}
    8701277
    8711278int imc_chat_msg( struct groupchat *c, char *msg, int flags )
     
    8961303       
    8971304        away = set_getstr( &ic->acc->set, "away" ) ?
    898              : set_getstr( &ic->bee->set, "away" );
     1305             : set_getstr( &ic->irc->set, "away" );
    8991306        if( away && *away )
    9001307        {
     
    9071314                away = NULL;
    9081315                msg = set_getstr( &ic->acc->set, "status" ) ?
    909                     : set_getstr( &ic->bee->set, "status" );
     1316                    : set_getstr( &ic->irc->set, "status" );
    9101317        }
    9111318       
  • protocols/nogaim.h

    rf924563 r6824fb3  
    22  * BitlBee -- An IRC to other IM-networks gateway                     *
    33  *                                                                    *
    4   * Copyright 2002-2010 Wilmer van der Gaast and others                *
     4  * Copyright 2002-2004 Wilmer van der Gaast and others                *
    55  \********************************************************************/
    66
     
    4545#include "proxy.h"
    4646#include "query.h"
    47 #include "md5.h"
    48 #include "ft.h"
    4947
    5048#define BUDDY_ALIAS_MAXLEN 388   /* because MSN names can be 387 characters */
     
    8785       
    8886        /* BitlBee */
    89         bee_t *bee;
     87        irc_t *irc;
    9088       
    9189        struct groupchat *groupchats;
     
    230228        void (* auth_allow)     (struct im_connection *, const char *who);
    231229        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 );
    235230};
    236231
     
    286281G_MODULE_EXPORT void imcb_buddy_nick_hint( struct im_connection *ic, const char *handle, const char *nick );
    287282
     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 */
     288G_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. */
     291G_MODULE_EXPORT void imcb_buddy_msg( struct im_connection *ic, const char *handle, char *msg, uint32_t flags, time_t sent_at );
    288292G_MODULE_EXPORT void imcb_buddy_typing( struct im_connection *ic, char *handle, uint32_t flags );
    289 G_MODULE_EXPORT struct bee_user *imcb_buddy_by_handle( struct im_connection *ic, const char *handle );
    290293G_MODULE_EXPORT void imcb_clean_handle( struct im_connection *ic, char *handle );
    291294
     
    313316/* Actions, or whatever. */
    314317int imc_away_send_update( struct im_connection *ic );
     318int imc_buddy_msg( struct im_connection *ic, char *handle, char *msg, int flags );
    315319int imc_chat_msg( struct groupchat *c, char *msg, int flags );
    316320
     
    321325
    322326/* Misc. stuff */
     327char *set_eval_timezone( set_t *set, char *value );
    323328char *set_eval_away_devoice( set_t *set, char *value );
    324329gboolean auto_reconnect( gpointer data, gint fd, b_input_condition cond );
  • protocols/oscar/oscar.c

    rf924563 r6824fb3  
    11901190        aim_ssi_auth_reply(od->sess, od->conn, uin, 1, "");
    11911191        // aim_send_im_ch4(od->sess, uin, AIM_ICQMSG_AUTHGRANTED, &message);
    1192         imcb_ask_add(data->ic, uin, NULL);
     1192        if(imcb_find_buddy(data->ic, uin) == NULL)
     1193                imcb_ask_add(data->ic, uin, NULL);
    11931194       
    11941195        g_free(uin);
     
    19511952        struct oscar_data *odata = (struct oscar_data *)g->proto_data;
    19521953        if (odata->icq) {
    1953                 /** FIXME(wilmer): Hmm, lost the ability to get away msgs here, do we care to get that back?
    19541954                struct buddy *budlight = imcb_find_buddy(g, who);
    19551955                if (budlight)
     
    19571957                                if (budlight->caps & AIM_CAPS_ICQSERVERRELAY)
    19581958                                        aim_send_im_ch2_geticqmessage(odata->sess, who, (budlight->uc & 0xff80) >> 7);
    1959                 */
    19601959        } else
    19611960                aim_getinfo(odata->sess, odata->conn, who, AIM_GETINFO_AWAYMESSAGE);
     
    20952094                switch (curitem->type) {
    20962095                        case 0x0000: /* Buddy */
    2097                                 if ((curitem->name) && (!imcb_buddy_by_handle(ic, nrm))) {
     2096                                if ((curitem->name) && (!imcb_find_buddy(ic, nrm))) {
    20982097                                        char *realname = NULL;
    20992098
  • protocols/twitter/twitter_lib.c

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

    rf924563 r6824fb3  
    6464        }
    6565       
    66         if( g_strcasecmp( set_getstr( &irc->b->set, "query_order" ), "lifo" ) == 0 || irc->queries == q )
     66        if( g_strcasecmp( set_getstr( &irc->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->b->set, "query_order" ), "fifo" ) == 0 )
     181        if( g_strcasecmp( set_getstr( &irc->set, "query_order" ), "fifo" ) == 0 )
    182182                q = irc->queries;
    183183        else
  • root_commands.c

    rf924563 r6824fb3  
    2626#define BITLBEE_CORE
    2727#include "commands.h"
     28#include "crypting.h"
    2829#include "bitlbee.h"
    2930#include "help.h"
     
    3233#include <string.h>
    3334
    34 void root_command_string( irc_t *irc, char *command )
    35 {
    36         root_command( irc, split_command_parts( command ) );
     35void 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 );
    3779}
    3880
     
    5193void root_command( irc_t *irc, char *cmd[] )
    5294{       
    53         int i, len;
     95        int i;
    5496       
    5597        if( !cmd[0] )
    5698                return;
    5799       
    58         len = strlen( cmd[0] );
    59100        for( i = 0; commands[i].command; i++ )
    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                        
     101                if( g_strcasecmp( commands[i].command, cmd[0] ) == 0 )
     102                {
    67103                        MIN_ARGS( commands[i].required_parameters );
    68104                       
     
    126162                irc->status |= USTATUS_IDENTIFIED;
    127163                irc_umode_set( irc, "+R", 1 );
    128                 if( set_getbool( &irc->b->set, "auto_connect" ) )
     164                if( set_getbool( &irc->set, "auto_connect" ) )
    129165                        cmd_account( irc, account_on );
    130166                break;
     
    166202        storage_status_t status;
    167203       
    168         status = storage_remove (irc->user->nick, cmd[1]);
     204        status = storage_remove (irc->nick, cmd[1]);
    169205        switch (status) {
    170206        case STORAGE_NO_SUCH_USER:
     
    178214                irc->status &= ~USTATUS_IDENTIFIED;
    179215                irc_umode_set( irc, "-R", 1 );
    180                 irc_usermsg( irc, "Account `%s' removed", irc->user->nick );
     216                irc_usermsg( irc, "Account `%s' removed", irc->nick );
    181217                break;
    182218        default:
     
    186222}
    187223
    188 static 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!" );
    196 }
    197 
    198224struct cmd_account_del_data
    199225{
     
    207233        account_t *a;
    208234       
    209         for( a = cad->irc->b->accounts; a && a != cad->a; a = a->next );
     235        for( a = cad->irc->accounts; a && a != cad->a; a = a->next );
    210236       
    211237        if( a == NULL )
     
    219245        else
    220246        {
    221                 account_del( cad->irc->b, a );
     247                account_del( cad->irc, a );
    222248                irc_usermsg( cad->irc, "Account deleted" );
    223249        }
     
    260286                set_name = set_full;
    261287               
    262                 head = &irc->b->set;
     288                head = &irc->set;
    263289        }
    264290        else
     
    331357        account_t *a;
    332358       
    333         if( ( a = account_get( irc->b, id ) ) )
     359        if( ( a = account_get( irc, id ) ) )
    334360                return &a->set;
    335361        else
     
    379405                }
    380406
    381                 a = account_add( irc->b, prpl, cmd[3], cmd[4] );
     407                a = account_add( irc, prpl, cmd[3], cmd[4] );
    382408                if( cmd[5] )
    383409                {
     
    393419                MIN_ARGS( 2 );
    394420
    395                 if( !( a = account_get( irc->b, cmd[2] ) ) )
     421                if( !( a = account_get( irc, cmd[2] ) ) )
    396422                {
    397423                        irc_usermsg( irc, "Invalid account" );
     
    415441                                               "set' command. Are you sure you want to delete this "
    416442                                               "account?", a->prpl->name, a->user );
    417                         //query_add( irc, NULL, msg, cmd_account_del_yes, cmd_account_del_no, cad );
     443                        query_add( irc, NULL, msg, cmd_account_del_yes, cmd_account_del_no, cad );
    418444                        g_free( msg );
    419445                }
     
    426452                        irc_usermsg( irc, "Account list:" );
    427453               
    428                 for( a = irc->b->accounts; a; a = a->next )
     454                for( a = irc->accounts; a; a = a->next )
    429455                {
    430456                        char *con;
     
    449475                if( cmd[2] )
    450476                {
    451                         if( ( a = account_get( irc->b, cmd[2] ) ) )
     477                        if( ( a = account_get( irc, cmd[2] ) ) )
    452478                        {
    453479                                if( a->ic )
     
    458484                                else
    459485                                {
    460                                         account_on( irc->b, a );
     486                                        account_on( irc, a );
    461487                                }
    462488                        }
     
    469495                else
    470496                {
    471                         if ( irc->b->accounts )
    472                         {
     497                        if ( irc->accounts ) {
    473498                                irc_usermsg( irc, "Trying to get all accounts connected..." );
    474499                       
    475                                 for( a = irc->b->accounts; a; a = a->next )
     500                                for( a = irc->accounts; a; a = a->next )
    476501                                        if( !a->ic && a->auto_connect )
    477                                                 account_on( irc->b, a );
     502                                                account_on( irc, a );
    478503                        }
    479504                        else
     
    489514                        irc_usermsg( irc, "Deactivating all active (re)connections..." );
    490515                       
    491                         for( a = irc->b->accounts; a; a = a->next )
     516                        for( a = irc->accounts; a; a = a->next )
    492517                        {
    493518                                if( a->ic )
    494                                         account_off( irc->b, a );
     519                                        account_off( irc, a );
    495520                                else if( a->reconnect )
    496521                                        cancel_auto_reconnect( a );
    497522                        }
    498523                }
    499                 else if( ( a = account_get( irc->b, cmd[2] ) ) )
     524                else if( ( a = account_get( irc, cmd[2] ) ) )
    500525                {
    501526                        if( a->ic )
    502527                        {
    503                                 account_off( irc->b, a );
     528                                account_off( irc, a );
    504529                        }
    505530                        else if( a->reconnect )
     
    544569        }
    545570       
    546         if( !( a = account_get( irc->b, cmd[1] ) ) )
     571        if( !( a = account_get( irc, cmd[1] ) ) )
    547572        {
    548573                irc_usermsg( irc, "Invalid account" );
     
    562587                        return;
    563588                }
    564                 else if( irc_user_by_name( irc, cmd[3] ) )
     589                else if( user_find( irc, cmd[3] ) )
    565590                {
    566591                        irc_usermsg( irc, "The requested nick `%s' already exists", cmd[3] );
     
    576601                a->ic->acc->prpl->add_buddy( a->ic, cmd[2], NULL );
    577602        else
    578                 /* Only for add -tmp. For regular adds, this callback will
    579                    be called once the IM server confirms. */
    580                 bee_user_new( irc->b, a->ic, cmd[2] );
     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 );
    581607       
    582608        irc_usermsg( irc, "Adding `%s' to your contact list", cmd[2]  );
    583 }
    584 
    585 static void cmd_remove( irc_t *irc, char **cmd )
    586 {
    587         irc_user_t *iu;
    588         bee_user_t *bu;
    589         char *s;
    590        
    591         if( !( iu = irc_user_by_name( irc, cmd[1] ) ) || !( bu = iu->bu ) )
    592         {
    593                 irc_usermsg( irc, "Buddy `%s' not found", cmd[1] );
    594                 return;
    595         }
    596         s = g_strdup( bu->handle );
    597        
    598         bu->ic->acc->prpl->remove_buddy( bu->ic, bu->handle, NULL );
    599         nick_del( bu->ic->acc, bu->handle );
    600         //TODO(wilmer): bee_user_free() and/or let the IM mod do it? irc_user_free( irc, cmd[1] );
    601        
    602         irc_usermsg( irc, "Buddy `%s' (nick %s) removed from contact list", s, cmd[1] );
    603         g_free( s );
    604        
    605         return;
    606609}
    607610
     
    613616        if( !cmd[2] )
    614617        {
    615                 irc_user_t *iu = irc_user_by_name( irc, cmd[1] );
    616                 if( !iu || !iu->bu )
     618                user_t *u = user_find( irc, cmd[1] );
     619                if( !u || !u->ic )
    617620                {
    618621                        irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
    619622                        return;
    620623                }
    621                 ic = iu->bu->ic;
    622                 cmd[2] = iu->bu->handle;
    623         }
    624         else if( !( a = account_get( irc->b, cmd[1] ) ) )
     624                ic = u->ic;
     625                cmd[2] = u->handle;
     626        }
     627        else if( !( a = account_get( irc, cmd[1] ) ) )
    625628        {
    626629                irc_usermsg( irc, "Invalid account" );
     
    645648static void cmd_rename( irc_t *irc, char **cmd )
    646649{
    647         irc_user_t *iu;
    648        
    649         iu = irc_user_by_name( irc, cmd[1] );
    650        
    651         if( iu == NULL )
     650        user_t *u;
     651       
     652        if( g_strcasecmp( cmd[1], irc->nick ) == 0 )
     653        {
     654                irc_usermsg( irc, "Nick `%s' can't be changed", cmd[1] );
     655        }
     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 ) )
     672        {
     673                irc_usermsg( irc, "Nick `%s' already exists", cmd[2] );
     674        }
     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] ) ) )
    652680        {
    653681                irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
    654682        }
    655         else if( iu == irc->user )
    656         {
    657                 irc_usermsg( irc, "Nick `%s' can't be changed", cmd[1] );
    658         }
    659         else if( !nick_ok( cmd[2] ) )
    660         {
    661                 irc_usermsg( irc, "Nick `%s' is invalid", cmd[2] );
    662         }
    663         else if( irc_user_by_name( irc, cmd[2] ) )
    664         {
    665                 irc_usermsg( irc, "Nick `%s' already exists", cmd[2] );
    666         }
    667         else
    668         {
    669                 if( !irc_user_set_nick( iu, cmd[2] ) )
    670                 {
    671                         irc_usermsg( irc, "Error while changing nick" );
    672                         return;
    673                 }
    674                
    675                 if( iu == irc->root )
    676                 {
     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                       
    677692                        /* If we're called internally (user did "set root_nick"),
    678693                           let's not go O(INF). :-) */
    679694                        if( strcmp( cmd[0], "set_rename" ) != 0 )
    680                                 set_setstr( &irc->b->set, "root_nick", cmd[2] );
    681                 }
    682                 else if( iu->bu )
    683                 {
    684                         nick_set( iu->bu->ic->acc, iu->bu->handle, cmd[2] );
     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] );
    685700                }
    686701               
     
    689704}
    690705
    691 #if 0
    692706char *set_eval_root_nick( set_t *set, char *new_nick )
    693707{
     
    717731        return strcmp( irc->channel, new_name ) == 0 ? new_name : SET_INVALID;
    718732}
    719 #endif
     733
     734static 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}
    720755
    721756static void cmd_block( irc_t *irc, char **cmd )
     
    724759        account_t *a;
    725760       
    726         if( !cmd[2] && ( a = account_get( irc->b, cmd[1] ) ) && a->ic )
     761        if( !cmd[2] && ( a = account_get( irc, cmd[1] ) ) && a->ic )
    727762        {
    728763                char *format;
     
    737772                for( l = a->ic->deny; l; l = l->next )
    738773                {
    739                         bee_user_t *bu = bee_user_by_handle( irc->b, a->ic, l->data );
    740                         irc_user_t *iu = bu ? bu->ui_data : NULL;
    741                         irc_usermsg( irc, format, l->data, iu ? iu->nick : "(none)" );
     774                        user_t *u = user_findhandle( a->ic, l->data );
     775                        irc_usermsg( irc, format, l->data, u ? u->nick : "(none)" );
    742776                }
    743777                irc_usermsg( irc, "End of list." );
     
    747781        else if( !cmd[2] )
    748782        {
    749                 irc_user_t *iu = irc_user_by_name( irc, cmd[1] );
    750                 if( !iu || !iu->bu )
     783                user_t *u = user_find( irc, cmd[1] );
     784                if( !u || !u->ic )
    751785                {
    752786                        irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
    753787                        return;
    754788                }
    755                 ic = iu->bu->ic;
    756                 cmd[2] = iu->bu->handle;
    757         }
    758         else if( !( a = account_get( irc->b, cmd[1] ) ) )
     789                ic = u->ic;
     790                cmd[2] = u->handle;
     791        }
     792        else if( !( a = account_get( irc, cmd[1] ) ) )
    759793        {
    760794                irc_usermsg( irc, "Invalid account" );
     
    784818        account_t *a;
    785819       
    786         if( !cmd[2] && ( a = account_get( irc->b, cmd[1] ) ) && a->ic )
     820        if( !cmd[2] && ( a = account_get( irc, cmd[1] ) ) && a->ic )
    787821        {
    788822                char *format;
     
    797831                for( l = a->ic->permit; l; l = l->next )
    798832                {
    799                         bee_user_t *bu = bee_user_by_handle( irc->b, a->ic, l->data );
    800                         irc_user_t *iu = bu ? bu->ui_data : NULL;
    801                         irc_usermsg( irc, format, l->data, iu ? iu->nick : "(none)" );
     833                        user_t *u = user_findhandle( a->ic, l->data );
     834                        irc_usermsg( irc, format, l->data, u ? u->nick : "(none)" );
    802835                }
    803836                irc_usermsg( irc, "End of list." );
     
    807840        else if( !cmd[2] )
    808841        {
    809                 irc_user_t *iu = irc_user_by_name( irc, cmd[1] );
    810                 if( !iu || !iu->bu )
     842                user_t *u = user_find( irc, cmd[1] );
     843                if( !u || !u->ic )
    811844                {
    812845                        irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
    813846                        return;
    814847                }
    815                 ic = iu->bu->ic;
    816                 cmd[2] = iu->bu->handle;
    817         }
    818         else if( !( a = account_get( irc->b, cmd[1] ) ) )
     848                ic = u->ic;
     849                cmd[2] = u->handle;
     850        }
     851        else if( !( a = account_get( irc, cmd[1] ) ) )
    819852        {
    820853                irc_usermsg( irc, "Invalid account" );
     
    883916}
    884917
     918static 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
    885928static void cmd_blist( irc_t *irc, char **cmd )
    886929{
    887930        int online = 0, away = 0, offline = 0;
    888         GSList *l;
     931        user_t *u;
    889932        char s[256];
    890933        char *format;
     
    907950                format = "%-16.16s  %-40.40s  %s";
    908951       
    909         irc_usermsg( irc, format, "Nick", "Handle/Account", "Status" );
    910        
    911         for( l = irc->users; l; l = l->next )
    912         {
    913                 irc_user_t *iu = l->data;
    914                 bee_user_t *bu = iu->bu;
    915                
    916                 if( !bu || ( bu->flags & ( BEE_USER_ONLINE | BEE_USER_AWAY ) ) != BEE_USER_ONLINE )
    917                         continue;
    918                
     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        {
    919956                if( online == 1 )
    920957                {
    921958                        char st[256] = "Online";
    922959                       
    923                         if( bu->status_msg )
    924                                 g_snprintf( st, sizeof( st ) - 1, "Online (%s)", bu->status_msg );
    925                        
    926                         g_snprintf( s, sizeof( s ) - 1, "%s %s(%s)", bu->handle, bu->ic->acc->prpl->name, bu->ic->acc->user );
    927                         irc_usermsg( irc, format, iu->nick, s, st );
     960                        if( u->status_msg )
     961                                g_snprintf( st, sizeof( st ) - 1, "Online (%s)", u->status_msg );
     962                       
     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 );
    928965                }
    929966               
     
    931968        }
    932969
    933         for( l = irc->users; l; l = l->next )
    934         {
    935                 irc_user_t *iu = l->data;
    936                 bee_user_t *bu = iu->bu;
    937                
    938                 if( !bu || !( bu->flags & BEE_USER_ONLINE ) || !( bu->flags & BEE_USER_AWAY ) )
    939                         continue;
    940                
     970        for( u = irc->users; u; u = u->next ) if( u->ic && u->online && u->away )
     971        {
    941972                if( away == 1 )
    942973                {
    943                         g_snprintf( s, sizeof( s ) - 1, "%s %s(%s)", bu->handle, bu->ic->acc->prpl->name, bu->ic->acc->user );
    944                         irc_usermsg( irc, format, iu->nick, s, irc_user_get_away( iu ) );
     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 );
    945976                }
    946977                n_away ++;
    947978        }
    948979       
    949         for( l = irc->users; l; l = l->next )
    950         {
    951                 irc_user_t *iu = l->data;
    952                 bee_user_t *bu = iu->bu;
    953                
    954                 if( !bu || bu->flags & BEE_USER_ONLINE )
    955                         continue;
    956                
     980        for( u = irc->users; u; u = u->next ) if( u->ic && !u->online )
     981        {
    957982                if( offline == 1 )
    958983                {
    959                         g_snprintf( s, sizeof( s ) - 1, "%s %s(%s)", bu->handle, bu->ic->acc->prpl->name, bu->ic->acc->user );
    960                         irc_usermsg( irc, format, iu->nick, s, "Offline" );
     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" );
    961986                }
    962987                n_offline ++;
     
    964989       
    965990        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
     993static 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        }
    9661019}
    9671020
     
    9861039}
    9871040
    988 #if 0
     1041static 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
    9891047static set_t **cmd_chat_set_findhead( irc_t *irc, char *id )
    9901048{
     
    10981156        }
    10991157}
    1100 #endif
    1101 
    1102 static void cmd_transfer( irc_t *irc, char **cmd )
    1103 {
    1104         GSList *files = irc->file_transfers;
    1105         enum { LIST, REJECT, CANCEL };
    1106         int subcmd = LIST;
    1107         int fid;
    1108 
    1109         if( !files )
    1110         {
    1111                 irc_usermsg( irc, "No pending transfers" );
    1112                 return;
    1113         }
    1114 
    1115         if( cmd[1] && ( strcmp( cmd[1], "reject" ) == 0 ) )
    1116         {
    1117                 subcmd = REJECT;
    1118         }
    1119         else if( cmd[1] && ( strcmp( cmd[1], "cancel" ) == 0 ) &&
    1120                  cmd[2] && ( sscanf( cmd[2], "%d", &fid ) == 1 ) )
    1121         {
    1122                 subcmd = CANCEL;
    1123         }
    1124 
    1125         for( ; files; files = g_slist_next( files ) )
    1126         {
    1127                 file_transfer_t *file = files->data;
    1128                
    1129                 switch( subcmd ) {
    1130                 case LIST:
    1131                         if ( file->status == FT_STATUS_LISTENING )
    1132                                 irc_usermsg( irc,
    1133                                         "Pending file(id %d): %s (Listening...)", file->local_id, file->file_name);
    1134                         else
    1135                         {
    1136                                 int kb_per_s = 0;
    1137                                 time_t diff = time( NULL ) - file->started ? : 1;
    1138                                 if ( ( file->started > 0 ) && ( file->bytes_transferred > 0 ) )
    1139                                         kb_per_s = file->bytes_transferred / 1024 / diff;
    1140                                        
    1141                                 irc_usermsg( irc,
    1142                                         "Pending file(id %d): %s (%10zd/%zd kb, %d kb/s)", file->local_id, file->file_name,
    1143                                         file->bytes_transferred/1024, file->file_size/1024, kb_per_s);
    1144                         }
    1145                         break;
    1146                 case REJECT:
    1147                         if( file->status == FT_STATUS_LISTENING )
    1148                         {
    1149                                 irc_usermsg( irc, "Rejecting file transfer for %s", file->file_name );
    1150                                 imcb_file_canceled( file->ic, file, "Denied by user" );
    1151                         }
    1152                         break;
    1153                 case CANCEL:
    1154                         if( file->local_id == fid )
    1155                         {
    1156                                 irc_usermsg( irc, "Canceling file transfer for %s", file->file_name );
    1157                                 imcb_file_canceled( file->ic, file, "Canceled by user" );
    1158                         }
    1159                         break;
    1160                 }
    1161         }
    1162 }
    1163 
    1164 /* IMPORTANT: Keep this list sorted! The short command logic needs that. */
     1158
    11651159const command_t commands[] = {
     1160        { "help",           0, cmd_help,           0 },
     1161        { "identify",       1, cmd_identify,       0 },
     1162        { "register",       1, cmd_register,       0 },
     1163        { "drop",           1, cmd_drop,           0 },
    11661164        { "account",        1, cmd_account,        0 },
    11671165        { "add",            2, cmd_add,            0 },
     1166        { "info",           1, cmd_info,           0 },
     1167        { "rename",         2, cmd_rename,         0 },
     1168        { "remove",         1, cmd_remove,         0 },
     1169        { "block",          1, cmd_block,          0 },
    11681170        { "allow",          1, cmd_allow,          0 },
    1169         { "blist",          0, cmd_blist,          0 },
    1170         { "block",          1, cmd_block,          0 },
    1171         { "drop",           1, cmd_drop,           0 },
    1172         { "ft",             0, cmd_transfer,       0 },
    1173         { "help",           0, cmd_help,           0 },
    1174         { "identify",       1, cmd_identify,       0 },
    1175         { "info",           1, cmd_info,           0 },
    1176         { "no",             0, cmd_yesno,          0 },
    1177         { "qlist",          0, cmd_qlist,          0 },
    1178         { "register",       1, cmd_register,       0 },
    1179         { "remove",         1, cmd_remove,         0 },
    1180         { "rename",         2, cmd_rename,         0 },
    11811171        { "save",           0, cmd_save,           0 },
    11821172        { "set",            0, cmd_set,            0 },
    1183         { "transfer",       0, cmd_transfer,       0 },
    11841173        { "yes",            0, cmd_yesno,          0 },
    1185 #if 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 },
    11861179        { "chat",           1, cmd_chat,           0 },
    1187 #endif
    11881180        { NULL }
    11891181};
  • set.c

    rf924563 r6824fb3  
    225225}
    226226
    227 /*
    228227char *set_eval_ops( set_t *set, char *value )
    229228{
     
    247246        return value;
    248247}
    249 */
  • storage.c

    rf924563 r6824fb3  
    2828#define BITLBEE_CORE
    2929#include "bitlbee.h"
     30#include "crypting.h"
    3031
    3132extern storage_t storage_text;
     
    6566        storage_t *storage;
    6667       
     68        register_storage_backend(&storage_text);
    6769        register_storage_backend(&storage_xml);
    6870       
  • storage_xml.c

    rf924563 r6824fb3  
    147147                                         arc_decode( pass_cr, pass_len, &password, xd->given_pass ) )
    148148                {
    149                         xd->current_account = account_add( irc->b, prpl, handle, password );
     149                        xd->current_account = account_add( irc, 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->b->set;
     183                                xd->current_set_head = &xd->irc->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->user->nick, password, XML_PASS_UNKNOWN );
     355        return xml_load_real( irc, irc->nick, password, XML_PASS_UNKNOWN );
    356356}
    357357
     
    396396        md5_state_t md5_state;
    397397       
    398         path2 = g_strdup( irc->user->nick );
     398        path2 = g_strdup( irc->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->user->nick, pass_buf, XML_FORMAT_VERSION ) )
     424        if( !xml_printf( fd, 0, "<user nick=\"%s\" password=\"%s\" version=\"%d\">\n", irc->nick, pass_buf, XML_FORMAT_VERSION ) )
    425425                goto write_error;
    426426       
    427427        g_free( pass_buf );
    428428       
    429         for( set = irc->b->set; set; set = set->next )
     429        for( set = irc->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->b->accounts; acc; acc = acc->next )
     434        for( acc = irc->accounts; acc; acc = acc->next )
    435435        {
    436436                unsigned char *pass_cr;
     
    470470                        goto write_error;
    471471               
    472 #if 0
    473472                for( c = irc->chatrooms; c; c = c->next )
    474473                {
     
    489488                                goto write_error;
    490489                }
    491 #endif
    492490               
    493491                if( !xml_printf( fd, 1, "</account>\n" ) )
  • win32.c

    rf924563 r6824fb3  
    2727#include "bitlbee.h"
    2828#include "commands.h"
     29#include "crypting.h"
    2930#include "protocols/nogaim.h"
    3031#include "help.h"
Note: See TracChangeset for help on using the changeset viewer.