source: irc.c @ 38ee021

Last change on this file since 38ee021 was 3923003, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-03-28T02:49:19Z

Restored server-initiated PINGs.

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