Changeset 6738a67 for irc.c


Ignore:
Timestamp:
2008-07-16T23:22:52Z (16 years ago)
Author:
Sven Moritz Hallberg <pesco@…>
Branches:
master
Children:
9b55485
Parents:
9730d72 (diff), 6a78c0e (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

merge in latest trunk

File:
1 edited

Legend:

Unmodified
Added
Removed
  • irc.c

    r9730d72 r6738a67  
    2626#define BITLBEE_CORE
    2727#include "bitlbee.h"
     28#include "sock.h"
    2829#include "crypting.h"
    2930#include "ipc.h"
     
    4546}
    4647
     48static char *set_eval_charset( set_t *set, char *value )
     49{
     50        irc_t *irc = set->data;
     51        GIConv ic, oc;
     52
     53        if( g_strcasecmp( value, "none" ) == 0 )
     54                value = g_strdup( "utf-8" );
     55
     56        if( ( ic = g_iconv_open( "utf-8", value ) ) == (GIConv) -1 )
     57        {
     58                return NULL;
     59        }
     60        if( ( oc = g_iconv_open( value, "utf-8" ) ) == (GIConv) -1 )
     61        {
     62                g_iconv_close( ic );
     63                return NULL;
     64        }
     65       
     66        if( irc->iconv != (GIConv) -1 )
     67                g_iconv_close( irc->iconv );
     68        if( irc->oconv != (GIConv) -1 )
     69                g_iconv_close( irc->oconv );
     70       
     71        irc->iconv = ic;
     72        irc->oconv = oc;
     73
     74        return value;
     75}
     76
    4777irc_t *irc_new( int fd )
    4878{
     
    6797        irc->mynick = g_strdup( ROOT_NICK );
    6898        irc->channel = g_strdup( ROOT_CHAN );
     99       
     100        irc->iconv = (GIConv) -1;
     101        irc->oconv = (GIConv) -1;
    69102       
    70103        if( global.conf->hostname )
     
    126159        set_add( &irc->set, "private", "true", set_eval_bool, irc );
    127160        set_add( &irc->set, "query_order", "lifo", NULL, irc );
     161        set_add( &irc->set, "root_nick", irc->mynick, set_eval_root_nick, irc );
    128162        set_add( &irc->set, "save_on_quit", "true", set_eval_bool, irc );
    129163        set_add( &irc->set, "simulate_netsplit", "true", set_eval_bool, irc );
     
    137171        irc->otr = otr_new();
    138172       
     173        /* Evaluator sets the iconv/oconv structures. */
     174        set_eval_charset( set_find( &irc->set, "charset" ), set_getstr( &irc->set, "charset" ) );
     175       
    139176        return( irc );
    140177}
     
    174211        if( irc->sendbuffer && !immed )
    175212        {
    176                 /* We won't read from this socket anymore. Instead, we'll connect a timer
    177                    to it that should shut down the connection in a second, just in case
    178                    bitlbee_.._write doesn't do it first. */
     213                /* Set up a timeout event that should shut down the connection
     214                   in a second, just in case ..._write doesn't do it first. */
    179215               
    180216                b_event_remove( irc->r_watch_source_id );
    181                 irc->r_watch_source_id = b_timeout_add( 1000, (b_event_handler) irc_free, irc );
     217                irc->r_watch_source_id = 0;
     218               
     219                b_event_remove( irc->ping_source_id );
     220                irc->ping_source_id = b_timeout_add( 1000, (b_event_handler) irc_free, irc );
    182221        }
    183222        else
     
    195234
    196235/* Because we have no garbage collection, this is quite annoying */
    197 void irc_free(irc_t * irc)
    198 {
    199         account_t *account;
     236void irc_free( irc_t * irc )
     237{
    200238        user_t *user, *usertmp;
    201239       
     
    206244                        irc_usermsg( irc, "Error while saving settings!" );
    207245       
    208         closesocket( irc->fd );
    209        
    210         if( irc->ping_source_id > 0 )
    211                 b_event_remove( irc->ping_source_id );
    212         b_event_remove( irc->r_watch_source_id );
    213         if( irc->w_watch_source_id > 0 )
    214                 b_event_remove( irc->w_watch_source_id );
    215        
    216246        irc_connection_list = g_slist_remove( irc_connection_list, irc );
    217247       
    218         for (account = irc->accounts; account; account = account->next) {
    219                 if (account->ic) {
    220                         imc_logout(account->ic, TRUE);
    221                 } else if (account->reconnect) {
    222                         cancel_auto_reconnect(account);
    223                 }
    224         }
    225        
    226         g_free(irc->sendbuffer);
    227         g_free(irc->readbuffer);
    228        
    229         g_free(irc->nick);
    230         g_free(irc->user);
    231         g_free(irc->host);
    232         g_free(irc->realname);
    233         g_free(irc->password);
    234        
    235         g_free(irc->myhost);
    236         g_free(irc->mynick);
    237        
    238         g_free(irc->channel);
    239        
    240         while (irc->queries != NULL)
    241                 query_del(irc, irc->queries);
    242        
    243         while (irc->accounts)
    244                 if (irc->accounts->ic == NULL)
    245                         account_del(irc, irc->accounts);
     248        while( irc->accounts )
     249        {
     250                if( irc->accounts->ic )
     251                        imc_logout( irc->accounts->ic, FALSE );
     252                else if( irc->accounts->reconnect )
     253                        cancel_auto_reconnect( irc->accounts );
     254               
     255                if( irc->accounts->ic == NULL )
     256                        account_del( irc, irc->accounts );
    246257                else
    247258                        /* Nasty hack, but account_del() doesn't work in this
    248259                           case and we don't want infinite loops, do we? ;-) */
    249260                        irc->accounts = irc->accounts->next;
    250        
    251         while (irc->set)
    252                 set_del(&irc->set, irc->set->key);
    253        
    254         if (irc->users != NULL) {
     261        }
     262       
     263        while( irc->queries != NULL )
     264                query_del( irc, irc->queries );
     265       
     266        while( irc->set )
     267                set_del( &irc->set, irc->set->key );
     268       
     269        if (irc->users != NULL)
     270        {
    255271                user = irc->users;
    256                 while (user != NULL) {
    257                         g_free(user->nick);
    258                         g_free(user->away);
    259                         g_free(user->handle);
    260                         if(user->user!=user->nick) g_free(user->user);
    261                         if(user->host!=user->nick) g_free(user->host);
    262                         if(user->realname!=user->nick) g_free(user->realname);
    263                         b_event_remove(user->sendbuf_timer);
     272                while( user != NULL )
     273                {
     274                        g_free( user->nick );
     275                        g_free( user->away );
     276                        g_free( user->handle );
     277                        if( user->user != user->nick ) g_free( user->user );
     278                        if( user->host != user->nick ) g_free( user->host );
     279                        if( user->realname != user->nick ) g_free( user->realname );
     280                        b_event_remove( user->sendbuf_timer );
    264281                                       
    265282                        usertmp = user;
    266283                        user = user->next;
    267                         g_free(usertmp);
    268                 }
    269         }
    270        
    271         g_hash_table_foreach_remove(irc->userhash, irc_free_hashkey, NULL);
    272         g_hash_table_destroy(irc->userhash);
    273        
    274         g_hash_table_foreach_remove(irc->watches, irc_free_hashkey, NULL);
    275         g_hash_table_destroy(irc->watches);
     284                        g_free( usertmp );
     285                }
     286        }
     287       
     288        if( irc->ping_source_id > 0 )
     289                b_event_remove( irc->ping_source_id );
     290        if( irc->r_watch_source_id > 0 )
     291                b_event_remove( irc->r_watch_source_id );
     292        if( irc->w_watch_source_id > 0 )
     293                b_event_remove( irc->w_watch_source_id );
     294       
     295        closesocket( irc->fd );
     296        irc->fd = -1;
     297       
     298        g_hash_table_foreach_remove( irc->userhash, irc_free_hashkey, NULL );
     299        g_hash_table_destroy( irc->userhash );
     300       
     301        g_hash_table_foreach_remove( irc->watches, irc_free_hashkey, NULL );
     302        g_hash_table_destroy( irc->watches );
     303       
     304        if( irc->iconv != (GIConv) -1 )
     305                g_iconv_close( irc->iconv );
     306        if( irc->oconv != (GIConv) -1 )
     307                g_iconv_close( irc->oconv );
     308       
     309        g_free( irc->sendbuffer );
     310        g_free( irc->readbuffer );
     311       
     312        g_free( irc->nick );
     313        g_free( irc->user );
     314        g_free( irc->host );
     315        g_free( irc->realname );
     316        g_free( irc->password );
     317       
     318        g_free( irc->myhost );
     319        g_free( irc->mynick );
     320       
     321        g_free( irc->channel );
     322       
     323        g_free( irc->last_target );
    276324       
    277325        otr_free(irc->otr);
    278326       
    279         g_free(irc);
    280        
    281         if( global.conf->runmode == RUNMODE_INETD || global.conf->runmode == RUNMODE_FORKDAEMON )
     327        g_free( irc );
     328       
     329        if( global.conf->runmode == RUNMODE_INETD ||
     330            global.conf->runmode == RUNMODE_FORKDAEMON ||
     331            ( global.conf->runmode == RUNMODE_DAEMON &&
     332              global.listen_socket == -1 &&
     333              irc_connection_list == NULL ) )
    282334                b_main_quit();
    283335}
     
    298350void irc_process( irc_t *irc )
    299351{
    300         char **lines, *temp, **cmd, *cs;
     352        char **lines, *temp, **cmd;
    301353        int i;
    302354
     
    307359                for( i = 0; *lines[i] != '\0'; i ++ )
    308360                {
    309                         char conv[IRC_MAX_LINE+1];
     361                        char *conv = NULL;
    310362                       
    311                         /* [WvG] Because irc_tokenize splits at every newline, the lines[] list
    312                             should end with an empty string. This is why this actually works.
    313                             Took me a while to figure out, Maurits. :-P */
     363                        /* [WvG] If the last line isn't empty, it's an incomplete line and we
     364                           should wait for the rest to come in before processing it. */
    314365                        if( lines[i+1] == NULL )
    315366                        {
     
    321372                        }
    322373                       
    323                         if( ( cs = set_getstr( &irc->set, "charset" ) ) )
    324                         {
    325                                 conv[IRC_MAX_LINE] = 0;
    326                                 if( do_iconv( cs, "UTF-8", lines[i], conv, 0, IRC_MAX_LINE - 2 ) == -1 )
     374                        if( irc->iconv != (GIConv) -1 )
     375                        {
     376                                gsize bytes_read, bytes_written;
     377                               
     378                                conv = g_convert_with_iconv( lines[i], -1, irc->iconv,
     379                                                             &bytes_read, &bytes_written, NULL );
     380                               
     381                                if( conv == NULL || bytes_read != strlen( lines[i] ) )
    327382                                {
    328383                                        /* GLib can do strange things if things are not in the expected charset,
     
    336391                                                                  "expect by changing the charset setting. See "
    337392                                                                  "`help set charset' for more information. Your "
    338                                                                   "message was ignored.", cs );
    339                                                 *conv = 0;
     393                                                                  "message was ignored.",
     394                                                                  set_getstr( &irc->set, "charset" ) );
     395                                               
     396                                                g_free( conv );
     397                                                conv = NULL;
    340398                                        }
    341399                                        else
    342400                                        {
    343401                                                irc_write( irc, ":%s NOTICE AUTH :%s", irc->myhost,
    344                                                            "Warning: invalid (non-UTF8) characters received at login time." );
     402                                                           "Warning: invalid characters received at login time." );
    345403                                               
    346                                                 strncpy( conv, lines[i], IRC_MAX_LINE );
     404                                                conv = g_strdup( lines[i] );
    347405                                                for( temp = conv; *temp; temp ++ )
    348406                                                        if( *temp & 0x80 )
     
    353411                        }
    354412                       
    355                         if( ( cmd = irc_parse_line( lines[i] ) ) == NULL )
    356                                 continue;
    357                         irc_exec( irc, cmd );
     413                        if( lines[i] )
     414                        {
     415                                if( ( cmd = irc_parse_line( lines[i] ) ) == NULL )
     416                                        continue;
     417                                irc_exec( irc, cmd );
     418                                g_free( cmd );
     419                        }
    358420                       
    359                         g_free( cmd );
     421                        g_free( conv );
    360422                       
    361423                        /* Shouldn't really happen, but just in case... */
     
    381443char **irc_tokenize( char *buffer )
    382444{
    383         int i, j;
     445        int i, j, n = 3;
    384446        char **lines;
    385447
    386         /* Count the number of elements we're gonna need. */
    387         for( i = 0, j = 1; buffer[i] != '\0'; i ++ )
    388         {
    389                 if( buffer[i] == '\n' )
    390                         if( buffer[i+1] != '\r' && buffer[i+1] != '\n' )
    391                                 j ++;
    392         }
    393        
    394         /* Allocate j+1 elements. */
    395         lines = g_new( char *, j + 1 );
     448        /* Allocate n+1 elements. */
     449        lines = g_new( char *, n + 1 );
     450       
     451        lines[0] = buffer;
     452       
     453        /* Split the buffer in several strings, and accept any kind of line endings,
     454         * knowing that ERC on Windows may send something interesting like \r\r\n,
     455         * and surely there must be clients that think just \n is enough... */
     456        for( i = 0, j = 0; buffer[i] != '\0'; i ++ )
     457        {
     458                if( buffer[i] == '\r' || buffer[i] == '\n' )
     459                {
     460                        while( buffer[i] == '\r' || buffer[i] == '\n' )
     461                                buffer[i++] = '\0';
     462                       
     463                        lines[++j] = buffer + i;
     464                       
     465                        if( j >= n )
     466                        {
     467                                n *= 2;
     468                                lines = g_renew( char *, lines, n + 1 );
     469                        }
     470
     471                        if( buffer[i] == '\0' )
     472                                break;
     473                }
     474        }
    396475       
    397476        /* NULL terminate our list. */
    398         lines[j] = NULL;
    399        
    400         lines[0] = buffer;
    401        
    402         /* Split the buffer in several strings, using \r\n as our seperator, where \r is optional.
    403          * Although this is not in the RFC, some braindead ircds (newnet's) use this, so some clients might too.
    404          */
    405         for( i = 0, j = 0; buffer[i] != '\0'; i ++)
    406         {
    407                 if( buffer[i] == '\n' )
    408                 {
    409                         buffer[i] = '\0';
    410                        
    411                         if( i > 0 && buffer[i-1] == '\r' )
    412                                 buffer[i-1] = '\0';
    413                         if( buffer[i+1] != '\r' && buffer[i+1] != '\n' )
    414                                 lines[++j] = buffer + i + 1;
    415                 }
    416         }
    417        
    418         return( lines );
     477        lines[++j] = NULL;
     478       
     479        return lines;
    419480}
    420481
     
    550611
    551612        return;
    552 
    553613}
    554614
     
    556616{
    557617        int size;
    558         char line[IRC_MAX_LINE+1], *cs;
     618        char line[IRC_MAX_LINE+1];
    559619               
    560620        /* Don't try to write anything new anymore when shutting down. */
     
    562622                return;
    563623       
    564         line[IRC_MAX_LINE] = 0;
     624        memset( line, 0, sizeof( line ) );
    565625        g_vsnprintf( line, IRC_MAX_LINE - 2, format, params );
    566        
    567626        strip_newlines( line );
    568         if( ( cs = set_getstr( &irc->set, "charset" ) ) && ( g_strcasecmp( cs, "utf-8" ) != 0 ) )
    569         {
    570                 char conv[IRC_MAX_LINE+1];
    571                
    572                 conv[IRC_MAX_LINE] = 0;
    573                 if( do_iconv( "UTF-8", cs, line, conv, 0, IRC_MAX_LINE - 2 ) != -1 )
    574                         strcpy( line, conv );
    575         }
    576         strcat( line, "\r\n" );
     627       
     628        if( irc->oconv != (GIConv) -1 )
     629        {
     630                gsize bytes_read, bytes_written;
     631                char *conv;
     632               
     633                conv = g_convert_with_iconv( line, -1, irc->oconv,
     634                                             &bytes_read, &bytes_written, NULL );
     635
     636                if( bytes_read == strlen( line ) )
     637                        strncpy( line, conv, IRC_MAX_LINE - 2 );
     638               
     639                g_free( conv );
     640        }
     641        g_strlcat( line, "\r\n", IRC_MAX_LINE + 1 );
    577642       
    578643        if( irc->sendbuffer != NULL )
     
    753818        irc->umode[0] = '\0';
    754819        irc_umode_set( irc, "+" UMODE, 1 );
    755 
    756         u = user_add( irc, irc->mynick );
     820u = user_add( irc, irc->mynick );
    757821        u->host = g_strdup( irc->myhost );
    758822        u->realname = g_strdup( ROOT_FN );
     
    782846       
    783847        irc->status |= USTATUS_LOGGED_IN;
     848       
     849        /* This is for bug #209 (use PASS to identify to NickServ). */
     850        if( irc->password != NULL )
     851        {
     852                char *send_cmd[] = { "identify", g_strdup( irc->password ), NULL };
     853               
     854                irc_setpass( irc, NULL );
     855                root_command( irc, send_cmd );
     856                g_free( send_cmd[1] );
     857        }
    784858}
    785859
     
    791865        if( !f )
    792866        {
    793                 irc_usermsg( irc, "Welcome to the BitlBee gateway!\n\nIf you've never used BitlBee before, please do read the help information using the \x02help\x02 command. Lots of FAQs are answered there.\n\nOTR users please note: Private key files are owned by the user BitlBee is running as." );
     867                irc_usermsg( irc, "Welcome to the BitlBee gateway!\n\n"
     868                                  "If you've never used BitlBee before, please do read the help "
     869                                  "information using the \x02help\x02 command. Lots of FAQs are "
     870                                  "answered there.\n"
     871                                  "OTR users please note: Private key files are owned by the user "
     872                                  "BitlBee is running as.\n"
     873                                  "If you already have an account on this server, just use the "
     874                                  "\x02identify\x02 command to identify yourself." );
    794875        }
    795876        else
Note: See TracChangeset for help on using the changeset viewer.