source: irc.c @ b919363

Last change on this file since b919363 was b919363, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-03-27T14:31:03Z

Mode stuff. Also disallow unsetting +R umode which was possible so far
(and shouldn't be).

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