From a83442a7c4dbf99937e9e5397e5665c671694161 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Fri, 21 Mar 2008 00:39:16 +0000 Subject: Fixed handling of "set charset none". Fixes bug #373. --- irc.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'irc.c') diff --git a/irc.c b/irc.c index 3a09f684..3589256e 100644 --- a/irc.c +++ b/irc.c @@ -308,7 +308,7 @@ void irc_process( irc_t *irc ) break; } - if( ( cs = set_getstr( &irc->set, "charset" ) ) ) + if( ( cs = set_getstr( &irc->set, "charset" ) ) && g_strcasecmp( cs, "none" ) != 0 ) { conv[IRC_MAX_LINE] = 0; if( do_iconv( cs, "UTF-8", lines[i], conv, 0, IRC_MAX_LINE - 2 ) == -1 ) @@ -329,7 +329,7 @@ void irc_process( irc_t *irc ) else { irc_write( irc, ":%s NOTICE AUTH :%s", irc->myhost, - "Warning: invalid (non-UTF8) characters received at login time." ); + "Warning: invalid characters received at login time." ); strncpy( conv, lines[i], IRC_MAX_LINE ); for( temp = conv; *temp; temp ++ ) @@ -553,7 +553,8 @@ void irc_vawrite( irc_t *irc, char *format, va_list params ) g_vsnprintf( line, IRC_MAX_LINE - 2, format, params ); strip_newlines( line ); - if( ( cs = set_getstr( &irc->set, "charset" ) ) && ( g_strcasecmp( cs, "utf-8" ) != 0 ) ) + if( ( cs = set_getstr( &irc->set, "charset" ) ) && + g_strcasecmp( cs, "none" ) != 0 && g_strcasecmp( cs, "utf-8" ) != 0 ) { char conv[IRC_MAX_LINE+1]; -- cgit v1.2.3 From a199d33ed818820ffba328f718799bbd77392f6a Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 29 Mar 2008 22:19:17 +0000 Subject: Closing bug #209: The PASS command can now be used to identify yourself to BitlBee. The advantage: No more messing with NickServ hooks. Just set a server password. --- irc.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'irc.c') diff --git a/irc.c b/irc.c index 3589256e..fa0c03fe 100644 --- a/irc.c +++ b/irc.c @@ -735,12 +735,27 @@ void irc_login( irc_t *irc ) u->online = 1; irc_spawn( irc, u ); - irc_usermsg( irc, "Welcome to the BitlBee gateway!\n\nIf you've never used BitlBee before, please do read the help information using the \x02help\x02 command. Lots of FAQs are answered there." ); + irc_usermsg( irc, "Welcome to the BitlBee gateway!\n\n" + "If you've never used BitlBee before, please do read the help " + "information using the \x02help\x02 command. Lots of FAQs are " + "answered there.\n" + "If you already have an account on this server, just use the " + "\x02identify\x02 command to identify yourself." ); if( global.conf->runmode == RUNMODE_FORKDAEMON || global.conf->runmode == RUNMODE_DAEMON ) ipc_to_master_str( "CLIENT %s %s :%s\r\n", irc->host, irc->nick, irc->realname ); irc->status |= USTATUS_LOGGED_IN; + + /* This is for bug #209 (use PASS to identify to NickServ). */ + if( irc->password != NULL ) + { + char *send_cmd[] = { "identify", g_strdup( irc->password ), NULL }; + + irc_setpass( irc, NULL ); + root_command( irc, send_cmd ); + g_free( send_cmd[1] ); + } } void irc_motd( irc_t *irc ) -- cgit v1.2.3 From 18ff38fad0d6d47853fb43ec5a99b29ba031a8ca Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 29 Mar 2008 23:15:04 +0000 Subject: Be more liberal with accepted line endings. ERC on Windows likes to use "\r\r\n", for example, and until now BitlBee only chopped off the \r\n, leaving the first \r as part of the command, which means it couldn't log in to BitlBee at all. (Bad character in nickname.) --- irc.c | 54 ++++++++++++++++++++++++++---------------------------- 1 file changed, 26 insertions(+), 28 deletions(-) (limited to 'irc.c') diff --git a/irc.c b/irc.c index fa0c03fe..99f0de9a 100644 --- a/irc.c +++ b/irc.c @@ -296,9 +296,8 @@ void irc_process( irc_t *irc ) { char conv[IRC_MAX_LINE+1]; - /* [WvG] Because irc_tokenize splits at every newline, the lines[] list - should end with an empty string. This is why this actually works. - Took me a while to figure out, Maurits. :-P */ + /* [WvG] If the last line isn't empty, it's an incomplete line and we + should wait for the rest to come in before processing it. */ if( lines[i+1] == NULL ) { temp = g_strdup( lines[i] ); @@ -368,42 +367,41 @@ void irc_process( irc_t *irc ) contains an incomplete line at the end, ends with an empty string. */ char **irc_tokenize( char *buffer ) { - int i, j; + int i, j, n = 3; char **lines; - /* Count the number of elements we're gonna need. */ - for( i = 0, j = 1; buffer[i] != '\0'; i ++ ) - { - if( buffer[i] == '\n' ) - if( buffer[i+1] != '\r' && buffer[i+1] != '\n' ) - j ++; - } - - /* Allocate j+1 elements. */ - lines = g_new( char *, j + 1 ); - - /* NULL terminate our list. */ - lines[j] = NULL; + /* Allocate n+1 elements. */ + lines = g_new( char *, n + 1 ); lines[0] = buffer; - /* Split the buffer in several strings, using \r\n as our seperator, where \r is optional. - * Although this is not in the RFC, some braindead ircds (newnet's) use this, so some clients might too. - */ - for( i = 0, j = 0; buffer[i] != '\0'; i ++) + /* Split the buffer in several strings, and accept any kind of line endings, + * knowing that ERC on Windows may send something interesting like \r\r\n, + * and surely there must be clients that think just \n is enough... */ + for( i = 0, j = 0; buffer[i] != '\0'; i ++ ) { - if( buffer[i] == '\n' ) + if( buffer[i] == '\r' || buffer[i] == '\n' ) { - buffer[i] = '\0'; + while( buffer[i] == '\r' || buffer[i] == '\n' ) + buffer[i++] = '\0'; - if( i > 0 && buffer[i-1] == '\r' ) - buffer[i-1] = '\0'; - if( buffer[i+1] != '\r' && buffer[i+1] != '\n' ) - lines[++j] = buffer + i + 1; + lines[++j] = buffer + i; + + if( j >= n ) + { + n *= 2; + lines = g_renew( char *, lines, n + 1 ); + } + + if( buffer[i] == '\0' ) + break; } } - return( lines ); + /* NULL terminate our list. */ + lines[++j] = NULL; + + return lines; } /* Split an IRC-style line into little parts/arguments. */ -- cgit v1.2.3 From f9756bd2e2711d58e06ad2a33ad3292ff10fc6da Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 30 Mar 2008 22:26:16 +0100 Subject: Changed charset handling: irc_t keeps two iconv structures, which are just used for every line sent and received, so now there's no need to use g_iconv_open() every time a message comes in/out. Also, fixed a small memory leak that was there for a long time but somehow never caught my attention. --- irc.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 79 insertions(+), 23 deletions(-) (limited to 'irc.c') diff --git a/irc.c b/irc.c index 99f0de9a..2faa2bc1 100644 --- a/irc.c +++ b/irc.c @@ -41,6 +41,35 @@ static char *passchange( set_t *set, char *value ) return NULL; } +static char *set_eval_charset( set_t *set, char *value ) +{ + irc_t *irc = set->data; + GIConv ic, oc; + + if( g_strcasecmp( value, "none" ) == 0 ) + value = g_strdup( "utf-8" ); + + if( ( ic = g_iconv_open( "utf-8", value ) ) == (GIConv) -1 ) + { + return NULL; + } + if( ( oc = g_iconv_open( value, "utf-8" ) ) == (GIConv) -1 ) + { + g_iconv_close( ic ); + return NULL; + } + + if( irc->iconv != (GIConv) -1 ) + g_iconv_close( irc->iconv ); + if( irc->oconv != (GIConv) -1 ) + g_iconv_close( irc->oconv ); + + irc->iconv = ic; + irc->oconv = oc; + + return value; +} + irc_t *irc_new( int fd ) { irc_t *irc; @@ -64,6 +93,9 @@ irc_t *irc_new( int fd ) irc->mynick = g_strdup( ROOT_NICK ); irc->channel = g_strdup( ROOT_CHAN ); + irc->iconv = (GIConv) -1; + irc->oconv = (GIConv) -1; + if( global.conf->hostname ) { irc->myhost = g_strdup( global.conf->hostname ); @@ -126,6 +158,9 @@ irc_t *irc_new( int fd ) conf_loaddefaults( irc ); + /* Evaluator sets the iconv/oconv structures. */ + set_eval_charset( set_find( &irc->set, "charset" ), set_getstr( &irc->set, "charset" ) ); + return( irc ); } @@ -264,6 +299,13 @@ void irc_free(irc_t * irc) g_hash_table_foreach_remove(irc->watches, irc_free_hashkey, NULL); g_hash_table_destroy(irc->watches); + if( irc->iconv != (GIConv) -1 ) + g_iconv_close( irc->iconv ); + if( irc->oconv != (GIConv) -1 ) + g_iconv_close( irc->oconv ); + + g_free( irc->last_target ); + g_free(irc); if( global.conf->runmode == RUNMODE_INETD || global.conf->runmode == RUNMODE_FORKDAEMON ) @@ -285,7 +327,7 @@ void irc_setpass (irc_t *irc, const char *pass) void irc_process( irc_t *irc ) { - char **lines, *temp, **cmd, *cs; + char **lines, *temp, **cmd; int i; if( irc->readbuffer != NULL ) @@ -294,7 +336,7 @@ void irc_process( irc_t *irc ) for( i = 0; *lines[i] != '\0'; i ++ ) { - char conv[IRC_MAX_LINE+1]; + char *conv = NULL; /* [WvG] If the last line isn't empty, it's an incomplete line and we should wait for the rest to come in before processing it. */ @@ -307,10 +349,14 @@ void irc_process( irc_t *irc ) break; } - if( ( cs = set_getstr( &irc->set, "charset" ) ) && g_strcasecmp( cs, "none" ) != 0 ) + if( irc->iconv != (GIConv) -1 ) { - conv[IRC_MAX_LINE] = 0; - if( do_iconv( cs, "UTF-8", lines[i], conv, 0, IRC_MAX_LINE - 2 ) == -1 ) + gsize bytes_read, bytes_written; + + conv = g_convert_with_iconv( lines[i], -1, irc->iconv, + &bytes_read, &bytes_written, NULL ); + + if( conv == NULL || bytes_read != strlen( lines[i] ) ) { /* GLib can do strange things if things are not in the expected charset, so let's be a little bit paranoid here: */ @@ -322,15 +368,18 @@ void irc_process( irc_t *irc ) "that charset, or tell BitlBee which charset to " "expect by changing the charset setting. See " "`help set charset' for more information. Your " - "message was ignored.", cs ); - *conv = 0; + "message was ignored.", + set_getstr( &irc->set, "charset" ) ); + + g_free( conv ); + conv = NULL; } else { irc_write( irc, ":%s NOTICE AUTH :%s", irc->myhost, "Warning: invalid characters received at login time." ); - strncpy( conv, lines[i], IRC_MAX_LINE ); + conv = g_strdup( lines[i] ); for( temp = conv; *temp; temp ++ ) if( *temp & 0x80 ) *temp = '?'; @@ -339,11 +388,15 @@ void irc_process( irc_t *irc ) lines[i] = conv; } - if( ( cmd = irc_parse_line( lines[i] ) ) == NULL ) - continue; - irc_exec( irc, cmd ); + if( lines[i] ) + { + if( ( cmd = irc_parse_line( lines[i] ) ) == NULL ) + continue; + irc_exec( irc, cmd ); + g_free( cmd ); + } - g_free( cmd ); + g_free( conv ); /* Shouldn't really happen, but just in case... */ if( !g_slist_find( irc_connection_list, irc ) ) @@ -535,32 +588,35 @@ void irc_write( irc_t *irc, char *format, ... ) va_end( params ); return; - } void irc_vawrite( irc_t *irc, char *format, va_list params ) { int size; - char line[IRC_MAX_LINE+1], *cs; + char line[IRC_MAX_LINE+1]; /* Don't try to write anything new anymore when shutting down. */ if( irc->status & USTATUS_SHUTDOWN ) return; - line[IRC_MAX_LINE] = 0; + memset( line, 0, sizeof( line ) ); g_vsnprintf( line, IRC_MAX_LINE - 2, format, params ); - strip_newlines( line ); - if( ( cs = set_getstr( &irc->set, "charset" ) ) && - g_strcasecmp( cs, "none" ) != 0 && g_strcasecmp( cs, "utf-8" ) != 0 ) + + if( irc->oconv != (GIConv) -1 ) { - char conv[IRC_MAX_LINE+1]; + gsize bytes_read, bytes_written; + char *conv; + + conv = g_convert_with_iconv( line, -1, irc->oconv, + &bytes_read, &bytes_written, NULL ); + + if( bytes_read == strlen( line ) ) + strncpy( line, conv, IRC_MAX_LINE - 2 ); - conv[IRC_MAX_LINE] = 0; - if( do_iconv( "UTF-8", cs, line, conv, 0, IRC_MAX_LINE - 2 ) != -1 ) - strcpy( line, conv ); + g_free( conv ); } - strcat( line, "\r\n" ); + g_strlcat( line, "\r\n", IRC_MAX_LINE + 1 ); if( irc->sendbuffer != NULL ) { -- cgit v1.2.3 From fa75134008bd9206ca02380927c27581feb65c3e Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 2 Apr 2008 00:07:21 +0100 Subject: Reordered irc_free() a little bit, hoping that this will fix a crash-on-quit bug I can't figure out. The previous order wasn't optimal. --- irc.c | 111 +++++++++++++++++++++++++++++++++--------------------------------- 1 file changed, 56 insertions(+), 55 deletions(-) (limited to 'irc.c') diff --git a/irc.c b/irc.c index 2faa2bc1..585cf232 100644 --- a/irc.c +++ b/irc.c @@ -219,9 +219,8 @@ static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data ) } /* Because we have no garbage collection, this is quite annoying */ -void irc_free(irc_t * irc) +void irc_free( irc_t * irc ) { - account_t *account; user_t *user, *usertmp; log_message( LOGLVL_INFO, "Destroying connection with fd %d", irc->fd ); @@ -230,83 +229,85 @@ void irc_free(irc_t * irc) if( storage_save( irc, TRUE ) != STORAGE_OK ) irc_usermsg( irc, "Error while saving settings!" ); - closesocket( irc->fd ); - - if( irc->ping_source_id > 0 ) - b_event_remove( irc->ping_source_id ); - b_event_remove( irc->r_watch_source_id ); - if( irc->w_watch_source_id > 0 ) - b_event_remove( irc->w_watch_source_id ); - irc_connection_list = g_slist_remove( irc_connection_list, irc ); - for (account = irc->accounts; account; account = account->next) { - if (account->ic) { - imc_logout(account->ic, TRUE); - } else if (account->reconnect) { - cancel_auto_reconnect(account); - } - } - - g_free(irc->sendbuffer); - g_free(irc->readbuffer); - - g_free(irc->nick); - g_free(irc->user); - g_free(irc->host); - g_free(irc->realname); - g_free(irc->password); - - g_free(irc->myhost); - g_free(irc->mynick); - - g_free(irc->channel); - - while (irc->queries != NULL) - query_del(irc, irc->queries); - - while (irc->accounts) - if (irc->accounts->ic == NULL) - account_del(irc, irc->accounts); + while( irc->accounts ) + { + if( irc->accounts->ic ) + imc_logout( irc->accounts->ic, FALSE ); + else if( irc->accounts->reconnect ) + cancel_auto_reconnect( irc->accounts ); + + if( irc->accounts->ic == NULL ) + account_del( irc, irc->accounts ); else /* Nasty hack, but account_del() doesn't work in this case and we don't want infinite loops, do we? ;-) */ irc->accounts = irc->accounts->next; + } + + while( irc->queries != NULL ) + query_del( irc, irc->queries ); - while (irc->set) - set_del(&irc->set, irc->set->key); + while( irc->set ) + set_del( &irc->set, irc->set->key ); - if (irc->users != NULL) { + if (irc->users != NULL) + { user = irc->users; - while (user != NULL) { - g_free(user->nick); - g_free(user->away); - g_free(user->handle); - if(user->user!=user->nick) g_free(user->user); - if(user->host!=user->nick) g_free(user->host); - if(user->realname!=user->nick) g_free(user->realname); - b_event_remove(user->sendbuf_timer); + while( user != NULL ) + { + g_free( user->nick ); + g_free( user->away ); + g_free( user->handle ); + if( user->user != user->nick ) g_free( user->user ); + if( user->host != user->nick ) g_free( user->host ); + if( user->realname != user->nick ) g_free( user->realname ); + b_event_remove( user->sendbuf_timer ); usertmp = user; user = user->next; - g_free(usertmp); + g_free( usertmp ); } } - g_hash_table_foreach_remove(irc->userhash, irc_free_hashkey, NULL); - g_hash_table_destroy(irc->userhash); + if( irc->ping_source_id > 0 ) + b_event_remove( irc->ping_source_id ); + b_event_remove( irc->r_watch_source_id ); + if( irc->w_watch_source_id > 0 ) + b_event_remove( irc->w_watch_source_id ); + + closesocket( irc->fd ); + irc->fd = -1; + + g_hash_table_foreach_remove( irc->userhash, irc_free_hashkey, NULL ); + g_hash_table_destroy( irc->userhash ); - g_hash_table_foreach_remove(irc->watches, irc_free_hashkey, NULL); - g_hash_table_destroy(irc->watches); + g_hash_table_foreach_remove( irc->watches, irc_free_hashkey, NULL ); + g_hash_table_destroy( irc->watches ); if( irc->iconv != (GIConv) -1 ) g_iconv_close( irc->iconv ); if( irc->oconv != (GIConv) -1 ) g_iconv_close( irc->oconv ); + g_free( irc->sendbuffer ); + g_free( irc->readbuffer ); + + g_free( irc->nick ); + g_free( irc->user ); + g_free( irc->host ); + g_free( irc->realname ); + g_free( irc->password ); + + g_free( irc->myhost ); + g_free( irc->mynick ); + + g_free( irc->channel ); + g_free( irc->last_target ); - g_free(irc); + g_free( irc ); if( global.conf->runmode == RUNMODE_INETD || global.conf->runmode == RUNMODE_FORKDAEMON ) b_main_quit(); -- cgit v1.2.3