source: irc.c @ 1f92a58

Last change on this file since 1f92a58 was 1f92a58, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-04-10T02:27:50Z

Restore the storage module.

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