Changeset 9fae35c for irc.c


Ignore:
Timestamp:
2006-01-23T23:28:13Z (18 years ago)
Author:
Jelmer Vernooij <jelmer@…>
Branches:
master
Children:
ec3e411
Parents:
7308b63 (diff), 68c7c14 (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 from Wilmer

File:
1 edited

Legend:

Unmodified
Added
Removed
  • irc.c

    r7308b63 r9fae35c  
    2727#include "bitlbee.h"
    2828#include "crypting.h"
     29#include "ipc.h"
    2930
    3031static gboolean irc_userping( gpointer _irc );
     
    4041irc_t *irc_new( int fd )
    4142{
    42         irc_t *irc = g_new0( irc_t, 1 );
    43        
     43        irc_t *irc;
     44        struct hostent *peer;
     45        unsigned int i;
     46        char buf[128];
     47#ifdef IPV6
     48        struct sockaddr_in6 sock[1];
     49#else
    4450        struct sockaddr_in sock[1];
    45 #ifdef IPV6
    46         struct sockaddr_in6 sock6[1];
    4751#endif
    48         struct hostent *peer;
    49         unsigned int i, j;
     52       
     53        irc = g_new0( irc_t, 1 );
    5054       
    5155        irc->fd = fd;
     
    7175       
    7276        i = sizeof( *sock );
    73 #ifdef IPV6
    74         j = sizeof( *sock6 );
    75 #endif
     77       
    7678        if( global.conf->hostname )
    7779                irc->myhost = g_strdup( global.conf->hostname );
    78         else if( getsockname( irc->fd, (struct sockaddr*) sock, &i ) == 0 && sock->sin_family == AF_INET )
    79         {
    80                 if( ( peer = gethostbyaddr( (char*) &sock->sin_addr, sizeof( sock->sin_addr ), AF_INET ) ) )
     80#ifdef IPV6
     81        else if( getsockname( irc->fd, (struct sockaddr*) sock, &i ) == 0 && sock->sin6_family == AF_INETx )
     82        {
     83                if( ( peer = gethostbyaddr( (char*) &sock->sin6_addr, sizeof( sock->sin6_addr ), AF_INETx ) ) )
    8184                        irc->myhost = g_strdup( peer->h_name );
    82         }
    83 #ifdef IPV6
    84         else if( getsockname( irc->fd, (struct sockaddr*) sock6, &j ) == 0 && sock6->sin6_family == AF_INET6 )
    85         {
    86                 if( ( peer = gethostbyaddr( (char*) &sock6->sin6_addr, sizeof( sock6->sin6_addr ), AF_INET6 ) ) )
     85                else if( inet_ntop( AF_INETx, &sock->sin6_addr, buf, sizeof( buf ) - 1 ) != NULL )
     86                        irc->myhost = g_strdup( ipv6_unwrap( buf ) );
     87        }
     88#else
     89        else if( getsockname( irc->fd, (struct sockaddr*) sock, &i ) == 0 && sock->sin_family == AF_INETx )
     90        {
     91                if( ( peer = gethostbyaddr( (char*) &sock->sin_addr, sizeof( sock->sin_addr ), AF_INETx ) ) )
    8792                        irc->myhost = g_strdup( peer->h_name );
     93                else if( inet_ntop( AF_INETx, &sock->sin_addr, buf, sizeof( buf ) - 1 ) != NULL )
     94                        irc->myhost = g_strdup( buf );
    8895        }
    8996#endif
     
    9198        i = sizeof( *sock );
    9299#ifdef IPV6
    93         j = sizeof( *sock6 );
     100        if( getpeername( irc->fd, (struct sockaddr*) sock, &i ) == 0 && sock->sin6_family == AF_INETx )
     101        {
     102                if( ( peer = gethostbyaddr( (char*) &sock->sin6_addr, sizeof( sock->sin6_addr ), AF_INETx ) ) )
     103                        irc->host = g_strdup( peer->h_name );
     104                else if( inet_ntop( AF_INETx, &sock->sin6_addr, buf, sizeof( buf ) - 1 ) != NULL )
     105                        irc->host = g_strdup( ipv6_unwrap( buf ) );
     106        }
     107#else
     108        if( getpeername( irc->fd, (struct sockaddr*) sock, &i ) == 0 && sock->sin_family == AF_INETx )
     109        {
     110                if( ( peer = gethostbyaddr( (char*) &sock->sin_addr, sizeof( sock->sin_addr ), AF_INETx ) ) )
     111                        irc->host = g_strdup( peer->h_name );
     112                else if( inet_ntop( AF_INETx, &sock->sin_addr, buf, sizeof( buf ) - 1 ) != NULL )
     113                        irc->host = g_strdup( buf );
     114        }
    94115#endif
    95         if( getpeername( irc->fd, (struct sockaddr*) sock, &i ) == 0 && sock->sin_family == AF_INET )
    96         {
    97                 if( ( peer = gethostbyaddr( (char*) &sock->sin_addr, sizeof( sock->sin_addr ), AF_INET ) ) )
    98                         irc->host = g_strdup( peer->h_name );
    99         }
    100 #ifdef IPV6
    101         else if( getpeername( irc->fd, (struct sockaddr*) sock6, &j ) == 0 && sock6->sin6_family == AF_INET6 )
    102         {
    103                 if( ( peer = gethostbyaddr( (char*) &sock6->sin6_addr, sizeof( sock6->sin6_addr ), AF_INET6 ) ) )
    104                         irc->host = g_strdup( peer->h_name );
    105         }
    106 #endif
    107        
     116       
     117        /* Rare, but possible. */
    108118        if( !irc->host ) irc->host = g_strdup( "localhost." );
    109119        if( !irc->myhost ) irc->myhost = g_strdup( "localhost." );
     
    142152}
    143153
     154/* immed=1 makes this function pretty much equal to irc_free(), except that
     155   this one will "log". In case the connection is already broken and we
     156   shouldn't try to write to it. */
     157void irc_abort( irc_t *irc, int immed, char *format, ... )
     158{
     159        if( format != NULL )
     160        {
     161                va_list params;
     162                char *reason;
     163               
     164                va_start( params, format );
     165                reason = g_strdup_vprintf( format, params );
     166                va_end( params );
     167               
     168                if( !immed )
     169                        irc_write( irc, "ERROR :Closing link: %s", reason );
     170               
     171                ipc_to_master_str( "OPERMSG :Client exiting: %s@%s [%s]\r\n",
     172                                   irc->nick ? irc->nick : "(NONE)", irc->host, reason );
     173               
     174                g_free( reason );
     175        }
     176        else
     177        {
     178                if( !immed )
     179                        irc_write( irc, "ERROR :Closing link" );
     180               
     181                ipc_to_master_str( "OPERMSG :Client exiting: %s@%s [%s]\r\n",
     182                                   irc->nick ? irc->nick : "(NONE)", irc->host, "No reason given" );
     183        }
     184       
     185        irc->status = USTATUS_SHUTDOWN;
     186        if( irc->sendbuffer && !immed )
     187        {
     188                /* We won't read from this socket anymore. Instead, we'll connect a timer
     189                   to it that should shut down the connection in a second, just in case
     190                   bitlbee_.._write doesn't do it first. */
     191               
     192                g_source_remove( irc->r_watch_source_id );
     193                irc->r_watch_source_id = g_timeout_add_full( G_PRIORITY_HIGH, 1000, (GSourceFunc) irc_free, irc, NULL );
     194        }
     195        else
     196        {
     197                irc_free( irc );
     198        }
     199}
     200
    144201static gboolean irc_free_userhash( gpointer key, gpointer value, gpointer data )
    145202{
     
    163220                if( storage_save( irc, TRUE ) != STORAGE_OK )
    164221                        irc_usermsg( irc, "Error while saving settings!" );
     222       
     223        closesocket( irc->fd );
    165224       
    166225        if( irc->ping_source_id > 0 )
     
    264323        g_free(irc);
    265324       
    266         if( global.conf->runmode == RUNMODE_INETD )
     325        if( global.conf->runmode == RUNMODE_INETD || global.conf->runmode == RUNMODE_FORKDAEMON )
    267326                g_main_quit( global.loop );
    268327}
     
    282341}
    283342
    284 int irc_process( irc_t *irc )
    285 {
    286         char **lines, *temp;   
     343void irc_process( irc_t *irc )
     344{
     345        char **lines, *temp, **cmd;
    287346        int i;
    288347
    289         if( irc->readbuffer != NULL ) {
    290                 lines = irc_tokenize(irc->readbuffer );
    291                 for( i = 0; *lines[i] != '\0'; i++ ) {
    292                         if( lines[i+1] == NULL ) {
     348        if( irc->readbuffer != NULL )
     349        {
     350                lines = irc_tokenize( irc->readbuffer );
     351               
     352                for( i = 0; *lines[i] != '\0'; i ++ )
     353                {
     354                        if( lines[i+1] == NULL )
     355                        {
    293356                                temp = g_strdup( lines[i] );
    294357                                g_free( irc->readbuffer );
    295358                                irc->readbuffer = temp;
    296                                 i++;
     359                                i ++;
    297360                                break;
    298361                        }                       
    299                         if (!irc_process_line(irc, lines[i])) {
     362                       
     363                        if( ( cmd = irc_parse_line( lines[i] ) ) == NULL )
     364                                continue;
     365                        irc_exec( irc, cmd );
     366                       
     367                        g_free( cmd );
     368                       
     369                        /* Shouldn't really happen, but just in case... */
     370                        if( !g_slist_find( irc_connection_list, irc ) )
     371                        {
    300372                                g_free( lines );
    301                                 return 0;
     373                                return;
    302374                        }
    303375                }
    304                 if(lines[i]!=NULL) {
    305                         g_free(irc->readbuffer);
    306                         irc->readbuffer=NULL;   
    307                 }
     376               
     377                if( lines[i] != NULL )
     378                {
     379                        g_free( irc->readbuffer );
     380                        irc->readbuffer = NULL;
     381                }
     382               
    308383                g_free( lines );
    309384        }
    310         return 1;       
    311385}
    312386
     
    317391
    318392        /* Count the number of elements we're gonna need. */
    319         for(i=0, j=1; buffer[i]!='\0'; i++ ) {
    320                 if(buffer[i]=='\n' )
    321                         if(buffer[i+1]!='\r' && buffer[i+1]!='\n')
    322                                 j++;
     393        for( i = 0, j = 1; buffer[i] != '\0'; i ++ )
     394        {
     395                if( buffer[i] == '\n' )
     396                        if( buffer[i+1] != '\r' && buffer[i+1] != '\n' )
     397                                j ++;
    323398        }
    324399       
    325400        /* Allocate j+1 elements. */
    326         lines=g_new (char *, j+1);
     401        lines = g_new( char *, j + 1 );
    327402       
    328403        /* NULL terminate our list. */
    329         lines[j]=NULL;
    330        
    331         lines[0]=buffer;
     404        lines[j] = NULL;
     405       
     406        lines[0] = buffer;
    332407       
    333408        /* Split the buffer in several strings, using \r\n as our seperator, where \r is optional.
    334409         * Although this is not in the RFC, some braindead ircds (newnet's) use this, so some clients might too.
    335410         */
    336         for( i=0, j=0; buffer[i]!='\0'; i++) {
    337                 if(buffer[i]=='\n') {
    338                         buffer[i]='\0';
    339 
    340                         /* We dont want to read 1 byte before our buffer
    341                          * and (in rare cases) generate a SIGSEGV.
    342                          */
    343                         if(i!=0)
    344                                 if(buffer[i-1]=='\r')
    345                                         buffer[i-1]='\0';
    346                         if(buffer[i+1]!='\r'&&buffer[i+1]!='\n')
    347                                 lines[++j]=buffer+i+1;
    348                 }
    349         }
    350 
    351         return(lines);
    352 }
    353 
    354 int irc_process_line( irc_t *irc, char *line )
     411        for( i = 0, j = 0; buffer[i] != '\0'; i ++)
     412        {
     413                if( buffer[i] == '\n' )
     414                {
     415                        buffer[i] = '\0';
     416                       
     417                        if( i > 0 && buffer[i-1] == '\r' )
     418                                buffer[i-1] = '\0';
     419                        if( buffer[i+1] != '\r' && buffer[i+1] != '\n' )
     420                                lines[++j] = buffer + i + 1;
     421                }
     422        }
     423       
     424        return( lines );
     425}
     426
     427char **irc_parse_line( char *line )
    355428{
    356429        int i, j;
     
    358431       
    359432        /* Move the line pointer to the start of the command, skipping spaces and the optional prefix. */
    360         if(line[0]==':') {
    361                 for(i=0; line[i]!=32; i++);
    362                 line=line+i;
    363         }
    364         for(i=0; line[i]==32; i++);
    365         line=line+i;
    366 
     433        if( line[0] == ':' )
     434        {
     435                for( i = 0; line[i] != ' '; i ++ );
     436                line = line + i;
     437        }
     438        for( i = 0; line[i] == ' '; i ++ );
     439        line = line + i;
     440       
    367441        /* If we're already at the end of the line, return. If not, we're going to need at least one element. */
    368         if(line[0]=='\0')
    369                 return 1;
    370         else
    371                 j=1;   
    372        
    373         /* Count the number of char **cmd elements we're going to need. */     
    374         for(i=0; line[i]!='\0'; i++) {
    375                 if((line[i]==32) && (line[i+1]!=32) && (line[i+1]!='\0') && (line[i+1]!=':'))           
    376                         j++;
    377                 else if((line[i]==':') && (line[i+1]!='\0') && (line[i-1]==32)) {
    378                         j++;
    379                         break;
    380                 }
     442        if( line[0] == '\0')
     443                return NULL;
     444       
     445        /* Count the number of char **cmd elements we're going to need. */
     446        j = 1;
     447        for( i = 0; line[i] != '\0'; i ++ )
     448        {
     449                if( line[i] == ' ' )
     450                {
     451                        j ++;
    381452                       
     453                        if( line[i+1] == ':' )
     454                                break;
     455                }
    382456        }       
    383457
    384458        /* Allocate the space we need. */
    385         cmd=g_new(char *, j+1);
    386         cmd[j]=NULL;
     459        cmd = g_new( char *, j + 1 );
     460        cmd[j] = NULL;
    387461       
    388462        /* Do the actual line splitting, format is:
     
    391465         */
    392466
    393         cmd[0]=line;
    394         for(i=0, j=0; line[i]!='\0'; i++) {
    395                 if((line[i]==32)) {
    396                         line[i]='\0';
    397                         if((line[i+1]!=32) && (line[i+1]!='\0') && (line[i+1]!=':'))           
    398                                 cmd[++j]=line+i+1;
    399                 }
    400                 else if((line[i]==':') && (line[i+1]!='\0') && (line[i-1]=='\0')) {
    401                         cmd[++j]=line+i+1;
    402                         break;
    403                 }
    404         }
    405        
    406         i=irc_exec(irc, cmd);
    407         g_free(cmd);
    408 
    409         return(i);     
    410 }
    411 
    412 int irc_exec( irc_t *irc, char **cmd )
    413 {       
    414         int i;
    415 
    416         if( (global.conf)->authmode == AUTHMODE_CLOSED && irc->status < USTATUS_AUTHORIZED )
    417         {
    418                 if( g_strcasecmp( cmd[0], "PASS" ) == 0 )
    419                 {
    420                         if( !cmd[1] )
     467        cmd[0] = line;
     468        for( i = 0, j = 0; line[i] != '\0'; i ++ )
     469        {
     470                if( line[i] == ' ' )
     471                {
     472                        line[i] = '\0';
     473                        cmd[++j] = line + i + 1;
     474                       
     475                        if( line[i+1] == ':' )
    421476                        {
    422                                 irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
     477                                cmd[j] ++;
     478                                break;
    423479                        }
    424                         else if( strcmp( cmd[1], (global.conf)->password ) == 0 )
    425                         {
    426                                 irc->status = USTATUS_AUTHORIZED;
    427                         }
    428                         else
    429                         {
    430                                 irc_reply( irc, 464, ":Nope, maybe you should try it again..." );
    431                         }
    432                 }
    433                 else
    434                 {
    435                         irc_reply( irc, 464, ":Uhh, fine, but I want the password first." );
    436                 }
    437                
    438                 return( 1 );
    439         }
    440        
    441         if( g_strcasecmp( cmd[0], "USER" ) == 0 )
    442         {
    443                 if( !( cmd[1] && cmd[2] && cmd[3] && cmd[4] ) )
    444                 {
    445                         irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
    446                 }
    447                 else if( irc->user )
    448                 {
    449                         irc_reply( irc, 462, ":You can't change your nick/userinfo" );
    450                 }
    451                 else
    452                 {
    453                         irc->user = g_strdup( cmd[1] );
    454                         irc->realname = g_strdup( cmd[4] );
    455                         if( irc->nick ) irc_login( irc );
    456                 }
    457                 return( 1 );
    458         }
    459         else if( g_strcasecmp( cmd[0], "NICK" ) == 0 )
    460         {
    461                 if( !cmd[1] )
    462                 {
    463                         irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
    464                 }
    465                 else if( irc->nick )
    466                 {
    467                         irc_reply( irc, 438, ":The hand of the deity is upon thee, thy nick may not change" );
    468                 }
    469                 /* This is not clean, but for now it'll have to be like this... */
    470                 else if( ( nick_cmp( cmd[1], irc->mynick ) == 0 ) || ( nick_cmp( cmd[1], NS_NICK ) == 0 ) )
    471                 {
    472                         irc_reply( irc, 433, ":This nick is already in use" );
    473                 }
    474                 else if( !nick_ok( cmd[1] ) )
    475                 {
    476                         /* [SH] Invalid characters. */
    477                         irc_reply( irc, 432, ":This nick contains invalid characters" );
    478                 }
    479                 else
    480                 {
    481                         irc->nick = g_strdup( cmd[1] );
    482                         if( irc->user ) irc_login( irc );
    483                 }
    484                 return( 1 );
    485         }
    486         else if( g_strcasecmp( cmd[0], "QUIT" ) == 0 )
    487         {
    488                 irc_write( irc, "ERROR :%s%s", cmd[1]?"Quit: ":"", cmd[1]?cmd[1]:"Client Quit" );
    489                 g_io_channel_close( irc->io_channel );
    490                 return( 0 );
    491         }
    492        
    493         if( !irc->user || !irc->nick )
    494         {
    495                 irc_reply( irc, 451, ":Register first" );
    496                 return( 1 );
    497         }
    498        
    499         if( g_strcasecmp( cmd[0], "PING" ) == 0 )
    500         {
    501                 irc_write( irc, ":%s PONG %s :%s", irc->myhost, irc->myhost, cmd[1]?cmd[1]:irc->myhost );
    502         }
    503         else if( g_strcasecmp( cmd[0], "MODE" ) == 0 )
    504         {
    505                 if( !cmd[1] )
    506                 {
    507                         irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
    508                 }
    509                 else if( *cmd[1] == '#' || *cmd[1] == '&' )
    510                 {
    511                         if( cmd[2] )
    512                         {
    513                                 if( *cmd[2] == '+' || *cmd[2] == '-' )
    514                                         irc_reply( irc, 477, "%s :Can't change channel modes", cmd[1] );
    515                                 else if( *cmd[2] == 'b' )
    516                                         irc_reply( irc, 368, "%s :No bans possible", cmd[1] );
    517                         }
    518                         else
    519                                 irc_reply( irc, 324, "%s +%s", cmd[1], CMODE );
    520                 }
    521                 else
    522                 {
    523                         if( nick_cmp( cmd[1], irc->nick ) == 0 )
    524                         {
    525                                 if( cmd[2] )
    526                                         irc_umode_set( irc, irc->nick, cmd[2] );
    527                         }
    528                         else
    529                                 irc_reply( irc, 502, ":Don't touch their modes" );
    530                 }
    531         }
    532         else if( g_strcasecmp( cmd[0], "NAMES" ) == 0 )
    533         {
    534                 irc_names( irc, cmd[1]?cmd[1]:irc->channel );
    535         }
    536         else if( g_strcasecmp( cmd[0], "PART" ) == 0 )
    537         {
    538                 struct conversation *c;
    539                
    540                 if( !cmd[1] )
    541                 {
    542                         irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
    543                 }
    544                 else if( g_strcasecmp( cmd[1], irc->channel ) == 0 )
    545                 {
    546                         user_t *u = user_find( irc, irc->nick );
    547                        
    548                         /* Not allowed to leave control channel */
    549                         irc_part( irc, u, irc->channel );
    550                         irc_join( irc, u, irc->channel );
    551                 }
    552                 else if( ( c = conv_findchannel( cmd[1] ) ) )
    553                 {
    554                         user_t *u = user_find( irc, irc->nick );
    555                        
    556                         irc_part( irc, u, c->channel );
    557                        
    558                         if( c->gc && c->gc->prpl )
    559                         {
    560                                 c->joined = 0;
    561                                 c->gc->prpl->chat_leave( c->gc, c->id );
    562                         }
    563                 }
    564                 else
    565                 {
    566                         irc_reply( irc, 403, "%s :No such channel", cmd[1] );
    567                 }
    568         }
    569         else if( g_strcasecmp( cmd[0], "JOIN" ) == 0 )
    570         {
    571                 if( !cmd[1] )
    572                 {
    573                         irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
    574                 }
    575                 else if( g_strcasecmp( cmd[1], irc->channel ) == 0 )
    576                         ; /* Dude, you're already there...
    577                              RFC doesn't have any reply for that though? */
    578                 else if( cmd[1] )
    579                 {
    580                         if( ( cmd[1][0] == '#' || cmd[1][0] == '&' ) && cmd[1][1] )
    581                         {
    582                                 user_t *u = user_find( irc, cmd[1] + 1 );
    583                                
    584                                 if( u && u->gc && u->gc->prpl && u->gc->prpl->chat_open )
    585                                 {
    586                                         irc_reply( irc, 403, "%s :Initializing groupchat in a different channel", cmd[1] );
    587                                        
    588                                         if( !u->gc->prpl->chat_open( u->gc, u->handle ) )
    589                                         {
    590                                                 irc_usermsg( irc, "Could not open a groupchat with %s, maybe you don't have a connection to him/her yet?", u->nick );
    591                                         }
    592                                 }
    593                                 else
    594                                 {
    595                                         irc_reply( irc, 403, "%s :Groupchats are not possible with %s", cmd[1], cmd[1]+1 );
    596                                 }
    597                         }
    598                         else
    599                         {
    600                                 irc_reply( irc, 403, "%s :No such channel", cmd[1] );
    601                         }
    602                 }
    603         }
    604         else if( g_strcasecmp( cmd[0], "INVITE" ) == 0 )
    605         {
    606                 if( cmd[1] && cmd[2] )
    607                         irc_invite( irc, cmd[1], cmd[2] );
    608                 else
    609                         irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
    610         }
    611         else if( g_strcasecmp( cmd[0], "PRIVMSG" ) == 0 || g_strcasecmp( cmd[0], "NOTICE" ) == 0 )
    612         {
    613                 if( !cmd[1] )
    614                 {
    615                         irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
    616                 }
    617                 else if ( !cmd[2] )
    618                 {
    619                         irc_reply( irc, 412, ":No text to send" );
    620                 }
    621                 else if ( irc->nick && g_strcasecmp( cmd[1], irc->nick ) == 0 )
    622                 {
    623                         irc_write( irc, ":%s!%s@%s %s %s :%s", irc->nick, irc->user, irc->host, cmd[0], cmd[1], cmd[2] );
    624                 }
    625                 else
    626                 {
    627                         if( g_strcasecmp( cmd[1], irc->channel ) == 0 )
    628                         {
    629                                 unsigned int i;
    630                                 char *t = set_getstr( irc, "default_target" );
    631                                
    632                                 if( g_strcasecmp( t, "last" ) == 0 && irc->last_target )
    633                                         cmd[1] = irc->last_target;
    634                                 else if( g_strcasecmp( t, "root" ) == 0 )
    635                                         cmd[1] = irc->mynick;
    636                                
    637                                 for( i = 0; i < strlen( cmd[2] ); i ++ )
    638                                 {
    639                                         if( cmd[2][i] == ' ' ) break;
    640                                         if( cmd[2][i] == ':' || cmd[2][i] == ',' )
    641                                         {
    642                                                 cmd[1] = cmd[2];
    643                                                 cmd[2] += i;
    644                                                 *cmd[2] = 0;
    645                                                 while( *(++cmd[2]) == ' ' );
    646                                                 break;
    647                                         }
    648                                 }
    649                                
    650                                 irc->is_private = 0;
    651                                
    652                                 if( cmd[1] != irc->last_target )
    653                                 {
    654                                         if( irc->last_target )
    655                                                 g_free( irc->last_target );
    656                                         irc->last_target = g_strdup( cmd[1] );
    657                                 }
    658                         }
    659                         else
    660                         {
    661                                 irc->is_private = 1;
    662                         }
    663                         irc_send( irc, cmd[1], cmd[2], ( g_strcasecmp( cmd[0], "NOTICE" ) == 0 ) ? IM_FLAG_AWAY : 0 );
    664                 }
    665         }
    666         else if( g_strcasecmp( cmd[0], "WHO" ) == 0 )
    667         {
    668                 irc_who( irc, cmd[1] );
    669         }
    670         else if( g_strcasecmp( cmd[0], "USERHOST" ) == 0 )
    671         {
    672                 user_t *u;
    673                
    674                 if( !cmd[1] )
    675                 {
    676                         irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
    677                 }
    678                 /* [TV] Usable USERHOST-implementation according to
    679                         RFC1459. Without this, mIRC shows an error
    680                         while connecting, and the used way of rejecting
    681                         breaks standards.
    682                 */
    683                
    684                 for( i = 1; cmd[i]; i ++ )
    685                         if( ( u = user_find( irc, cmd[i] ) ) )
    686                         {
    687                                 if( u->online && u->away )
    688                                         irc_reply( irc, 302, ":%s=-%s@%s", u->nick, u->user, u->host );
    689                                 else
    690                                         irc_reply( irc, 302, ":%s=+%s@%s", u->nick, u->user, u->host );
    691                         }
    692         }
    693         else if( g_strcasecmp( cmd[0], "ISON" ) == 0 )
    694         {
    695                 user_t *u;
    696                 char buff[IRC_MAX_LINE];
    697                 int lenleft;
    698                
    699                 buff[0] = '\0';
    700                
    701                 /* [SH] Leave room for : and \0 */
    702                 lenleft = IRC_MAX_LINE - 2;
    703                
    704                 for( i = 1; cmd[i]; i ++ )
    705                 {
    706                         if( ( u = user_find( irc, cmd[i] ) ) && u->online )
    707                         {
    708                                 /* [SH] Make sure we don't use too much buffer space. */
    709                                 lenleft -= strlen( u->nick ) + 1;
    710                                
    711                                 if( lenleft < 0 )
    712                                 {
    713                                         break;
    714                                 }
    715                                
    716                                 /* [SH] Add the nick to the buffer. Note
    717                                  * that an extra space is always added. Even
    718                                  * if it's the last nick in the list. Who
    719                                  * cares?
    720                                  */
    721                                
    722                                 strcat( buff, u->nick );
    723                                 strcat( buff, " " );
    724                         }
    725                 }
    726                
    727                 /* [WvG] Well, maybe someone cares, so why not remove it? */
    728                 if( strlen( buff ) > 0 )
    729                         buff[strlen(buff)-1] = '\0';
    730                
    731                 /* [SH] By the way, that really *was* WvG talking. */
    732                 /* [WvG] Really? */
    733                 /* [SH] Yeah... But *this* is WvG talking too. ;-P */
    734                 /* [WvG] *sigh* */
    735                
    736                 irc_reply( irc, 303, ":%s", buff );
    737         }
    738         else if( g_strcasecmp( cmd[0], "WATCH" ) == 0 )
    739         {
    740                 /* Obviously we could also mark a user structure as being
    741                    watched, but what if the WATCH command is sent right
    742                    after connecting? The user won't exist yet then... */
    743                 for( i = 1; cmd[i]; i ++ )
    744                 {
    745                         char *nick;
    746                         user_t *u;
    747                        
    748                         if( !cmd[i][0] || !cmd[i][1] )
    749                                 break;
    750                        
    751                         nick = g_strdup( cmd[i] + 1 );
    752                         nick_lc( nick );
    753                        
    754                         u = user_find( irc, nick );
    755                        
    756                         if( cmd[i][0] == '+' )
    757                         {
    758                                 if( !g_hash_table_lookup( irc->watches, nick ) )
    759                                         g_hash_table_insert( irc->watches, nick, nick );
    760                                
    761                                 if( u && u->online )
    762                                         irc_reply( irc, 604, "%s %s %s %d :%s", u->nick, u->user, u->host, time( NULL ), "is online" );
    763                                 else
    764                                         irc_reply( irc, 605, "%s %s %s %d :%s", nick, "*", "*", time( NULL ), "is offline" );
    765                         }
    766                         else if( cmd[i][0] == '-' )
    767                         {
    768                                 gpointer okey, ovalue;
    769                                
    770                                 if( g_hash_table_lookup_extended( irc->watches, nick, &okey, &ovalue ) )
    771                                 {
    772                                         g_free( okey );
    773                                         g_hash_table_remove( irc->watches, okey );
    774                                        
    775                                         irc_reply( irc, 602, "%s %s %s %d :%s", nick, "*", "*", 0, "Stopped watching" );
    776                                 }
    777                         }
    778                 }
    779         }
    780         else if( g_strcasecmp( cmd[0], "TOPIC" ) == 0 )
    781         {
    782                 if( cmd[1] && cmd[2] )
    783                         irc_reply( irc, 482, "%s :Cannot change topic", cmd[1] );
    784                 else if( cmd[1] )
    785                         irc_topic( irc, cmd[1] );
    786                 else
    787                         irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
    788         }
    789         else if( g_strcasecmp( cmd[0], "AWAY" ) == 0 )
    790         {
    791                 irc_away( irc, cmd[1] );
    792         }
    793         else if( g_strcasecmp( cmd[0], "WHOIS" ) == 0 )
    794         {
    795                 if( cmd[1] )
    796                 {
    797                         irc_whois( irc, cmd[1] );
    798                 }
    799                 else
    800                 {
    801                         irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
    802                 }
    803         }
    804         else if( g_strcasecmp( cmd[0], "WHOWAS" ) == 0 )
    805         {
    806                 /* For some reason irssi tries a whowas when whois fails. We can
    807                    ignore this, but then the user never gets a "user not found"
    808                    message from irssi which is a bit annoying. So just respond
    809                    with not-found and irssi users will get better error messages */
    810                
    811                 if( cmd[1] )
    812                 {
    813                         irc_reply( irc, 406, "%s :Nick does not exist", cmd[1] );
    814                         irc_reply( irc, 369, "%s :End of WHOWAS", cmd[1] );
    815                 }
    816                 else
    817                 {
    818                         irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
    819                 }
    820         }
    821         else if( ( g_strcasecmp( cmd[0], "NICKSERV" ) == 0 ) || ( g_strcasecmp( cmd[0], "NS" ) == 0 ) )
    822         {
    823                 /* [SH] This aliases the NickServ command to PRIVMSG root */
    824                 /* [TV] This aliases the NS command to PRIVMSG root as well */
    825                 root_command( irc, cmd + 1 );
    826         }
    827         else if( g_strcasecmp( cmd[0], "MOTD" ) == 0 )
    828         {
    829                 irc_motd( irc );
    830         }
    831         else if( g_strcasecmp( cmd[0], "PONG" ) == 0 )
    832         {
    833                 /* We could check the value we get back from the user, but in
    834                    fact we don't care, we're just happy he's still alive. */
    835                 irc->last_pong = gettime();
    836                 irc->pinging = 0;
    837         }
    838         else if( g_strcasecmp( cmd[0], "COMPLETIONS" ) == 0 )
    839         {
    840                 user_t *u = user_find( irc, irc->mynick );
    841                 help_t *h;
    842                 set_t *s;
    843                 int i;
    844                
    845                 irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", "OK" );
    846                
    847                 for( i = 0; commands[i].command; i ++ )
    848                         irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", commands[i].command );
    849                
    850                 for( h = global.help; h; h = h->next )
    851                         irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS help ", h->string );
    852                
    853                 for( s = irc->set; s; s = s->next )
    854                         irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS set ", s->key );
    855                
    856                 irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", "END" );
    857         }
    858         else if( set_getint( irc, "debug" ) )
    859         {
    860                 irc_usermsg( irc, "\002--- Unknown command:" );
    861                 for( i = 0; cmd[i]; i ++ ) irc_usermsg( irc, "%s", cmd[i] );
    862                 irc_usermsg( irc, "\002--------------------" );
    863         }
    864        
    865         return( 1 );
     480                }
     481        }
     482       
     483        return cmd;
     484}
     485
     486char *irc_build_line( char **cmd )
     487{
     488        int i, len;
     489        char *s;
     490       
     491        if( cmd[0] == NULL )
     492                return NULL;
     493       
     494        len = 1;
     495        for( i = 0; cmd[i]; i ++ )
     496                len += strlen( cmd[i] ) + 1;
     497       
     498        if( strchr( cmd[i-1], ' ' ) != NULL )
     499                len ++;
     500       
     501        s = g_new0( char, len + 1 );
     502        for( i = 0; cmd[i]; i ++ )
     503        {
     504                if( cmd[i+1] == NULL && strchr( cmd[i], ' ' ) != NULL )
     505                        strcat( s, ":" );
     506               
     507                strcat( s, cmd[i] );
     508               
     509                if( cmd[i+1] )
     510                        strcat( s, " " );
     511        }
     512        strcat( s, "\r\n" );
     513       
     514        return s;
    866515}
    867516
     
    923572        if( irc->sendbuffer != NULL ) {
    924573                size = strlen( irc->sendbuffer ) + strlen( line );
    925 #ifdef FLOOD_SEND
    926                 if( size > FLOOD_SEND_MAXBUFFER ) {
    927                         /* Die flooder, die! >:) */
    928 
    929                         g_free(irc->sendbuffer);
    930                        
    931                         /* We need the \r\n at the start because else we might append our string to a half
    932                          * sent line. A bit hackish, but it works.
    933                          */
    934                         irc->sendbuffer = g_strdup( "\r\nERROR :Sendq Exceeded\r\n" );
    935                         irc->quit = 1;
    936                        
    937                         return;
    938                 }
    939 #endif
    940574                irc->sendbuffer = g_renew ( char, irc->sendbuffer, size + 1 );
    941575                strcpy( ( irc->sendbuffer + strlen( irc->sendbuffer ) ), line );
     
    1037671}
    1038672
    1039 void irc_who( irc_t *irc, char *channel )
    1040 {
    1041         user_t *u = irc->users;
    1042         struct conversation *c;
    1043         GList *l;
    1044        
    1045         if( !channel || *channel == '0' || *channel == '*' || !*channel )
    1046                 while( u )
    1047                 {
    1048                         irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", u->online ? irc->channel : "*", u->user, u->host, irc->myhost, u->nick, u->online ? ( u->away ? 'G' : 'H' ) : 'G', u->realname );
    1049                         u = u->next;
    1050                 }
    1051         else if( g_strcasecmp( channel, irc->channel ) == 0 )
    1052                 while( u )
    1053                 {
    1054                         if( u->online )
    1055                                 irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->away ? 'G' : 'H', u->realname );
    1056                         u = u->next;
    1057                 }
    1058         else if( ( c = conv_findchannel( channel ) ) )
    1059                 for( l = c->in_room; l; l = l->next )
    1060                 {
    1061                         if( ( u = user_findhandle( c->gc, l->data ) ) )
    1062                                 irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->away ? 'G' : 'H', u->realname );
    1063                 }
    1064         else if( ( u = user_find( irc, channel ) ) )
    1065                 irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->online ? ( u->away ? 'G' : 'H' ) : 'G', u->realname );
    1066        
    1067         irc_reply( irc, 315, "%s :End of /WHO list.", channel?channel:"**" );
     673int irc_check_login( irc_t *irc )
     674{
     675        if( irc->user && irc->nick )
     676        {
     677                if( global.conf->authmode == AUTHMODE_CLOSED && irc->status < USTATUS_AUTHORIZED )
     678                {
     679                        irc_reply( irc, 464, ":This server is password-protected." );
     680                        return 0;
     681                }
     682                else
     683                {
     684                        irc_login( irc );
     685                        return 1;
     686                }
     687        }
     688        else
     689        {
     690                /* More information needed. */
     691                return 0;
     692        }
    1068693}
    1069694
     
    1075700        irc_reply( irc,   2, ":Host %s is running BitlBee " BITLBEE_VERSION " " ARCH "/" CPU ".", irc->myhost );
    1076701        irc_reply( irc,   3, ":%s", IRCD_INFO );
    1077         irc_reply( irc,   4, "%s %s %s %s", irc->myhost, BITLBEE_VERSION, UMODES, CMODES );
     702        irc_reply( irc,   4, "%s %s %s %s", irc->myhost, BITLBEE_VERSION, UMODES UMODES_PRIV, CMODES );
    1078703        irc_reply( irc,   5, "PREFIX=(ov)@+ CHANTYPES=#& CHANMODES=,,,%s NICKLEN=%d NETWORK=BitlBee CASEMAPPING=rfc1459 MAXTARGETS=1 WATCH=128 :are supported by this server", CMODES, MAX_NICK_LENGTH - 1 );
    1079704        irc_motd( irc );
    1080         irc_umode_set( irc, irc->myhost, "+" UMODE );
     705        irc_umode_set( irc, "+" UMODE, 1 );
    1081706
    1082707        u = user_add( irc, irc->mynick );
     
    1100725        u->realname = g_strdup( irc->realname );
    1101726        u->online = 1;
    1102 //      u->send_handler = msg_echo;
    1103727        irc_spawn( irc, u );
    1104728       
    1105729        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 FAQ's are answered there." );
     730       
     731        if( global.conf->runmode == RUNMODE_FORKDAEMON || global.conf->runmode == RUNMODE_DAEMON )
     732                ipc_to_master_str( "CLIENT %s %s :%s\r\n", irc->host, irc->nick, irc->realname );
    1106733       
    1107734        irc->status = USTATUS_LOGGED_IN;
     
    1156783                }
    1157784                irc_reply( irc, 376, ":End of MOTD" );
    1158                 closesocket( fd );
     785                close( fd );
    1159786        }
    1160787}
     
    1177804}
    1178805
    1179 void irc_whois( irc_t *irc, char *nick )
    1180 {
    1181         user_t *u = user_find( irc, nick );
    1182        
    1183         if( u )
    1184         {
    1185                 irc_reply( irc, 311, "%s %s %s * :%s", u->nick, u->user, u->host, u->realname );
    1186                
    1187                 if( u->gc )
    1188                         irc_reply( irc, 312, "%s %s.%s :%s network", u->nick, u->gc->user->username,
    1189                                    *u->gc->user->proto_opt[0] ? u->gc->user->proto_opt[0] : "", u->gc->prpl->name );
    1190                 else
    1191                         irc_reply( irc, 312, "%s %s :%s", u->nick, irc->myhost, IRCD_INFO );
    1192                
    1193                 if( !u->online )
    1194                         irc_reply( irc, 301, "%s :%s", u->nick, "User is offline" );
    1195                 else if( u->away )
    1196                         irc_reply( irc, 301, "%s :%s", u->nick, u->away );
    1197                
    1198                 irc_reply( irc, 318, "%s :End of /WHOIS list", nick );
    1199         }
    1200         else
    1201         {
    1202                 irc_reply( irc, 401, "%s :Nick does not exist", nick );
    1203         }
    1204 }
    1205 
    1206 
    1207 void irc_umode_set( irc_t *irc, char *who, char *s )
    1208 {
     806void irc_umode_set( irc_t *irc, char *s, int allow_priv )
     807{
     808        /* allow_priv: Set to 0 if s contains user input, 1 if you want
     809           to set a "privileged" mode (+o, +R, etc). */
    1209810        char m[256], st = 1, *t;
    1210811        int i;
     
    1219820                if( *t == '+' || *t == '-' )
    1220821                        st = *t == '+';
    1221                 else
     822                else if( st == 0 || ( strchr( UMODES, *t ) || ( allow_priv && strchr( UMODES_PRIV, *t ) ) ) )
    1222823                        m[(int)*t] = st;
    1223824        }
     
    1226827       
    1227828        for( i = 0; i < 256 && strlen( irc->umode ) < ( sizeof( irc->umode ) - 1 ); i ++ )
    1228                 if( m[i] && strchr( UMODES, i ) )
     829                if( m[i] )
    1229830                        irc->umode[strlen(irc->umode)] = i;
    1230831       
    1231832        irc_reply( irc, 221, "+%s", irc->umode );
    1232 }
    1233 
    1234 int irc_away( irc_t *irc, char *away )
    1235 {
    1236         user_t *u = user_find( irc, irc->nick );
    1237         GSList *c = get_connections();
    1238        
    1239         if( !u ) return( 0 );
    1240        
    1241         if( away && *away )
    1242         {
    1243                 int i, j;
    1244                
    1245                 /* Copy away string, but skip control chars. Mainly because
    1246                    Jabber really doesn't like them. */
    1247                 u->away = g_malloc( strlen( away ) + 1 );
    1248                 for( i = j = 0; away[i]; i ++ )
    1249                         if( ( u->away[j] = away[i] ) >= ' ' )
    1250                                 j ++;
    1251                 u->away[j] = 0;
    1252                
    1253                 irc_reply( irc, 306, ":You're now away: %s", u->away );
    1254                 /* irc_umode_set( irc, irc->myhost, "+a" ); */
    1255         }
    1256         else
    1257         {
    1258                 if( u->away ) g_free( u->away );
    1259                 u->away = NULL;
    1260                 /* irc_umode_set( irc, irc->myhost, "-a" ); */
    1261                 irc_reply( irc, 305, ":Welcome back" );
    1262         }
    1263        
    1264         while( c )
    1265         {
    1266                 if( ((struct gaim_connection *)c->data)->flags & OPT_LOGGED_IN )
    1267                         proto_away( c->data, u->away );
    1268                
    1269                 c = c->next;
    1270         }
    1271        
    1272         return( 1 );
    1273833}
    1274834
     
    1324884        }
    1325885        g_free( nick );
    1326 }
    1327 
    1328 void irc_invite( irc_t *irc, char *nick, char *channel )
    1329 {
    1330         struct conversation *c = conv_findchannel( channel );
    1331         user_t *u = user_find( irc, nick );
    1332        
    1333         if( u && c && ( u->gc == c->gc ) )
    1334                 if( c->gc && c->gc->prpl && c->gc->prpl->chat_invite )
    1335                 {
    1336                         c->gc->prpl->chat_invite( c->gc, c->id, "", u->handle );
    1337                         irc_reply( irc, 341, "%s %s", nick, channel );
    1338                         return;
    1339                 }
    1340        
    1341         irc_reply( irc, 482, "%s :Invite impossible; User/Channel non-existent or incompatible", channel );
    1342886}
    1343887
     
    1430974               
    1431975                if( u->send_handler )
    1432                         return( u->send_handler( irc, u, s, flags ) );
     976                {
     977                        u->send_handler( irc, u, s, flags );
     978                        return 1;
     979                }
    1433980        }
    1434981        else if( c && c->gc && c->gc->prpl )
     
    14561003}
    14571004
    1458 int buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags )
    1459 {
    1460         if( !u || !u->gc ) return( 0 );
     1005void buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags )
     1006{
     1007        if( !u || !u->gc ) return;
    14611008       
    14621009        if( set_getint( irc, "buddy_sendbuffer" ) && set_getint( irc, "buddy_sendbuffer_delay" ) > 0 )
     
    14941041                        g_source_remove( u->sendbuf_timer );
    14951042                u->sendbuf_timer = g_timeout_add( delay, buddy_send_handler_delayed, u );
    1496                
    1497                 return( 1 );
    14981043        }
    14991044        else
    15001045        {
    1501                 return( serv_send_im( irc, u, msg, flags ) );
     1046                serv_send_im( irc, u, msg, flags );
    15021047        }
    15031048}
     
    16041149        if( rv > 0 )
    16051150        {
    1606                 irc_write( irc, "ERROR :Closing Link: Ping Timeout: %d seconds", rv );
    1607                 irc_free( irc );
     1151                irc_abort( irc, 0, "Ping Timeout: %d seconds", rv );
    16081152                return FALSE;
    16091153        }
Note: See TracChangeset for help on using the changeset viewer.