Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • irc.c

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