Changeset 3ddb7477 for irc.c


Ignore:
Timestamp:
2010-03-26T12:14:37Z (10 years ago)
Author:
Wilmer van der Gaast <wilmer@…>
Branches:
master
Children:
ebaebfe
Parents:
ba7d16f
Message:

One total mess that doesn't do much yet, but reorganised some stuff and
untying the IRC and the core parts a little bit. Lots of work left to do.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • irc.c

    rba7d16f r3ddb7477  
    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 "ipc.h"
    30 #include "dcc.h"
    31 
    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         GIConv ic, oc;
    55 
    56         if( g_strcasecmp( value, "none" ) == 0 )
    57                 value = g_strdup( "utf-8" );
    58 
    59         if( ( ic = g_iconv_open( "utf-8", value ) ) == (GIConv) -1 )
    60         {
    61                 return NULL;
    62         }
    63         if( ( oc = g_iconv_open( value, "utf-8" ) ) == (GIConv) -1 )
    64         {
    65                 g_iconv_close( ic );
    66                 return NULL;
    67         }
    68        
    69         if( irc->iconv != (GIConv) -1 )
    70                 g_iconv_close( irc->iconv );
    71         if( irc->oconv != (GIConv) -1 )
    72                 g_iconv_close( irc->oconv );
    73        
    74         irc->iconv = ic;
    75         irc->oconv = oc;
    76 
    77         return value;
    78 }
    79 
    80 static char *set_eval_away_status( set_t *set, char *value )
    81 {
    82         irc_t *irc = set->data;
    83         account_t *a;
    84        
    85         g_free( set->value );
    86         set->value = g_strdup( value );
    87        
    88         for( a = irc->accounts; a; a = a->next )
    89         {
    90                 struct im_connection *ic = a->ic;
    91                
    92                 if( ic && ic->flags & OPT_LOGGED_IN )
    93                         imc_away_send_update( ic );
    94         }
    95        
    96         return value;
    97 }
     27
     28GSList *irc_connection_list;
     29
     30static char *set_eval_charset( set_t *set, char *value );
    9831
    9932irc_t *irc_new( int fd )
     
    10235        struct sockaddr_storage sock;
    10336        socklen_t socklen = sizeof( sock );
     37        char *host = NULL, *myhost = NULL;
     38        irc_user_t *iu;
    10439        set_t *s;
     40        bee_t *b;
    10541       
    10642        irc = g_new0( irc_t, 1 );
     
    11450        irc->last_pong = gettime();
    11551       
    116         irc->userhash = g_hash_table_new( g_str_hash, g_str_equal );
     52        irc->nick_user_hash = g_hash_table_new( g_str_hash, g_str_equal );
    11753        irc->watches = g_hash_table_new( g_str_hash, g_str_equal );
    11854       
    11955        strcpy( irc->umode, UMODE );
    120         irc->mynick = g_strdup( ROOT_NICK );
    121         irc->channel = g_strdup( ROOT_CHAN );
    12256       
    12357        irc->iconv = (GIConv) -1;
     
    12660        if( global.conf->hostname )
    12761        {
    128                 irc->myhost = g_strdup( global.conf->hostname );
     62                myhost = g_strdup( global.conf->hostname );
    12963        }
    13064        else if( getsockname( irc->fd, (struct sockaddr*) &sock, &socklen ) == 0 )
     
    13569                                 NI_MAXHOST, NULL, 0, 0 ) == 0 )
    13670                {
    137                         irc->myhost = g_strdup( ipv6_unwrap( buf ) );
     71                        myhost = g_strdup( ipv6_unwrap( buf ) );
    13872                }
    13973        }
     
    14680                                 NI_MAXHOST, NULL, 0, 0 ) == 0 )
    14781                {
    148                         irc->host = g_strdup( ipv6_unwrap( buf ) );
    149                 }
    150         }
    151        
    152         if( irc->host == NULL )
    153                 irc->host = g_strdup( "localhost.localdomain" );
    154         if( irc->myhost == NULL )
    155                 irc->myhost = g_strdup( "localhost.localdomain" );
    156        
    157         if( global.conf->ping_interval > 0 && global.conf->ping_timeout > 0 )
    158                 irc->ping_source_id = b_timeout_add( global.conf->ping_interval * 1000, irc_userping, irc );
    159        
    160         irc_write( irc, ":%s NOTICE AUTH :%s", irc->myhost, "BitlBee-IRCd initialized, please go on" );
     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" );
     90       
     91        //if( global.conf->ping_interval > 0 && global.conf->ping_timeout > 0 )
     92        //      irc->ping_source_id = b_timeout_add( global.conf->ping_interval * 1000, irc_userping, irc );
    16193
    16294        irc_connection_list = g_slist_append( irc_connection_list, irc );
    16395       
    164         s = set_add( &irc->set, "away", NULL,  set_eval_away_status, irc );
    165         s->flags |= SET_NULL_OK;
    166         s = set_add( &irc->set, "away_devoice", "true",  set_eval_away_devoice, irc );
    167         s = set_add( &irc->set, "auto_connect", "true", set_eval_bool, irc );
    168         s = set_add( &irc->set, "auto_reconnect", "true", set_eval_bool, irc );
    169         s = set_add( &irc->set, "auto_reconnect_delay", "5*3<900", set_eval_account_reconnect_delay, irc );
    170         s = set_add( &irc->set, "buddy_sendbuffer", "false", set_eval_bool, irc );
    171         s = set_add( &irc->set, "buddy_sendbuffer_delay", "200", set_eval_int, irc );
    172         s = set_add( &irc->set, "charset", "utf-8", set_eval_charset, irc );
    173         s = set_add( &irc->set, "control_channel", irc->channel, set_eval_control_channel, irc );
    174         s = set_add( &irc->set, "debug", "false", set_eval_bool, irc );
    175         s = set_add( &irc->set, "default_target", "root", NULL, irc );
    176         s = set_add( &irc->set, "display_namechanges", "false", set_eval_bool, irc );
    177         s = set_add( &irc->set, "handle_unknown", "root", NULL, irc );
    178         s = set_add( &irc->set, "lcnicks", "true", set_eval_bool, irc );
    179         s = set_add( &irc->set, "ops", "both", set_eval_ops, irc );
    180         s = set_add( &irc->set, "password", NULL, set_eval_password, irc );
    181         s->flags |= SET_NULL_OK;
    182         s = set_add( &irc->set, "private", "true", set_eval_bool, irc );
    183         s = set_add( &irc->set, "query_order", "lifo", NULL, irc );
    184         s = set_add( &irc->set, "root_nick", irc->mynick, set_eval_root_nick, irc );
    185         s = set_add( &irc->set, "save_on_quit", "true", set_eval_bool, irc );
    186         s = set_add( &irc->set, "simulate_netsplit", "true", set_eval_bool, irc );
    187         s = set_add( &irc->set, "status", NULL,  set_eval_away_status, irc );
    188         s->flags |= SET_NULL_OK;
    189         s = set_add( &irc->set, "strip_html", "true", NULL, irc );
    190         s = set_add( &irc->set, "to_char", ": ", set_eval_to_char, irc );
    191         s = set_add( &irc->set, "typing_notice", "false", set_eval_bool, irc );
    192        
    193         conf_loaddefaults( irc );
     96        b = irc->b = bee_new();
     97       
     98        s = set_add( &b->set, "away_devoice", "true", NULL/*set_eval_away_devoice*/, irc );
     99        s = set_add( &b->set, "buddy_sendbuffer", "false", set_eval_bool, irc );
     100        s = set_add( &b->set, "buddy_sendbuffer_delay", "200", set_eval_int, irc );
     101        s = set_add( &b->set, "charset", "utf-8", set_eval_charset, irc );
     102        //s = set_add( &b->set, "control_channel", irc->channel, NULL/*set_eval_control_channel*/, irc );
     103        s = set_add( &b->set, "default_target", "root", NULL, irc );
     104        s = set_add( &b->set, "display_namechanges", "false", set_eval_bool, irc );
     105        s = set_add( &b->set, "handle_unknown", "root", NULL, irc );
     106        s = set_add( &b->set, "lcnicks", "true", set_eval_bool, irc );
     107        s = set_add( &b->set, "ops", "both", NULL/*set_eval_ops*/, irc );
     108        s = set_add( &b->set, "private", "true", set_eval_bool, irc );
     109        s = set_add( &b->set, "query_order", "lifo", NULL, irc );
     110        s = set_add( &b->set, "root_nick", ROOT_NICK, NULL/*set_eval_root_nick*/, irc );
     111        s = set_add( &b->set, "simulate_netsplit", "true", set_eval_bool, irc );
     112        s = set_add( &b->set, "to_char", ": ", set_eval_to_char, irc );
     113        s = set_add( &b->set, "typing_notice", "false", set_eval_bool, irc );
     114
     115        irc->root = iu = irc_user_new( irc, ROOT_NICK );
     116        iu->host = g_strdup( myhost );
     117        iu->fullname = g_strdup( ROOT_FN );
     118       
     119        iu = irc_user_new( irc, NS_NICK );
     120        iu->host = g_strdup( myhost );
     121        iu->fullname = g_strdup( ROOT_FN );
     122       
     123        irc->user = g_new0( irc_user_t, 1 );
     124        irc->user->host = g_strdup( host );
     125       
     126        conf_loaddefaults( b );
    194127       
    195128        /* Evaluator sets the iconv/oconv structures. */
    196         set_eval_charset( set_find( &irc->set, "charset" ), set_getstr( &irc->set, "charset" ) );
    197        
    198         return( irc );
     129        set_eval_charset( set_find( &b->set, "charset" ), set_getstr( &b->set, "charset" ) );
     130       
     131        irc_write( irc, ":%s NOTICE AUTH :%s", irc->root->host, "BitlBee-IRCd initialized, please go on" );
     132       
     133        return irc;
    199134}
    200135
     
    217152               
    218153                ipc_to_master_str( "OPERMSG :Client exiting: %s@%s [%s]\r\n",
    219                                    irc->nick ? irc->nick : "(NONE)", irc->host, reason );
     154                                   irc->user->nick ? irc->user->nick : "(NONE)", irc->root->host, reason );
    220155               
    221156                g_free( reason );
     
    227162               
    228163                ipc_to_master_str( "OPERMSG :Client exiting: %s@%s [%s]\r\n",
    229                                    irc->nick ? irc->nick : "(NONE)", irc->host, "No reason given" );
     164                                   irc->user->nick ? irc->user->nick : "(NONE)", irc->root->host, "No reason given" );
    230165        }
    231166       
     
    248183}
    249184
    250 static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data )
    251 {
    252         g_free( key );
    253        
    254         return( TRUE );
    255 }
    256 
    257 /* Because we have no garbage collection, this is quite annoying */
     185static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data );
     186
    258187void irc_free( irc_t * irc )
    259188{
    260         user_t *user, *usertmp;
    261        
    262189        log_message( LOGLVL_INFO, "Destroying connection with fd %d", irc->fd );
    263190       
    264         if( irc->status & USTATUS_IDENTIFIED && set_getbool( &irc->set, "save_on_quit" ) )
     191        /*
     192        if( irc->status & USTATUS_IDENTIFIED && set_getbool( &irc->b->set, "save_on_quit" ) )
    265193                if( storage_save( irc, NULL, TRUE ) != STORAGE_OK )
    266194                        irc_usermsg( irc, "Error while saving settings!" );
     195        */
    267196       
    268197        irc_connection_list = g_slist_remove( irc_connection_list, irc );
    269198       
    270         while( irc->accounts )
    271         {
    272                 if( irc->accounts->ic )
    273                         imc_logout( irc->accounts->ic, FALSE );
    274                 else if( irc->accounts->reconnect )
    275                         cancel_auto_reconnect( irc->accounts );
    276                
    277                 if( irc->accounts->ic == NULL )
    278                         account_del( irc, irc->accounts );
    279                 else
    280                         /* Nasty hack, but account_del() doesn't work in this
    281                            case and we don't want infinite loops, do we? ;-) */
    282                         irc->accounts = irc->accounts->next;
    283         }
    284        
     199        /*
    285200        while( irc->queries != NULL )
    286201                query_del( irc, irc->queries );
    287        
    288         while( irc->set )
    289                 set_del( &irc->set, irc->set->key );
    290        
    291         if (irc->users != NULL)
    292         {
    293                 user = irc->users;
    294                 while( user != NULL )
    295                 {
    296                         g_free( user->nick );
    297                         g_free( user->away );
    298                         g_free( user->handle );
    299                         if( user->user != user->nick ) g_free( user->user );
    300                         if( user->host != user->nick ) g_free( user->host );
    301                         if( user->realname != user->nick ) g_free( user->realname );
    302                         b_event_remove( user->sendbuf_timer );
    303                                        
    304                         usertmp = user;
    305                         user = user->next;
    306                         g_free( usertmp );
    307                 }
    308         }
     202        */
     203       
     204        while( irc->users )
     205                irc_user_free( irc, irc->users->data );
    309206       
    310207        if( irc->ping_source_id > 0 )
     
    318215        irc->fd = -1;
    319216       
    320         g_hash_table_foreach_remove( irc->userhash, irc_free_hashkey, NULL );
    321         g_hash_table_destroy( irc->userhash );
     217        g_hash_table_foreach_remove( irc->nick_user_hash, irc_free_hashkey, NULL );
     218        g_hash_table_destroy( irc->nick_user_hash );
    322219       
    323220        g_hash_table_foreach_remove( irc->watches, irc_free_hashkey, NULL );
     
    332229        g_free( irc->readbuffer );
    333230       
    334         g_free( irc->nick );
    335         g_free( irc->user );
    336         g_free( irc->host );
    337         g_free( irc->realname );
    338231        g_free( irc->password );
    339        
    340         g_free( irc->myhost );
    341         g_free( irc->mynick );
    342        
    343         g_free( irc->channel );
    344        
    345         g_free( irc->last_target );
    346232       
    347233        g_free( irc );
     
    355241}
    356242
    357 /* USE WITH CAUTION!
    358    Sets pass without checking */
    359 void irc_setpass (irc_t *irc, const char *pass)
    360 {
    361         g_free (irc->password);
    362        
    363         if (pass) {
    364                 irc->password = g_strdup (pass);
    365         } else {
    366                 irc->password = NULL;
    367         }
    368 }
     243static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data )
     244{
     245        g_free( key );
     246       
     247        return( TRUE );
     248}
     249
     250static char **irc_splitlines( char *buffer );
    369251
    370252void irc_process( irc_t *irc )
     
    375257        if( irc->readbuffer != NULL )
    376258        {
    377                 lines = irc_tokenize( irc->readbuffer );
     259                lines = irc_splitlines( irc->readbuffer );
    378260               
    379261                for( i = 0; *lines[i] != '\0'; i ++ )
     
    412294                                                                  "`help set charset' for more information. Your "
    413295                                                                  "message was ignored.",
    414                                                                   set_getstr( &irc->set, "charset" ) );
     296                                                                  set_getstr( &irc->b->set, "charset" ) );
    415297                                               
    416298                                                g_free( conv );
     
    419301                                        else
    420302                                        {
    421                                                 irc_write( irc, ":%s NOTICE AUTH :%s", irc->myhost,
     303                                                irc_write( irc, ":%s NOTICE AUTH :%s", irc->root->host,
    422304                                                           "Warning: invalid characters received at login time." );
    423305                                               
     
    457339}
    458340
    459 /* Splits a long string into separate lines. The array is NULL-terminated and, unless the string
    460    contains an incomplete line at the end, ends with an empty string. */
    461 char **irc_tokenize( char *buffer )
     341/* Splits a long string into separate lines. The array is NULL-terminated
     342   and, unless the string contains an incomplete line at the end, ends with
     343   an empty string. Could use g_strsplit() but this one does it in-place.
     344   (So yes, it's destructive.) */
     345static char **irc_splitlines( char *buffer )
    462346{
    463347        int i, j, n = 3;
     
    590474}
    591475
    592 void irc_reply( irc_t *irc, int code, char *format, ... )
    593 {
    594         char text[IRC_MAX_LINE];
    595         va_list params;
    596        
    597         va_start( params, format );
    598         g_vsnprintf( text, IRC_MAX_LINE, format, params );
    599         va_end( params );
    600         irc_write( irc, ":%s %03d %s %s", irc->myhost, code, irc->nick?irc->nick:"*", text );
    601        
    602         return;
    603 }
    604 
    605 int irc_usermsg( irc_t *irc, char *format, ... )
    606 {
    607         char text[1024];
    608         va_list params;
    609         char is_private = 0;
    610         user_t *u;
    611        
    612         u = user_find( irc, irc->mynick );
    613         is_private = u->is_private;
    614        
    615         va_start( params, format );
    616         g_vsnprintf( text, sizeof( text ), format, params );
    617         va_end( params );
    618        
    619         return( irc_msgfrom( irc, u->nick, text ) );
    620 }
    621 
    622476void irc_write( irc_t *irc, char *format, ... )
    623477{
     
    630484        return;
    631485}
     486
     487void irc_write_all( int now, char *format, ... )
     488{
     489        va_list params;
     490        GSList *temp;   
     491       
     492        va_start( params, format );
     493       
     494        temp = irc_connection_list;
     495        while( temp != NULL )
     496        {
     497                irc_t *irc = temp->data;
     498               
     499                if( now )
     500                {
     501                        g_free( irc->sendbuffer );
     502                        irc->sendbuffer = g_strdup( "\r\n" );
     503                }
     504                irc_vawrite( temp->data, format, params );
     505                if( now )
     506                {
     507                        bitlbee_io_current_client_write( irc, irc->fd, GAIM_INPUT_WRITE );
     508                }
     509                temp = temp->next;
     510        }
     511       
     512        va_end( params );
     513        return;
     514}
    632515
    633516void irc_vawrite( irc_t *irc, char *format, va_list params )
     
    686569}
    687570
    688 void irc_write_all( int now, char *format, ... )
    689 {
    690         va_list params;
    691         GSList *temp;   
    692        
    693         va_start( params, format );
    694        
    695         temp = irc_connection_list;
    696         while( temp != NULL )
    697         {
    698                 irc_t *irc = temp->data;
    699                
    700                 if( now )
    701                 {
    702                         g_free( irc->sendbuffer );
    703                         irc->sendbuffer = g_strdup( "\r\n" );
    704                 }
    705                 irc_vawrite( temp->data, format, params );
    706                 if( now )
    707                 {
    708                         bitlbee_io_current_client_write( irc, irc->fd, GAIM_INPUT_WRITE );
    709                 }
    710                 temp = temp->next;
    711         }
    712        
    713         va_end( params );
    714         return;
    715 }
    716 
    717 void irc_names( irc_t *irc, char *channel )
    718 {
    719         user_t *u;
    720         char namelist[385] = "";
    721         struct groupchat *c = NULL;
    722         char *ops = set_getstr( &irc->set, "ops" );
    723        
    724         /* RFCs say there is no error reply allowed on NAMES, so when the
    725            channel is invalid, just give an empty reply. */
    726        
    727         if( g_strcasecmp( channel, irc->channel ) == 0 )
    728         {
    729                 for( u = irc->users; u; u = u->next ) if( u->online )
    730                 {
    731                         if( strlen( namelist ) + strlen( u->nick ) > sizeof( namelist ) - 4 )
    732                         {
    733                                 irc_reply( irc, 353, "= %s :%s", channel, namelist );
    734                                 *namelist = 0;
    735                         }
    736                        
    737                         if( u->ic && !u->away && set_getbool( &irc->set, "away_devoice" ) )
    738                                 strcat( namelist, "+" );
    739                         else if( ( strcmp( u->nick, irc->mynick ) == 0 && ( strcmp( ops, "root" ) == 0 || strcmp( ops, "both" ) == 0 ) ) ||
    740                                  ( strcmp( u->nick, irc->nick ) == 0 && ( strcmp( ops, "user" ) == 0 || strcmp( ops, "both" ) == 0 ) ) )
    741                                 strcat( namelist, "@" );
    742                        
    743                         strcat( namelist, u->nick );
    744                         strcat( namelist, " " );
    745                 }
    746         }
    747         else if( ( c = irc_chat_by_channel( irc, channel ) ) )
    748         {
    749                 GList *l;
    750                
    751                 /* root and the user aren't in the channel userlist but should
    752                    show up in /NAMES, so list them first: */
    753                 sprintf( namelist, "%s%s %s%s ", strcmp( ops, "root" ) == 0 || strcmp( ops, "both" ) ? "@" : "", irc->mynick,
    754                                                  strcmp( ops, "user" ) == 0 || strcmp( ops, "both" ) ? "@" : "", irc->nick );
    755                
    756                 for( l = c->in_room; l; l = l->next ) if( ( u = user_findhandle( c->ic, l->data ) ) )
    757                 {
    758                         if( strlen( namelist ) + strlen( u->nick ) > sizeof( namelist ) - 4 )
    759                         {
    760                                 irc_reply( irc, 353, "= %s :%s", channel, namelist );
    761                                 *namelist = 0;
    762                         }
    763                        
    764                         strcat( namelist, u->nick );
    765                         strcat( namelist, " " );
    766                 }
    767         }
    768        
    769         if( *namelist )
    770                 irc_reply( irc, 353, "= %s :%s", channel, namelist );
    771        
    772         irc_reply( irc, 366, "%s :End of /NAMES list", channel );
    773 }
    774 
    775571int irc_check_login( irc_t *irc )
    776572{
    777         if( irc->user && irc->nick )
     573        if( irc->user->user && irc->user->nick )
    778574        {
    779575                if( global.conf->authmode == AUTHMODE_CLOSED && !( irc->status & USTATUS_AUTHORIZED ) )
    780576                {
    781                         irc_reply( irc, 464, ":This server is password-protected." );
     577                        irc_send_num( irc, 464, ":This server is password-protected." );
    782578                        return 0;
    783579                }
    784580                else
    785581                {
    786                         irc_login( irc );
     582                        irc_send_login( irc );
    787583                        return 1;
    788584                }
     
    795591}
    796592
    797 void irc_login( irc_t *irc )
    798 {
    799         user_t *u;
    800        
    801         irc_reply( irc,   1, ":Welcome to the BitlBee gateway, %s", irc->nick );
    802         irc_reply( irc,   2, ":Host %s is running BitlBee " BITLBEE_VERSION " " ARCH "/" CPU ".", irc->myhost );
    803         irc_reply( irc,   3, ":%s", IRCD_INFO );
    804         irc_reply( irc,   4, "%s %s %s %s", irc->myhost, BITLBEE_VERSION, UMODES UMODES_PRIV, CMODES );
    805         irc_reply( irc,   5, "PREFIX=(ov)@+ CHANTYPES=%s CHANMODES=,,,%s NICKLEN=%d NETWORK=BitlBee "
    806                              "CASEMAPPING=rfc1459 MAXTARGETS=1 WATCH=128 :are supported by this server",
    807                              CTYPES, CMODES, MAX_NICK_LENGTH - 1 );
    808         irc_motd( irc );
    809         irc->umode[0] = '\0';
    810         irc_umode_set( irc, "+" UMODE, 1 );
    811 
    812         u = user_add( irc, irc->mynick );
    813         u->host = g_strdup( irc->myhost );
    814         u->realname = g_strdup( ROOT_FN );
    815         u->online = 1;
    816         u->send_handler = root_command_string;
    817         u->is_private = 0; /* [SH] The channel is root's personal playground. */
    818         irc_spawn( irc, u );
    819        
    820         u = user_add( irc, NS_NICK );
    821         u->host = g_strdup( irc->myhost );
    822         u->realname = g_strdup( ROOT_FN );
    823         u->online = 0;
    824         u->send_handler = root_command_string;
    825         u->is_private = 1; /* [SH] NickServ is not in the channel, so should always /query. */
    826        
    827         u = user_add( irc, irc->nick );
    828         u->user = g_strdup( irc->user );
    829         u->host = g_strdup( irc->host );
    830         u->realname = g_strdup( irc->realname );
    831         u->online = 1;
    832         irc_spawn( irc, u );
    833        
    834         irc_usermsg( irc, "Welcome to the BitlBee gateway!\n\n"
    835                           "If you've never used BitlBee before, please do read the help "
    836                           "information using the \x02help\x02 command. Lots of FAQs are "
    837                           "answered there.\n"
    838                           "If you already have an account on this server, just use the "
    839                           "\x02identify\x02 command to identify yourself." );
    840        
    841         if( global.conf->runmode == RUNMODE_FORKDAEMON || global.conf->runmode == RUNMODE_DAEMON )
    842                 ipc_to_master_str( "CLIENT %s %s :%s\r\n", irc->host, irc->nick, irc->realname );
    843        
    844         irc->status |= USTATUS_LOGGED_IN;
    845        
    846         /* This is for bug #209 (use PASS to identify to NickServ). */
    847         if( irc->password != NULL )
    848         {
    849                 char *send_cmd[] = { "identify", g_strdup( irc->password ), NULL };
    850                
    851                 irc_setpass( irc, NULL );
    852                 root_command( irc, send_cmd );
    853                 g_free( send_cmd[1] );
    854         }
    855 }
    856 
    857 void irc_motd( irc_t *irc )
    858 {
    859         int fd;
    860        
    861         fd = open( global.conf->motdfile, O_RDONLY );
    862         if( fd == -1 )
    863         {
    864                 irc_reply( irc, 422, ":We don't need MOTDs." );
    865         }
    866         else
    867         {
    868                 char linebuf[80];       /* Max. line length for MOTD's is 79 chars. It's what most IRC networks seem to do. */
    869                 char *add, max;
    870                 int len;
    871                
    872                 linebuf[79] = len = 0;
    873                 max = sizeof( linebuf ) - 1;
    874                
    875                 irc_reply( irc, 375, ":- %s Message Of The Day - ", irc->myhost );
    876                 while( read( fd, linebuf + len, 1 ) == 1 )
    877                 {
    878                         if( linebuf[len] == '\n' || len == max )
    879                         {
    880                                 linebuf[len] = 0;
    881                                 irc_reply( irc, 372, ":- %s", linebuf );
    882                                 len = 0;
    883                         }
    884                         else if( linebuf[len] == '%' )
    885                         {
    886                                 read( fd, linebuf + len, 1 );
    887                                 if( linebuf[len] == 'h' )
    888                                         add = irc->myhost;
    889                                 else if( linebuf[len] == 'v' )
    890                                         add = BITLBEE_VERSION;
    891                                 else if( linebuf[len] == 'n' )
    892                                         add = irc->nick;
    893                                 else
    894                                         add = "%";
    895                                
    896                                 strncpy( linebuf + len, add, max - len );
    897                                 while( linebuf[++len] );
    898                         }
    899                         else if( len < max )
    900                         {
    901                                 len ++;
    902                         }
    903                 }
    904                 irc_reply( irc, 376, ":End of MOTD" );
    905                 close( fd );
    906         }
    907 }
    908 
    909 void irc_topic( irc_t *irc, char *channel )
    910 {
    911         struct groupchat *c = irc_chat_by_channel( irc, channel );
    912        
    913         if( c && c->topic )
    914                 irc_reply( irc, 332, "%s :%s", channel, c->topic );
    915         else if( g_strcasecmp( channel, irc->channel ) == 0 )
    916                 irc_reply( irc, 332, "%s :%s", channel, CONTROL_TOPIC );
    917         else
    918                 irc_reply( irc, 331, "%s :No topic for this channel", channel );
    919 }
    920 
    921 void irc_umode_set( irc_t *irc, char *s, int allow_priv )
    922 {
    923         /* allow_priv: Set to 0 if s contains user input, 1 if you want
    924            to set a "privileged" mode (+o, +R, etc). */
    925         char m[256], st = 1, *t;
    926         int i;
    927         char changes[512], *p, st2 = 2;
    928         char badflag = 0;
    929        
    930         memset( m, 0, sizeof( m ) );
    931        
    932         for( t = irc->umode; *t; t ++ )
    933                 m[(int)*t] = 1;
    934 
    935         p = changes;
    936         for( t = s; *t; t ++ )
    937         {
    938                 if( *t == '+' || *t == '-' )
    939                         st = *t == '+';
    940                 else if( st == 0 || ( strchr( UMODES, *t ) || ( allow_priv && strchr( UMODES_PRIV, *t ) ) ) )
    941                 {
    942                         if( m[(int)*t] != st)
    943                         {
    944                                 if( st != st2 )
    945                                         st2 = st, *p++ = st ? '+' : '-';
    946                                 *p++ = *t;
    947                         }
    948                         m[(int)*t] = st;
    949                 }
    950                 else
    951                         badflag = 1;
    952         }
    953         *p = '\0';
    954        
    955         memset( irc->umode, 0, sizeof( irc->umode ) );
    956        
    957         for( i = 0; i < 256 && strlen( irc->umode ) < ( sizeof( irc->umode ) - 1 ); i ++ )
    958                 if( m[i] )
    959                         irc->umode[strlen(irc->umode)] = i;
    960        
    961         if( badflag )
    962                 irc_reply( irc, 501, ":Unknown MODE flag" );
    963         /* Deliberately no !user@host on the prefix here */
    964         if( *changes )
    965                 irc_write( irc, ":%s MODE %s %s", irc->nick, irc->nick, changes );
    966 }
    967 
    968 void irc_spawn( irc_t *irc, user_t *u )
    969 {
    970         irc_join( irc, u, irc->channel );
    971 }
    972 
    973 void irc_join( irc_t *irc, user_t *u, char *channel )
    974 {
    975         char *nick;
    976        
    977         if( ( g_strcasecmp( channel, irc->channel ) != 0 ) || user_find( irc, irc->nick ) )
    978                 irc_write( irc, ":%s!%s@%s JOIN :%s", u->nick, u->user, u->host, channel );
    979        
    980         if( nick_cmp( u->nick, irc->nick ) == 0 )
    981         {
    982                 irc_write( irc, ":%s MODE %s +%s", irc->myhost, channel, CMODE );
    983                 irc_names( irc, channel );
    984                 irc_topic( irc, channel );
    985         }
    986        
    987         nick = g_strdup( u->nick );
    988         nick_lc( nick );
    989         if( g_hash_table_lookup( irc->watches, nick ) )
    990         {
    991                 irc_reply( irc, 600, "%s %s %s %d :%s", u->nick, u->user, u->host, (int) time( NULL ), "logged online" );
    992         }
    993         g_free( nick );
    994 }
    995 
    996 void irc_part( irc_t *irc, user_t *u, char *channel )
    997 {
    998         irc_write( irc, ":%s!%s@%s PART %s :%s", u->nick, u->user, u->host, channel, "" );
    999 }
    1000 
    1001 void irc_kick( irc_t *irc, user_t *u, char *channel, user_t *kicker )
    1002 {
    1003         irc_write( irc, ":%s!%s@%s KICK %s %s :%s", kicker->nick, kicker->user, kicker->host, channel, u->nick, "" );
    1004 }
    1005 
    1006 void irc_kill( irc_t *irc, user_t *u )
    1007 {
    1008         char *nick, *s;
    1009         char reason[128];
    1010        
    1011         if( u->ic && u->ic->flags & OPT_LOGGING_OUT && set_getbool( &irc->set, "simulate_netsplit" ) )
    1012         {
    1013                 if( u->ic->acc->server )
    1014                         g_snprintf( reason, sizeof( reason ), "%s %s", irc->myhost,
    1015                                     u->ic->acc->server );
    1016                 else if( ( s = strchr( u->ic->acc->user, '@' ) ) )
    1017                         g_snprintf( reason, sizeof( reason ), "%s %s", irc->myhost,
    1018                                     s + 1 );
    1019                 else
    1020                         g_snprintf( reason, sizeof( reason ), "%s %s.%s", irc->myhost,
    1021                                     u->ic->acc->prpl->name, irc->myhost );
    1022                
    1023                 /* proto_opt might contain garbage after the : */
    1024                 if( ( s = strchr( reason, ':' ) ) )
    1025                         *s = 0;
    1026         }
    1027         else
    1028         {
    1029                 strcpy( reason, "Leaving..." );
    1030         }
    1031        
    1032         irc_write( irc, ":%s!%s@%s QUIT :%s", u->nick, u->user, u->host, reason );
    1033        
    1034         nick = g_strdup( u->nick );
    1035         nick_lc( nick );
    1036         if( g_hash_table_lookup( irc->watches, nick ) )
    1037         {
    1038                 irc_reply( irc, 601, "%s %s %s %d :%s", u->nick, u->user, u->host, (int) time( NULL ), "logged offline" );
    1039         }
    1040         g_free( nick );
    1041 }
    1042 
    1043 int irc_send( irc_t *irc, char *nick, char *s, int flags )
    1044 {
    1045         struct groupchat *c = NULL;
    1046         user_t *u = NULL;
    1047        
    1048         if( strchr( CTYPES, *nick ) )
    1049         {
    1050                 if( !( c = irc_chat_by_channel( irc, nick ) ) )
    1051                 {
    1052                         irc_reply( irc, 403, "%s :Channel does not exist", nick );
    1053                         return( 0 );
    1054                 }
    1055         }
    1056         else
    1057         {
    1058                 u = user_find( irc, nick );
    1059                
    1060                 if( !u )
    1061                 {
    1062                         if( irc->is_private )
    1063                                 irc_reply( irc, 401, "%s :Nick does not exist", nick );
    1064                         else
    1065                                 irc_usermsg( irc, "Nick `%s' does not exist!", nick );
    1066                         return( 0 );
    1067                 }
    1068         }
    1069        
    1070         if( *s == 1 && s[strlen(s)-1] == 1 )
    1071         {
    1072                 if( g_strncasecmp( s + 1, "ACTION", 6 ) == 0 )
    1073                 {
    1074                         if( s[7] == ' ' ) s ++;
    1075                         s += 3;
    1076                         *(s++) = '/';
    1077                         *(s++) = 'm';
    1078                         *(s++) = 'e';
    1079                         *(s++) = ' ';
    1080                         s -= 4;
    1081                         s[strlen(s)-1] = 0;
    1082                 }
    1083                 else if( g_strncasecmp( s + 1, "VERSION", 7 ) == 0 )
    1084                 {
    1085                         u = user_find( irc, irc->mynick );
    1086                         irc_privmsg( irc, u, "NOTICE", irc->nick, "", "\001VERSION BitlBee " BITLBEE_VERSION " " ARCH "/" CPU "\001" );
    1087                         return( 1 );
    1088                 }
    1089                 else if( g_strncasecmp( s + 1, "PING", 4 ) == 0 )
    1090                 {
    1091                         u = user_find( irc, irc->mynick );
    1092                         irc_privmsg( irc, u, "NOTICE", irc->nick, "", s );
    1093                         return( 1 );
    1094                 }
    1095                 else if( g_strncasecmp( s + 1, "TYPING", 6 ) == 0 )
    1096                 {
    1097                         if( u && u->ic && u->ic->acc->prpl->send_typing && strlen( s ) >= 10 )
    1098                         {
    1099                                 time_t current_typing_notice = time( NULL );
    1100                                
    1101                                 if( current_typing_notice - u->last_typing_notice >= 5 )
    1102                                 {
    1103                                         u->ic->acc->prpl->send_typing( u->ic, u->handle, ( s[8] - '0' ) << 8 );
    1104                                         u->last_typing_notice = current_typing_notice;
    1105                                 }
    1106                         }
    1107                         return( 1 );
    1108                 }
    1109                 else if( g_strncasecmp( s + 1, "DCC", 3 ) == 0 )
    1110                 {
    1111                         if( u && u->ic && u->ic->acc->prpl->transfer_request )
    1112                         {
    1113                                 file_transfer_t *ft = dcc_request( u->ic, s + 5 );
    1114                                 if ( ft )
    1115                                         u->ic->acc->prpl->transfer_request( u->ic, ft, u->handle );
    1116                         }
    1117                         return( 1 );
    1118                 }               
    1119                 else
    1120                 {
    1121                         irc_usermsg( irc, "Supported CTCPs are ACTION, VERSION, PING, TYPING, DCC" );
    1122                         return( 0 );
    1123                 }
    1124         }
    1125        
    1126         if( u )
    1127         {
    1128                 /* For the next message, we probably do have to send new notices... */
    1129                 u->last_typing_notice = 0;
    1130                 u->is_private = irc->is_private;
    1131                
    1132                 if( u->is_private )
    1133                 {
    1134                         if( !u->online )
    1135                                 irc_reply( irc, 301, "%s :%s", u->nick, "User is offline" );
    1136                         else if( u->away )
    1137                                 irc_reply( irc, 301, "%s :%s", u->nick, u->away );
    1138                 }
    1139                
    1140                 if( u->send_handler )
    1141                 {
    1142                         u->send_handler( irc, u, s, flags );
    1143                         return 1;
    1144                 }
    1145         }
    1146         else if( c && c->ic && c->ic->acc && c->ic->acc->prpl )
    1147         {
    1148                 return( imc_chat_msg( c, s, 0 ) );
    1149         }
    1150        
    1151         return( 0 );
    1152 }
    1153 
    1154 static gboolean buddy_send_handler_delayed( gpointer data, gint fd, b_input_condition cond )
    1155 {
    1156         user_t *u = data;
    1157        
    1158         /* Shouldn't happen, but just to be sure. */
    1159         if( u->sendbuf_len < 2 )
    1160                 return FALSE;
    1161        
    1162         u->sendbuf[u->sendbuf_len-2] = 0; /* Cut off the last newline */
    1163         imc_buddy_msg( u->ic, u->handle, u->sendbuf, u->sendbuf_flags );
    1164        
    1165         g_free( u->sendbuf );
    1166         u->sendbuf = NULL;
    1167         u->sendbuf_len = 0;
    1168         u->sendbuf_timer = 0;
    1169         u->sendbuf_flags = 0;
    1170        
    1171         return FALSE;
    1172 }
    1173 
    1174 void buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags )
    1175 {
    1176         if( !u || !u->ic ) return;
    1177        
    1178         if( set_getbool( &irc->set, "buddy_sendbuffer" ) && set_getint( &irc->set, "buddy_sendbuffer_delay" ) > 0 )
    1179         {
    1180                 int delay;
    1181                
    1182                 if( u->sendbuf_len > 0 && u->sendbuf_flags != flags)
    1183                 {
    1184                         /* Flush the buffer */
    1185                         b_event_remove( u->sendbuf_timer );
    1186                         buddy_send_handler_delayed( u, -1, 0 );
    1187                 }
    1188 
    1189                 if( u->sendbuf_len == 0 )
    1190                 {
    1191                         u->sendbuf_len = strlen( msg ) + 2;
    1192                         u->sendbuf = g_new( char, u->sendbuf_len );
    1193                         u->sendbuf[0] = 0;
    1194                         u->sendbuf_flags = flags;
    1195                 }
    1196                 else
    1197                 {
    1198                         u->sendbuf_len += strlen( msg ) + 1;
    1199                         u->sendbuf = g_renew( char, u->sendbuf, u->sendbuf_len );
    1200                 }
    1201                
    1202                 strcat( u->sendbuf, msg );
    1203                 strcat( u->sendbuf, "\n" );
    1204                
    1205                 delay = set_getint( &irc->set, "buddy_sendbuffer_delay" );
    1206                 if( delay <= 5 )
    1207                         delay *= 1000;
    1208                
    1209                 if( u->sendbuf_timer > 0 )
    1210                         b_event_remove( u->sendbuf_timer );
    1211                 u->sendbuf_timer = b_timeout_add( delay, buddy_send_handler_delayed, u );
    1212         }
    1213         else
    1214         {
    1215                 imc_buddy_msg( u->ic, u->handle, msg, flags );
    1216         }
    1217 }
    1218 
    1219 int irc_privmsg( irc_t *irc, user_t *u, char *type, char *to, char *prefix, char *msg )
    1220 {
    1221         char last = 0;
    1222         char *s = msg, *line = msg;
    1223        
    1224         /* The almighty linesplitter .. woohoo!! */
    1225         while( !last )
    1226         {
    1227                 if( *s == '\r' && *(s+1) == '\n' )
    1228                         *(s++) = 0;
    1229                 if( *s == '\n' )
    1230                 {
    1231                         last = s[1] == 0;
    1232                         *s = 0;
    1233                 }
    1234                 else
    1235                 {
    1236                         last = s[0] == 0;
    1237                 }
    1238                 if( *s == 0 )
    1239                 {
    1240                         if( g_strncasecmp( line, "/me ", 4 ) == 0 && ( !prefix || !*prefix ) && g_strcasecmp( type, "PRIVMSG" ) == 0 )
    1241                         {
    1242                                 irc_write( irc, ":%s!%s@%s %s %s :\001ACTION %s\001", u->nick, u->user, u->host,
    1243                                            type, to, line + 4 );
    1244                         }
    1245                         else
    1246                         {
    1247                                 irc_write( irc, ":%s!%s@%s %s %s :%s%s", u->nick, u->user, u->host,
    1248                                            type, to, prefix ? prefix : "", line );
    1249                         }
    1250                         line = s + 1;
    1251                 }
    1252                 s ++;
    1253         }
    1254        
    1255         return( 1 );
    1256 }
    1257 
    1258 int irc_msgfrom( irc_t *irc, char *nick, char *msg )
    1259 {
    1260         user_t *u = user_find( irc, nick );
    1261         static char *prefix = NULL;
    1262        
    1263         if( !u ) return( 0 );
    1264         if( prefix && *prefix ) g_free( prefix );
    1265        
    1266         if( !u->is_private && nick_cmp( u->nick, irc->mynick ) != 0 )
    1267         {
    1268                 int len = strlen( irc->nick) + 3;
    1269                 prefix = g_new (char, len );
    1270                 g_snprintf( prefix, len, "%s%s", irc->nick, set_getstr( &irc->set, "to_char" ) );
    1271                 prefix[len-1] = 0;
    1272         }
    1273         else
    1274         {
    1275                 prefix = "";
    1276         }
    1277        
    1278         return( irc_privmsg( irc, u, "PRIVMSG", u->is_private ? irc->nick : irc->channel, prefix, msg ) );
    1279 }
    1280 
    1281 int irc_noticefrom( irc_t *irc, char *nick, char *msg )
    1282 {
    1283         user_t *u = user_find( irc, nick );
    1284        
    1285         if( u )
    1286                 return( irc_privmsg( irc, u, "NOTICE", irc->nick, "", msg ) );
    1287         else
    1288                 return( 0 );
    1289 }
    1290 
    1291 /* Returns 0 if everything seems to be okay, a number >0 when there was a
    1292    timeout. The number returned is the number of seconds we received no
    1293    pongs from the user. When not connected yet, we don't ping but drop the
    1294    connection when the user fails to connect in IRC_LOGIN_TIMEOUT secs. */
    1295 static gboolean irc_userping( gpointer _irc, gint fd, b_input_condition cond )
    1296 {
    1297         irc_t *irc = _irc;
    1298         int rv = 0;
    1299        
    1300         if( !( irc->status & USTATUS_LOGGED_IN ) )
    1301         {
    1302                 if( gettime() > ( irc->last_pong + IRC_LOGIN_TIMEOUT ) )
    1303                         rv = gettime() - irc->last_pong;
    1304         }
    1305         else
    1306         {
    1307                 if( ( gettime() > ( irc->last_pong + global.conf->ping_interval ) ) && !irc->pinging )
    1308                 {
    1309                         irc_write( irc, "PING :%s", IRC_PING_STRING );
    1310                         irc->pinging = 1;
    1311                 }
    1312                 else if( gettime() > ( irc->last_pong + global.conf->ping_timeout ) )
    1313                 {
    1314                         rv = gettime() - irc->last_pong;
    1315                 }
    1316         }
    1317        
    1318         if( rv > 0 )
    1319         {
    1320                 irc_abort( irc, 0, "Ping Timeout: %d seconds", rv );
    1321                 return FALSE;
    1322         }
    1323        
    1324         return TRUE;
    1325 }
    1326 
    1327 struct groupchat *irc_chat_by_channel( irc_t *irc, char *channel )
    1328 {
    1329         struct groupchat *c;
    1330         account_t *a;
    1331        
    1332         /* This finds the connection which has a conversation which belongs to this channel */
    1333         for( a = irc->accounts; a; a = a->next )
    1334         {
    1335                 if( a->ic == NULL )
    1336                         continue;
    1337                
    1338                 c = a->ic->groupchats;
    1339                 while( c )
    1340                 {
    1341                         if( c->channel && g_strcasecmp( c->channel, channel ) == 0 )
    1342                                 return c;
    1343                        
    1344                         c = c->next;
    1345                 }
    1346         }
    1347        
    1348         return NULL;
    1349 }
     593
     594
     595static char *set_eval_charset( set_t *set, char *value )
     596{
     597        irc_t *irc = set->data;
     598        GIConv ic, oc;
     599
     600        if( g_strcasecmp( value, "none" ) == 0 )
     601                value = g_strdup( "utf-8" );
     602
     603        if( ( ic = g_iconv_open( "utf-8", value ) ) == (GIConv) -1 )
     604        {
     605                return NULL;
     606        }
     607        if( ( oc = g_iconv_open( value, "utf-8" ) ) == (GIConv) -1 )
     608        {
     609                g_iconv_close( ic );
     610                return NULL;
     611        }
     612       
     613        if( irc->iconv != (GIConv) -1 )
     614                g_iconv_close( irc->iconv );
     615        if( irc->oconv != (GIConv) -1 )
     616                g_iconv_close( irc->oconv );
     617       
     618        irc->iconv = ic;
     619        irc->oconv = oc;
     620
     621        return value;
     622}
Note: See TracChangeset for help on using the changeset viewer.