source: irc.c @ 0b5cc72

Last change on this file since 0b5cc72 was fb117aee, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-04-02T02:29:45Z

Cleaned lots of compiler warnings so I can get some signal again.

  • Property mode set to 100644
File size: 19.4 KB
RevLine 
[b7d3cc34]1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2004 Wilmer van der Gaast and others                *
5  \********************************************************************/
6
[3ddb7477]7/* The IRC-based UI (for now the only one)                              */
[b7d3cc34]8
9/*
10  This program is free software; you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation; either version 2 of the License, or
13  (at your option) any later version.
14
15  This program is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  GNU General Public License for more details.
19
20  You should have received a copy of the GNU General Public License with
21  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
22  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
23  Suite 330, Boston, MA  02111-1307  USA
24*/
25
26#include "bitlbee.h"
[fb117aee]27#include "ipc.h"
[b7d3cc34]28
[3ddb7477]29GSList *irc_connection_list;
[b7d3cc34]30
[3923003]31static gboolean irc_userping( gpointer _irc, gint fd, b_input_condition cond );
[3ddb7477]32static char *set_eval_charset( set_t *set, char *value );
[58adb7e]33
[b7d3cc34]34irc_t *irc_new( int fd )
35{
[e4d6271]36        irc_t *irc;
[e9b755e]37        struct sockaddr_storage sock;
[7435ccf]38        socklen_t socklen = sizeof( sock );
[3ddb7477]39        char *host = NULL, *myhost = NULL;
40        irc_user_t *iu;
[7125cb3]41        set_t *s;
[3ddb7477]42        bee_t *b;
[e4d6271]43       
44        irc = g_new0( irc_t, 1 );
[b7d3cc34]45       
46        irc->fd = fd;
[a0d04d6]47        sock_make_nonblocking( irc->fd );
48       
[ba9edaa]49        irc->r_watch_source_id = b_input_add( irc->fd, GAIM_INPUT_READ, bitlbee_io_current_client_read, irc );
[b7d3cc34]50       
51        irc->status = USTATUS_OFFLINE;
52        irc->last_pong = gettime();
53       
[3ddb7477]54        irc->nick_user_hash = g_hash_table_new( g_str_hash, g_str_equal );
[b7d3cc34]55        irc->watches = g_hash_table_new( g_str_hash, g_str_equal );
56       
[f9756bd]57        irc->iconv = (GIConv) -1;
58        irc->oconv = (GIConv) -1;
59       
[b7d3cc34]60        if( global.conf->hostname )
61        {
[3ddb7477]62                myhost = g_strdup( global.conf->hostname );
[b7d3cc34]63        }
[7435ccf]64        else if( getsockname( irc->fd, (struct sockaddr*) &sock, &socklen ) == 0 ) 
[b7d3cc34]65        {
[2231302]66                char buf[NI_MAXHOST+1];
[e9b755e]67
[2231302]68                if( getnameinfo( (struct sockaddr *) &sock, socklen, buf,
[c84e31a]69                                 NI_MAXHOST, NULL, 0, 0 ) == 0 )
[2231302]70                {
[3ddb7477]71                        myhost = g_strdup( ipv6_unwrap( buf ) );
[2231302]72                }
[b7d3cc34]73        }
74       
[7435ccf]75        if( getpeername( irc->fd, (struct sockaddr*) &sock, &socklen ) == 0 )
[b7d3cc34]76        {
[2231302]77                char buf[NI_MAXHOST+1];
[e9b755e]78
[2231302]79                if( getnameinfo( (struct sockaddr *)&sock, socklen, buf,
[c84e31a]80                                 NI_MAXHOST, NULL, 0, 0 ) == 0 )
[2231302]81                {
[3ddb7477]82                        host = g_strdup( ipv6_unwrap( buf ) );
[2231302]83                }
[b7d3cc34]84        }
85       
[3ddb7477]86        if( host == NULL )
87                host = g_strdup( "localhost.localdomain" );
88        if( myhost == NULL )
89                myhost = g_strdup( "localhost.localdomain" );
[3e1e11af]90       
[3923003]91        if( global.conf->ping_interval > 0 && global.conf->ping_timeout > 0 )
92                irc->ping_source_id = b_timeout_add( global.conf->ping_interval * 1000, irc_userping, irc );
[b7d3cc34]93
94        irc_connection_list = g_slist_append( irc_connection_list, irc );
95       
[3ddb7477]96        b = irc->b = bee_new();
[d860a8d]97        b->ui_data = irc;
98        b->ui = &irc_ui_funcs;
[3ddb7477]99       
100        s = set_add( &b->set, "away_devoice", "true", NULL/*set_eval_away_devoice*/, irc );
101        s = set_add( &b->set, "buddy_sendbuffer", "false", set_eval_bool, irc );
102        s = set_add( &b->set, "buddy_sendbuffer_delay", "200", set_eval_int, irc );
103        s = set_add( &b->set, "charset", "utf-8", set_eval_charset, irc );
104        //s = set_add( &b->set, "control_channel", irc->channel, NULL/*set_eval_control_channel*/, irc );
105        s = set_add( &b->set, "default_target", "root", NULL, irc );
106        s = set_add( &b->set, "display_namechanges", "false", set_eval_bool, irc );
107        s = set_add( &b->set, "handle_unknown", "root", NULL, irc );
108        s = set_add( &b->set, "lcnicks", "true", set_eval_bool, irc );
109        s = set_add( &b->set, "ops", "both", NULL/*set_eval_ops*/, irc );
110        s = set_add( &b->set, "private", "true", set_eval_bool, irc );
111        s = set_add( &b->set, "query_order", "lifo", NULL, irc );
112        s = set_add( &b->set, "root_nick", ROOT_NICK, NULL/*set_eval_root_nick*/, irc );
113        s = set_add( &b->set, "simulate_netsplit", "true", set_eval_bool, irc );
114        s = set_add( &b->set, "to_char", ": ", set_eval_to_char, irc );
115        s = set_add( &b->set, "typing_notice", "false", set_eval_bool, irc );
116
117        irc->root = iu = irc_user_new( irc, ROOT_NICK );
118        iu->host = g_strdup( myhost );
119        iu->fullname = g_strdup( ROOT_FN );
[280c56a]120        iu->f = &irc_user_root_funcs;
[3ddb7477]121       
122        iu = irc_user_new( irc, NS_NICK );
123        iu->host = g_strdup( myhost );
124        iu->fullname = g_strdup( ROOT_FN );
[280c56a]125        iu->f = &irc_user_root_funcs;
[3ddb7477]126       
127        irc->user = g_new0( irc_user_t, 1 );
128        irc->user->host = g_strdup( host );
129       
[ebaebfe]130        conf_loaddefaults( irc );
[b7d3cc34]131       
[f9756bd]132        /* Evaluator sets the iconv/oconv structures. */
[3ddb7477]133        set_eval_charset( set_find( &b->set, "charset" ), set_getstr( &b->set, "charset" ) );
[f9756bd]134       
[3ddb7477]135        irc_write( irc, ":%s NOTICE AUTH :%s", irc->root->host, "BitlBee-IRCd initialized, please go on" );
136       
[ebaebfe]137        g_free( myhost );
138        g_free( host );
139       
[3ddb7477]140        return irc;
[b7d3cc34]141}
142
[f73b969]143/* immed=1 makes this function pretty much equal to irc_free(), except that
144   this one will "log". In case the connection is already broken and we
145   shouldn't try to write to it. */
[fc50d48]146void irc_abort( irc_t *irc, int immed, char *format, ... )
[c1826c6]147{
[fc50d48]148        if( format != NULL )
149        {
[f73b969]150                va_list params;
[fc50d48]151                char *reason;
152               
153                va_start( params, format );
[f73b969]154                reason = g_strdup_vprintf( format, params );
[fc50d48]155                va_end( params );
156               
157                if( !immed )
158                        irc_write( irc, "ERROR :Closing link: %s", reason );
159               
160                ipc_to_master_str( "OPERMSG :Client exiting: %s@%s [%s]\r\n",
[3ddb7477]161                                   irc->user->nick ? irc->user->nick : "(NONE)", irc->root->host, reason );
[fc50d48]162               
163                g_free( reason );
164        }
165        else
166        {
167                if( !immed )
168                        irc_write( irc, "ERROR :Closing link" );
169               
170                ipc_to_master_str( "OPERMSG :Client exiting: %s@%s [%s]\r\n",
[3ddb7477]171                                   irc->user->nick ? irc->user->nick : "(NONE)", irc->root->host, "No reason given" );
[fc50d48]172        }
173       
[79e826a]174        irc->status |= USTATUS_SHUTDOWN;
[fc50d48]175        if( irc->sendbuffer && !immed )
[c1826c6]176        {
[883a398]177                /* Set up a timeout event that should shut down the connection
178                   in a second, just in case ..._write doesn't do it first. */
[fc50d48]179               
[ba9edaa]180                b_event_remove( irc->r_watch_source_id );
[883a398]181                irc->r_watch_source_id = 0;
182               
183                b_event_remove( irc->ping_source_id );
184                irc->ping_source_id = b_timeout_add( 1000, (b_event_handler) irc_free, irc );
[c1826c6]185        }
186        else
187        {
188                irc_free( irc );
189        }
190}
191
[3ddb7477]192static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data );
[b7d3cc34]193
[fa75134]194void irc_free( irc_t * irc )
[b7d3cc34]195{
196        log_message( LOGLVL_INFO, "Destroying connection with fd %d", irc->fd );
197       
[3ddb7477]198        /*
199        if( irc->status & USTATUS_IDENTIFIED && set_getbool( &irc->b->set, "save_on_quit" ) )
[3183c21]200                if( storage_save( irc, NULL, TRUE ) != STORAGE_OK )
[b7d3cc34]201                        irc_usermsg( irc, "Error while saving settings!" );
[3ddb7477]202        */
[b7d3cc34]203       
204        irc_connection_list = g_slist_remove( irc_connection_list, irc );
205       
[3ddb7477]206        /*
[fa75134]207        while( irc->queries != NULL )
208                query_del( irc, irc->queries );
[3ddb7477]209        */
[5b52a48]210       
[3ddb7477]211        while( irc->users )
[ebaebfe]212        {
213                irc_user_t *iu = irc->users->data;
214                irc_user_free( irc, iu->nick );
215        }
[b7d3cc34]216       
[63a520b]217        while( irc->channels )
218                irc_channel_free( irc->channels->data );
219       
[fa75134]220        if( irc->ping_source_id > 0 )
221                b_event_remove( irc->ping_source_id );
[883a398]222        if( irc->r_watch_source_id > 0 )
223                b_event_remove( irc->r_watch_source_id );
[fa75134]224        if( irc->w_watch_source_id > 0 )
225                b_event_remove( irc->w_watch_source_id );
226       
227        closesocket( irc->fd );
228        irc->fd = -1;
229       
[3ddb7477]230        g_hash_table_foreach_remove( irc->nick_user_hash, irc_free_hashkey, NULL );
231        g_hash_table_destroy( irc->nick_user_hash );
[b7d3cc34]232       
[fa75134]233        g_hash_table_foreach_remove( irc->watches, irc_free_hashkey, NULL );
234        g_hash_table_destroy( irc->watches );
[b7d3cc34]235       
[f9756bd]236        if( irc->iconv != (GIConv) -1 )
237                g_iconv_close( irc->iconv );
238        if( irc->oconv != (GIConv) -1 )
239                g_iconv_close( irc->oconv );
240       
[fa75134]241        g_free( irc->sendbuffer );
242        g_free( irc->readbuffer );
243       
244        g_free( irc->password );
245       
246        g_free( irc );
[b7d3cc34]247       
[565a1ea]248        if( global.conf->runmode == RUNMODE_INETD ||
249            global.conf->runmode == RUNMODE_FORKDAEMON ||
250            ( global.conf->runmode == RUNMODE_DAEMON &&
251              global.listen_socket == -1 &&
252              irc_connection_list == NULL ) )
[ba9edaa]253                b_main_quit();
[b7d3cc34]254}
255
[3ddb7477]256static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data )
[7cad7b4]257{
[3ddb7477]258        g_free( key );
[7cad7b4]259       
[3ddb7477]260        return( TRUE );
[7cad7b4]261}
262
[3ddb7477]263static char **irc_splitlines( char *buffer );
264
[f73b969]265void irc_process( irc_t *irc )
[b7d3cc34]266{
[f9756bd]267        char **lines, *temp, **cmd;
[b7d3cc34]268        int i;
269
[de3e100]270        if( irc->readbuffer != NULL )
271        {
[3ddb7477]272                lines = irc_splitlines( irc->readbuffer );
[de3e100]273               
274                for( i = 0; *lines[i] != '\0'; i ++ )
275                {
[f9756bd]276                        char *conv = NULL;
[7d31002]277                       
[18ff38f]278                        /* [WvG] If the last line isn't empty, it's an incomplete line and we
279                           should wait for the rest to come in before processing it. */
[de3e100]280                        if( lines[i+1] == NULL )
281                        {
[b7d3cc34]282                                temp = g_strdup( lines[i] );
283                                g_free( irc->readbuffer );
284                                irc->readbuffer = temp;
[de3e100]285                                i ++;
[b7d3cc34]286                                break;
[e27661d]287                        }
288                       
[f9756bd]289                        if( irc->iconv != (GIConv) -1 )
[e27661d]290                        {
[f9756bd]291                                gsize bytes_read, bytes_written;
292                               
293                                conv = g_convert_with_iconv( lines[i], -1, irc->iconv,
294                                                             &bytes_read, &bytes_written, NULL );
295                               
296                                if( conv == NULL || bytes_read != strlen( lines[i] ) )
[94d52d64]297                                {
[fc0cf92]298                                        /* GLib can do strange things if things are not in the expected charset,
299                                           so let's be a little bit paranoid here: */
[94d52d64]300                                        if( irc->status & USTATUS_LOGGED_IN )
[fc0cf92]301                                        {
[43462708]302                                                irc_usermsg( irc, "Error: Charset mismatch detected. The charset "
[94d52d64]303                                                                  "setting is currently set to %s, so please make "
304                                                                  "sure your IRC client will send and accept text in "
305                                                                  "that charset, or tell BitlBee which charset to "
306                                                                  "expect by changing the charset setting. See "
307                                                                  "`help set charset' for more information. Your "
[f9756bd]308                                                                  "message was ignored.",
[3ddb7477]309                                                                  set_getstr( &irc->b->set, "charset" ) );
[f9756bd]310                                               
311                                                g_free( conv );
312                                                conv = NULL;
[fc0cf92]313                                        }
314                                        else
315                                        {
[3ddb7477]316                                                irc_write( irc, ":%s NOTICE AUTH :%s", irc->root->host,
[a83442a]317                                                           "Warning: invalid characters received at login time." );
[fc0cf92]318                                               
[f9756bd]319                                                conv = g_strdup( lines[i] );
[fc0cf92]320                                                for( temp = conv; *temp; temp ++ )
321                                                        if( *temp & 0x80 )
322                                                                *temp = '?';
323                                        }
[94d52d64]324                                }
325                                lines[i] = conv;
[e27661d]326                        }
[de3e100]327                       
[e1720ce]328                        if( lines[i] && ( cmd = irc_parse_line( lines[i] ) ) )
[f9756bd]329                        {
330                                irc_exec( irc, cmd );
331                                g_free( cmd );
332                        }
[f73b969]333                       
[f9756bd]334                        g_free( conv );
[f73b969]335                       
336                        /* Shouldn't really happen, but just in case... */
337                        if( !g_slist_find( irc_connection_list, irc ) )
[de3e100]338                        {
[b7d3cc34]339                                g_free( lines );
[f73b969]340                                return;
[b7d3cc34]341                        }
342                }
[de3e100]343               
344                if( lines[i] != NULL )
345                {
346                        g_free( irc->readbuffer );
[0431ea1]347                        irc->readbuffer = NULL;
[b7d3cc34]348                }
[de3e100]349               
[b7d3cc34]350                g_free( lines );
351        }
352}
353
[3ddb7477]354/* Splits a long string into separate lines. The array is NULL-terminated
355   and, unless the string contains an incomplete line at the end, ends with
356   an empty string. Could use g_strsplit() but this one does it in-place.
357   (So yes, it's destructive.) */
358static char **irc_splitlines( char *buffer )
[b7d3cc34]359{
[18ff38f]360        int i, j, n = 3;
[b7d3cc34]361        char **lines;
362
[18ff38f]363        /* Allocate n+1 elements. */
364        lines = g_new( char *, n + 1 );
[b7d3cc34]365       
[de3e100]366        lines[0] = buffer;
[b7d3cc34]367       
[18ff38f]368        /* Split the buffer in several strings, and accept any kind of line endings,
369         * knowing that ERC on Windows may send something interesting like \r\r\n,
370         * and surely there must be clients that think just \n is enough... */
371        for( i = 0, j = 0; buffer[i] != '\0'; i ++ )
[de3e100]372        {
[18ff38f]373                if( buffer[i] == '\r' || buffer[i] == '\n' )
[de3e100]374                {
[18ff38f]375                        while( buffer[i] == '\r' || buffer[i] == '\n' )
376                                buffer[i++] = '\0';
377                       
378                        lines[++j] = buffer + i;
[de3e100]379                       
[18ff38f]380                        if( j >= n )
381                        {
382                                n *= 2;
383                                lines = g_renew( char *, lines, n + 1 );
384                        }
385
386                        if( buffer[i] == '\0' )
387                                break;
[b7d3cc34]388                }
389        }
[de3e100]390       
[18ff38f]391        /* NULL terminate our list. */ 
392        lines[++j] = NULL;
393       
394        return lines;
[b7d3cc34]395}
396
[e27661d]397/* Split an IRC-style line into little parts/arguments. */
[0431ea1]398char **irc_parse_line( char *line )
[b7d3cc34]399{
400        int i, j;
401        char **cmd;
402       
403        /* Move the line pointer to the start of the command, skipping spaces and the optional prefix. */
[de3e100]404        if( line[0] == ':' )
405        {
[e1720ce]406                for( i = 0; line[i] && line[i] != ' '; i ++ );
[de3e100]407                line = line + i;
[b7d3cc34]408        }
[de3e100]409        for( i = 0; line[i] == ' '; i ++ );
410        line = line + i;
411       
[b7d3cc34]412        /* If we're already at the end of the line, return. If not, we're going to need at least one element. */
[de3e100]413        if( line[0] == '\0')
414                return NULL;
415       
416        /* Count the number of char **cmd elements we're going to need. */
417        j = 1;
418        for( i = 0; line[i] != '\0'; i ++ )
419        {
420                if( line[i] == ' ' )
421                {
422                        j ++;
[b7d3cc34]423                       
[de3e100]424                        if( line[i+1] == ':' )
425                                break;
426                }
[b7d3cc34]427        }       
428
429        /* Allocate the space we need. */
[de3e100]430        cmd = g_new( char *, j + 1 );
431        cmd[j] = NULL;
[b7d3cc34]432       
433        /* Do the actual line splitting, format is:
434         * Input: "PRIVMSG #bitlbee :foo bar"
435         * Output: cmd[0]=="PRIVMSG", cmd[1]=="#bitlbee", cmd[2]=="foo bar", cmd[3]==NULL
436         */
437
[de3e100]438        cmd[0] = line;
439        for( i = 0, j = 0; line[i] != '\0'; i ++ )
[b7d3cc34]440        {
[de3e100]441                if( line[i] == ' ' )
[b7d3cc34]442                {
[de3e100]443                        line[i] = '\0';
444                        cmd[++j] = line + i + 1;
[b7d3cc34]445                       
[de3e100]446                        if( line[i+1] == ':' )
[b7d3cc34]447                        {
[de3e100]448                                cmd[j] ++;
[b7d3cc34]449                                break;
450                        }
451                }
452        }
453       
[de3e100]454        return cmd;
[b7d3cc34]455}
456
[e27661d]457/* Converts such an array back into a command string. Mainly used for the IPC code right now. */
[74c119d]458char *irc_build_line( char **cmd )
459{
460        int i, len;
461        char *s;
[b7d3cc34]462       
[74c119d]463        if( cmd[0] == NULL )
464                return NULL;
[b7d3cc34]465       
[74c119d]466        len = 1;
467        for( i = 0; cmd[i]; i ++ )
468                len += strlen( cmd[i] ) + 1;
469       
470        if( strchr( cmd[i-1], ' ' ) != NULL )
471                len ++;
472       
473        s = g_new0( char, len + 1 );
474        for( i = 0; cmd[i]; i ++ )
[b7d3cc34]475        {
[74c119d]476                if( cmd[i+1] == NULL && strchr( cmd[i], ' ' ) != NULL )
477                        strcat( s, ":" );
[b7d3cc34]478               
[74c119d]479                strcat( s, cmd[i] );
[b7d3cc34]480               
[74c119d]481                if( cmd[i+1] )
482                        strcat( s, " " );
[b7d3cc34]483        }
[74c119d]484        strcat( s, "\r\n" );
[b7d3cc34]485       
[74c119d]486        return s;
[b7d3cc34]487}
488
[3ddb7477]489void irc_write( irc_t *irc, char *format, ... ) 
[b7d3cc34]490{
491        va_list params;
[3ddb7477]492
[b7d3cc34]493        va_start( params, format );
[3ddb7477]494        irc_vawrite( irc, format, params );     
[b7d3cc34]495        va_end( params );
[3ddb7477]496
[b7d3cc34]497        return;
498}
499
[3ddb7477]500void irc_write_all( int now, char *format, ... )
[b7d3cc34]501{
502        va_list params;
[3ddb7477]503        GSList *temp;   
[b7d3cc34]504       
505        va_start( params, format );
506       
[3ddb7477]507        temp = irc_connection_list;
508        while( temp != NULL )
509        {
510                irc_t *irc = temp->data;
511               
512                if( now )
513                {
514                        g_free( irc->sendbuffer );
515                        irc->sendbuffer = g_strdup( "\r\n" );
516                }
517                irc_vawrite( temp->data, format, params );
518                if( now )
519                {
520                        bitlbee_io_current_client_write( irc, irc->fd, GAIM_INPUT_WRITE );
521                }
522                temp = temp->next;
523        }
524       
[b7d3cc34]525        va_end( params );
526        return;
[3ddb7477]527} 
[b7d3cc34]528
529void irc_vawrite( irc_t *irc, char *format, va_list params )
530{
531        int size;
[f9756bd]532        char line[IRC_MAX_LINE+1];
[d783e48]533               
[0356ae3]534        /* Don't try to write anything new anymore when shutting down. */
[5898ef8]535        if( irc->status & USTATUS_SHUTDOWN )
[b7d3cc34]536                return;
[d783e48]537       
[f9756bd]538        memset( line, 0, sizeof( line ) );
[d783e48]539        g_vsnprintf( line, IRC_MAX_LINE - 2, format, params );
[b7d3cc34]540        strip_newlines( line );
[f9756bd]541       
542        if( irc->oconv != (GIConv) -1 )
[d783e48]543        {
[f9756bd]544                gsize bytes_read, bytes_written;
545                char *conv;
546               
547                conv = g_convert_with_iconv( line, -1, irc->oconv,
548                                             &bytes_read, &bytes_written, NULL );
549
550                if( bytes_read == strlen( line ) )
551                        strncpy( line, conv, IRC_MAX_LINE - 2 );
[d783e48]552               
[f9756bd]553                g_free( conv );
[d783e48]554        }
[f9756bd]555        g_strlcat( line, "\r\n", IRC_MAX_LINE + 1 );
[d783e48]556       
[a0d04d6]557        if( irc->sendbuffer != NULL )
558        {
[b7d3cc34]559                size = strlen( irc->sendbuffer ) + strlen( line );
560                irc->sendbuffer = g_renew ( char, irc->sendbuffer, size + 1 );
561                strcpy( ( irc->sendbuffer + strlen( irc->sendbuffer ) ), line );
562        }
[a0d04d6]563        else
[b7d3cc34]564        {
[a0d04d6]565                irc->sendbuffer = g_strdup(line);
[b7d3cc34]566        }
567       
[a0d04d6]568        if( irc->w_watch_source_id == 0 )
[0356ae3]569        {
570                /* If the buffer is empty we can probably write, so call the write event handler
571                   immediately. If it returns TRUE, it should be called again, so add the event to
572                   the queue. If it's FALSE, we emptied the buffer and saved ourselves some work
573                   in the event queue. */
[bbb6ffb]574                /* Really can't be done as long as the code doesn't do error checking very well:
575                if( bitlbee_io_current_client_write( irc, irc->fd, GAIM_INPUT_WRITE ) ) */
576               
577                /* So just always do it via the event handler. */
578                irc->w_watch_source_id = b_input_add( irc->fd, GAIM_INPUT_WRITE, bitlbee_io_current_client_write, irc );
[0356ae3]579        }
[a0d04d6]580       
[b7d3cc34]581        return;
582}
583
[edf9657]584int irc_check_login( irc_t *irc )
[b7d3cc34]585{
[3ddb7477]586        if( irc->user->user && irc->user->nick )
[edf9657]587        {
[3af70b0]588                if( global.conf->authmode == AUTHMODE_CLOSED && !( irc->status & USTATUS_AUTHORIZED ) )
[b7d3cc34]589                {
[3ddb7477]590                        irc_send_num( irc, 464, ":This server is password-protected." );
[edf9657]591                        return 0;
[b7d3cc34]592                }
[edf9657]593                else
[b7d3cc34]594                {
[4be8239]595                        irc_channel_t *ic;
596                        irc_user_t *iu = irc->user;
597                       
598                        irc->user = irc_user_new( irc, iu->nick );
599                        irc->user->user = iu->user;
[b95932e]600                        irc->user->host = iu->host;
[4be8239]601                        irc->user->fullname = iu->fullname;
[280c56a]602                        irc->user->f = &irc_user_self_funcs;
[4be8239]603                        g_free( iu->nick );
604                        g_free( iu );
605                       
606                        if( global.conf->runmode == RUNMODE_FORKDAEMON || global.conf->runmode == RUNMODE_DAEMON )
607                                ipc_to_master_str( "CLIENT %s %s :%s\r\n", irc->user->host, irc->user->nick, irc->user->fullname );
608                       
609                        irc->status |= USTATUS_LOGGED_IN;
610                       
611                        /* This is for bug #209 (use PASS to identify to NickServ). */
612                        if( irc->password != NULL )
613                        {
614                                char *send_cmd[] = { "identify", g_strdup( irc->password ), NULL };
615                               
616                                /*irc_setpass( irc, NULL );*/
617                                /*root_command( irc, send_cmd );*/
618                                g_free( send_cmd[1] );
619                        }
620                       
[3ddb7477]621                        irc_send_login( irc );
[4be8239]622                       
[b919363]623                        irc->umode[0] = '\0';
624                        irc_umode_set( irc, "+" UMODE, TRUE );
625                       
[4be8239]626                        ic = irc_channel_new( irc, ROOT_CHAN );
[83e92bf]627                        irc_channel_set_topic( ic, CONTROL_TOPIC, irc->root );
[4be8239]628                        irc_channel_add_user( ic, irc->user );
629                       
[74f1cde]630                        irc->last_root_cmd = g_strdup( ROOT_CHAN );
631                       
[edf9657]632                        return 1;
[b7d3cc34]633                }
[edf9657]634        }
635        else
636        {
637                /* More information needed. */
638                return 0;
639        }
[b7d3cc34]640}
641
[b919363]642void irc_umode_set( irc_t *irc, const char *s, gboolean allow_priv )
643{
644        /* allow_priv: Set to 0 if s contains user input, 1 if you want
645           to set a "privileged" mode (+o, +R, etc). */
646        char m[128], st = 1;
647        const char *t;
648        int i;
649        char changes[512], *p, st2 = 2;
650        char badflag = 0;
651       
652        memset( m, 0, sizeof( m ) );
653       
654        for( t = irc->umode; *t; t ++ )
655                if( *t < sizeof( m ) )
656                        m[(int)*t] = 1;
657       
658        p = changes;
659        for( t = s; *t; t ++ )
660        {
661                if( *t == '+' || *t == '-' )
662                        st = *t == '+';
663                else if( ( st == 0 && ( !strchr( UMODES_KEEP, *t ) || allow_priv ) ) ||
664                         ( st == 1 && strchr( UMODES, *t ) ) ||
665                         ( st == 1 && allow_priv && strchr( UMODES_PRIV, *t ) ) )
666                {
667                        if( m[(int)*t] != st)
668                        {
669                                if( st != st2 )
670                                        st2 = st, *p++ = st ? '+' : '-';
671                                *p++ = *t;
672                        }
673                        m[(int)*t] = st;
674                }
675                else
676                        badflag = 1;
677        }
678        *p = '\0';
679       
680        memset( irc->umode, 0, sizeof( irc->umode ) );
681       
682        for( i = 'A'; i <= 'z' && strlen( irc->umode ) < ( sizeof( irc->umode ) - 1 ); i ++ )
683                if( m[i] )
684                        irc->umode[strlen(irc->umode)] = i;
685       
686        if( badflag )
687                irc_send_num( irc, 501, ":Unknown MODE flag" );
688        if( *changes )
689                irc_write( irc, ":%s!%s@%s MODE %s :%s", irc->user->nick,
690                           irc->user->user, irc->user->host, irc->user->nick,
691                           changes );
692}
693
[b7d3cc34]694
[3923003]695/* Returns 0 if everything seems to be okay, a number >0 when there was a
696   timeout. The number returned is the number of seconds we received no
697   pongs from the user. When not connected yet, we don't ping but drop the
698   connection when the user fails to connect in IRC_LOGIN_TIMEOUT secs. */
699static gboolean irc_userping( gpointer _irc, gint fd, b_input_condition cond )
700{
701        irc_t *irc = _irc;
702        int rv = 0;
703       
704        if( !( irc->status & USTATUS_LOGGED_IN ) )
705        {
706                if( gettime() > ( irc->last_pong + IRC_LOGIN_TIMEOUT ) )
707                        rv = gettime() - irc->last_pong;
708        }
709        else
710        {
711                if( ( gettime() > ( irc->last_pong + global.conf->ping_interval ) ) && !irc->pinging )
712                {
713                        irc_write( irc, "PING :%s", IRC_PING_STRING );
714                        irc->pinging = 1;
715                }
716                else if( gettime() > ( irc->last_pong + global.conf->ping_timeout ) )
717                {
718                        rv = gettime() - irc->last_pong;
719                }
720        }
721       
722        if( rv > 0 )
723        {
724                irc_abort( irc, 0, "Ping Timeout: %d seconds", rv );
725                return FALSE;
726        }
727       
728        return TRUE;
729}
730
[b7d3cc34]731
[3ddb7477]732static char *set_eval_charset( set_t *set, char *value )
[b7d3cc34]733{
[3ddb7477]734        irc_t *irc = set->data;
735        GIConv ic, oc;
[b7d3cc34]736
[3ddb7477]737        if( g_strcasecmp( value, "none" ) == 0 )
738                value = g_strdup( "utf-8" );
[b7d3cc34]739
[3ddb7477]740        if( ( ic = g_iconv_open( "utf-8", value ) ) == (GIConv) -1 )
[b7d3cc34]741        {
[3ddb7477]742                return NULL;
[b7d3cc34]743        }
[3ddb7477]744        if( ( oc = g_iconv_open( value, "utf-8" ) ) == (GIConv) -1 )
[b7d3cc34]745        {
[3ddb7477]746                g_iconv_close( ic );
747                return NULL;
[b7d3cc34]748        }
749       
[3ddb7477]750        if( irc->iconv != (GIConv) -1 )
751                g_iconv_close( irc->iconv );
752        if( irc->oconv != (GIConv) -1 )
753                g_iconv_close( irc->oconv );
[b7d3cc34]754       
[3ddb7477]755        irc->iconv = ic;
756        irc->oconv = oc;
[0e7ab64]757
[3ddb7477]758        return value;
[0e7ab64]759}
Note: See TracBrowser for help on using the repository browser.