source: irc.c @ e63507a

Last change on this file since e63507a was d860a8d, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-04-01T03:38:50Z

Restored "account" root command and restored enough stuff to be able to
send messages. Also started moving stuff out from nogaim.* into bee_* files.

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