Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • irc.c

    ra83442a r1195cec  
    4242}
    4343
     44static char *set_eval_charset( set_t *set, char *value )
     45{
     46        irc_t *irc = set->data;
     47        GIConv ic, oc;
     48
     49        if( g_strcasecmp( value, "none" ) == 0 )
     50                value = g_strdup( "utf-8" );
     51
     52        if( ( ic = g_iconv_open( "utf-8", value ) ) == (GIConv) -1 )
     53        {
     54                return NULL;
     55        }
     56        if( ( oc = g_iconv_open( value, "utf-8" ) ) == (GIConv) -1 )
     57        {
     58                g_iconv_close( ic );
     59                return NULL;
     60        }
     61       
     62        if( irc->iconv != (GIConv) -1 )
     63                g_iconv_close( irc->iconv );
     64        if( irc->oconv != (GIConv) -1 )
     65                g_iconv_close( irc->oconv );
     66       
     67        irc->iconv = ic;
     68        irc->oconv = oc;
     69
     70        return value;
     71}
     72
    4473irc_t *irc_new( int fd )
    4574{
     
    6493        irc->mynick = g_strdup( ROOT_NICK );
    6594        irc->channel = g_strdup( ROOT_CHAN );
     95       
     96        irc->iconv = (GIConv) -1;
     97        irc->oconv = (GIConv) -1;
    6698       
    6799        if( global.conf->hostname )
     
    119151        set_add( &irc->set, "private", "true", set_eval_bool, irc );
    120152        set_add( &irc->set, "query_order", "lifo", NULL, irc );
     153        set_add( &irc->set, "root_nick", irc->mynick, set_eval_root_nick, irc );
    121154        set_add( &irc->set, "save_on_quit", "true", set_eval_bool, irc );
    122155        set_add( &irc->set, "simulate_netsplit", "true", set_eval_bool, irc );
     
    127160        conf_loaddefaults( irc );
    128161       
     162        /* Evaluator sets the iconv/oconv structures. */
     163        set_eval_charset( set_find( &irc->set, "charset" ), set_getstr( &irc->set, "charset" ) );
     164       
    129165        return( irc );
    130166}
     
    164200        if( irc->sendbuffer && !immed )
    165201        {
    166                 /* We won't read from this socket anymore. Instead, we'll connect a timer
    167                    to it that should shut down the connection in a second, just in case
    168                    bitlbee_.._write doesn't do it first. */
     202                /* Set up a timeout event that should shut down the connection
     203                   in a second, just in case ..._write doesn't do it first. */
    169204               
    170205                b_event_remove( irc->r_watch_source_id );
    171                 irc->r_watch_source_id = b_timeout_add( 1000, (b_event_handler) irc_free, irc );
     206                irc->r_watch_source_id = 0;
     207               
     208                b_event_remove( irc->ping_source_id );
     209                irc->ping_source_id = b_timeout_add( 1000, (b_event_handler) irc_free, irc );
    172210        }
    173211        else
     
    185223
    186224/* Because we have no garbage collection, this is quite annoying */
    187 void irc_free(irc_t * irc)
    188 {
    189         account_t *account;
     225void irc_free( irc_t * irc )
     226{
    190227        user_t *user, *usertmp;
    191228       
     
    196233                        irc_usermsg( irc, "Error while saving settings!" );
    197234       
    198         closesocket( irc->fd );
    199        
    200         if( irc->ping_source_id > 0 )
    201                 b_event_remove( irc->ping_source_id );
    202         b_event_remove( irc->r_watch_source_id );
    203         if( irc->w_watch_source_id > 0 )
    204                 b_event_remove( irc->w_watch_source_id );
    205        
    206235        irc_connection_list = g_slist_remove( irc_connection_list, irc );
    207236       
    208         for (account = irc->accounts; account; account = account->next) {
    209                 if (account->ic) {
    210                         imc_logout(account->ic, TRUE);
    211                 } else if (account->reconnect) {
    212                         cancel_auto_reconnect(account);
    213                 }
    214         }
    215        
    216         g_free(irc->sendbuffer);
    217         g_free(irc->readbuffer);
    218        
    219         g_free(irc->nick);
    220         g_free(irc->user);
    221         g_free(irc->host);
    222         g_free(irc->realname);
    223         g_free(irc->password);
    224        
    225         g_free(irc->myhost);
    226         g_free(irc->mynick);
    227        
    228         g_free(irc->channel);
    229        
    230         while (irc->queries != NULL)
    231                 query_del(irc, irc->queries);
    232        
    233         while (irc->accounts)
    234                 if (irc->accounts->ic == NULL)
    235                         account_del(irc, irc->accounts);
     237        while( irc->accounts )
     238        {
     239                if( irc->accounts->ic )
     240                        imc_logout( irc->accounts->ic, FALSE );
     241                else if( irc->accounts->reconnect )
     242                        cancel_auto_reconnect( irc->accounts );
     243               
     244                if( irc->accounts->ic == NULL )
     245                        account_del( irc, irc->accounts );
    236246                else
    237247                        /* Nasty hack, but account_del() doesn't work in this
    238248                           case and we don't want infinite loops, do we? ;-) */
    239249                        irc->accounts = irc->accounts->next;
    240        
    241         while (irc->set)
    242                 set_del(&irc->set, irc->set->key);
    243        
    244         if (irc->users != NULL) {
     250        }
     251       
     252        while( irc->queries != NULL )
     253                query_del( irc, irc->queries );
     254       
     255        while( irc->set )
     256                set_del( &irc->set, irc->set->key );
     257       
     258        if (irc->users != NULL)
     259        {
    245260                user = irc->users;
    246                 while (user != NULL) {
    247                         g_free(user->nick);
    248                         g_free(user->away);
    249                         g_free(user->handle);
    250                         if(user->user!=user->nick) g_free(user->user);
    251                         if(user->host!=user->nick) g_free(user->host);
    252                         if(user->realname!=user->nick) g_free(user->realname);
    253                         b_event_remove(user->sendbuf_timer);
     261                while( user != NULL )
     262                {
     263                        g_free( user->nick );
     264                        g_free( user->away );
     265                        g_free( user->handle );
     266                        if( user->user != user->nick ) g_free( user->user );
     267                        if( user->host != user->nick ) g_free( user->host );
     268                        if( user->realname != user->nick ) g_free( user->realname );
     269                        b_event_remove( user->sendbuf_timer );
    254270                                       
    255271                        usertmp = user;
    256272                        user = user->next;
    257                         g_free(usertmp);
    258                 }
    259         }
    260        
    261         g_hash_table_foreach_remove(irc->userhash, irc_free_hashkey, NULL);
    262         g_hash_table_destroy(irc->userhash);
    263        
    264         g_hash_table_foreach_remove(irc->watches, irc_free_hashkey, NULL);
    265         g_hash_table_destroy(irc->watches);
    266        
    267         g_free(irc);
     273                        g_free( usertmp );
     274                }
     275        }
     276       
     277        if( irc->ping_source_id > 0 )
     278                b_event_remove( irc->ping_source_id );
     279        if( irc->r_watch_source_id > 0 )
     280                b_event_remove( irc->r_watch_source_id );
     281        if( irc->w_watch_source_id > 0 )
     282                b_event_remove( irc->w_watch_source_id );
     283       
     284        closesocket( irc->fd );
     285        irc->fd = -1;
     286       
     287        g_hash_table_foreach_remove( irc->userhash, irc_free_hashkey, NULL );
     288        g_hash_table_destroy( irc->userhash );
     289       
     290        g_hash_table_foreach_remove( irc->watches, irc_free_hashkey, NULL );
     291        g_hash_table_destroy( irc->watches );
     292       
     293        if( irc->iconv != (GIConv) -1 )
     294                g_iconv_close( irc->iconv );
     295        if( irc->oconv != (GIConv) -1 )
     296                g_iconv_close( irc->oconv );
     297       
     298        g_free( irc->sendbuffer );
     299        g_free( irc->readbuffer );
     300       
     301        g_free( irc->nick );
     302        g_free( irc->user );
     303        g_free( irc->host );
     304        g_free( irc->realname );
     305        g_free( irc->password );
     306       
     307        g_free( irc->myhost );
     308        g_free( irc->mynick );
     309       
     310        g_free( irc->channel );
     311       
     312        g_free( irc->last_target );
     313       
     314        g_free( irc );
    268315       
    269316        if( global.conf->runmode == RUNMODE_INETD || global.conf->runmode == RUNMODE_FORKDAEMON )
     
    286333void irc_process( irc_t *irc )
    287334{
    288         char **lines, *temp, **cmd, *cs;
     335        char **lines, *temp, **cmd;
    289336        int i;
    290337
     
    295342                for( i = 0; *lines[i] != '\0'; i ++ )
    296343                {
    297                         char conv[IRC_MAX_LINE+1];
     344                        char *conv = NULL;
    298345                       
    299                         /* [WvG] Because irc_tokenize splits at every newline, the lines[] list
    300                             should end with an empty string. This is why this actually works.
    301                             Took me a while to figure out, Maurits. :-P */
     346                        /* [WvG] If the last line isn't empty, it's an incomplete line and we
     347                           should wait for the rest to come in before processing it. */
    302348                        if( lines[i+1] == NULL )
    303349                        {
     
    309355                        }
    310356                       
    311                         if( ( cs = set_getstr( &irc->set, "charset" ) ) && g_strcasecmp( cs, "none" ) != 0 )
    312                         {
    313                                 conv[IRC_MAX_LINE] = 0;
    314                                 if( do_iconv( cs, "UTF-8", lines[i], conv, 0, IRC_MAX_LINE - 2 ) == -1 )
     357                        if( irc->iconv != (GIConv) -1 )
     358                        {
     359                                gsize bytes_read, bytes_written;
     360                               
     361                                conv = g_convert_with_iconv( lines[i], -1, irc->iconv,
     362                                                             &bytes_read, &bytes_written, NULL );
     363                               
     364                                if( conv == NULL || bytes_read != strlen( lines[i] ) )
    315365                                {
    316366                                        /* GLib can do strange things if things are not in the expected charset,
     
    324374                                                                  "expect by changing the charset setting. See "
    325375                                                                  "`help set charset' for more information. Your "
    326                                                                   "message was ignored.", cs );
    327                                                 *conv = 0;
     376                                                                  "message was ignored.",
     377                                                                  set_getstr( &irc->set, "charset" ) );
     378                                               
     379                                                g_free( conv );
     380                                                conv = NULL;
    328381                                        }
    329382                                        else
     
    332385                                                           "Warning: invalid characters received at login time." );
    333386                                               
    334                                                 strncpy( conv, lines[i], IRC_MAX_LINE );
     387                                                conv = g_strdup( lines[i] );
    335388                                                for( temp = conv; *temp; temp ++ )
    336389                                                        if( *temp & 0x80 )
     
    341394                        }
    342395                       
    343                         if( ( cmd = irc_parse_line( lines[i] ) ) == NULL )
    344                                 continue;
    345                         irc_exec( irc, cmd );
     396                        if( lines[i] )
     397                        {
     398                                if( ( cmd = irc_parse_line( lines[i] ) ) == NULL )
     399                                        continue;
     400                                irc_exec( irc, cmd );
     401                                g_free( cmd );
     402                        }
    346403                       
    347                         g_free( cmd );
     404                        g_free( conv );
    348405                       
    349406                        /* Shouldn't really happen, but just in case... */
     
    369426char **irc_tokenize( char *buffer )
    370427{
    371         int i, j;
     428        int i, j, n = 3;
    372429        char **lines;
    373430
    374         /* Count the number of elements we're gonna need. */
    375         for( i = 0, j = 1; buffer[i] != '\0'; i ++ )
    376         {
    377                 if( buffer[i] == '\n' )
    378                         if( buffer[i+1] != '\r' && buffer[i+1] != '\n' )
    379                                 j ++;
    380         }
    381        
    382         /* Allocate j+1 elements. */
    383         lines = g_new( char *, j + 1 );
     431        /* Allocate n+1 elements. */
     432        lines = g_new( char *, n + 1 );
     433       
     434        lines[0] = buffer;
     435       
     436        /* Split the buffer in several strings, and accept any kind of line endings,
     437         * knowing that ERC on Windows may send something interesting like \r\r\n,
     438         * and surely there must be clients that think just \n is enough... */
     439        for( i = 0, j = 0; buffer[i] != '\0'; i ++ )
     440        {
     441                if( buffer[i] == '\r' || buffer[i] == '\n' )
     442                {
     443                        while( buffer[i] == '\r' || buffer[i] == '\n' )
     444                                buffer[i++] = '\0';
     445                       
     446                        lines[++j] = buffer + i;
     447                       
     448                        if( j >= n )
     449                        {
     450                                n *= 2;
     451                                lines = g_renew( char *, lines, n + 1 );
     452                        }
     453
     454                        if( buffer[i] == '\0' )
     455                                break;
     456                }
     457        }
    384458       
    385459        /* NULL terminate our list. */
    386         lines[j] = NULL;
    387        
    388         lines[0] = buffer;
    389        
    390         /* Split the buffer in several strings, using \r\n as our seperator, where \r is optional.
    391          * Although this is not in the RFC, some braindead ircds (newnet's) use this, so some clients might too.
    392          */
    393         for( i = 0, j = 0; buffer[i] != '\0'; i ++)
    394         {
    395                 if( buffer[i] == '\n' )
    396                 {
    397                         buffer[i] = '\0';
    398                        
    399                         if( i > 0 && buffer[i-1] == '\r' )
    400                                 buffer[i-1] = '\0';
    401                         if( buffer[i+1] != '\r' && buffer[i+1] != '\n' )
    402                                 lines[++j] = buffer + i + 1;
    403                 }
    404         }
    405        
    406         return( lines );
     460        lines[++j] = NULL;
     461       
     462        return lines;
    407463}
    408464
     
    538594
    539595        return;
    540 
    541596}
    542597
     
    544599{
    545600        int size;
    546         char line[IRC_MAX_LINE+1], *cs;
     601        char line[IRC_MAX_LINE+1];
    547602               
    548603        /* Don't try to write anything new anymore when shutting down. */
     
    550605                return;
    551606       
    552         line[IRC_MAX_LINE] = 0;
     607        memset( line, 0, sizeof( line ) );
    553608        g_vsnprintf( line, IRC_MAX_LINE - 2, format, params );
    554        
    555609        strip_newlines( line );
    556         if( ( cs = set_getstr( &irc->set, "charset" ) ) &&
    557             g_strcasecmp( cs, "none" ) != 0 && g_strcasecmp( cs, "utf-8" ) != 0 )
    558         {
    559                 char conv[IRC_MAX_LINE+1];
    560                
    561                 conv[IRC_MAX_LINE] = 0;
    562                 if( do_iconv( "UTF-8", cs, line, conv, 0, IRC_MAX_LINE - 2 ) != -1 )
    563                         strcpy( line, conv );
    564         }
    565         strcat( line, "\r\n" );
     610       
     611        if( irc->oconv != (GIConv) -1 )
     612        {
     613                gsize bytes_read, bytes_written;
     614                char *conv;
     615               
     616                conv = g_convert_with_iconv( line, -1, irc->oconv,
     617                                             &bytes_read, &bytes_written, NULL );
     618
     619                if( bytes_read == strlen( line ) )
     620                        strncpy( line, conv, IRC_MAX_LINE - 2 );
     621               
     622                g_free( conv );
     623        }
     624        g_strlcat( line, "\r\n", IRC_MAX_LINE + 1 );
    566625       
    567626        if( irc->sendbuffer != NULL )
     
    736795        irc_spawn( irc, u );
    737796       
    738         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." );
     797        irc_usermsg( irc, "Welcome to the BitlBee gateway!\n\n"
     798                          "If you've never used BitlBee before, please do read the help "
     799                          "information using the \x02help\x02 command. Lots of FAQs are "
     800                          "answered there.\n"
     801                          "If you already have an account on this server, just use the "
     802                          "\x02identify\x02 command to identify yourself." );
    739803       
    740804        if( global.conf->runmode == RUNMODE_FORKDAEMON || global.conf->runmode == RUNMODE_DAEMON )
     
    742806       
    743807        irc->status |= USTATUS_LOGGED_IN;
     808       
     809        /* This is for bug #209 (use PASS to identify to NickServ). */
     810        if( irc->password != NULL )
     811        {
     812                char *send_cmd[] = { "identify", g_strdup( irc->password ), NULL };
     813               
     814                irc_setpass( irc, NULL );
     815                root_command( irc, send_cmd );
     816                g_free( send_cmd[1] );
     817        }
    744818}
    745819
Note: See TracChangeset for help on using the changeset viewer.