diff options
-rw-r--r-- | irc.c | 102 | ||||
-rw-r--r-- | irc.h | 1 | ||||
-rw-r--r-- | irc_commands.c | 3 | ||||
-rw-r--r-- | set.c | 15 | ||||
-rw-r--r-- | set.h | 1 |
5 files changed, 81 insertions, 41 deletions
@@ -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 ) { @@ -60,6 +60,7 @@ typedef struct irc int pinging; char *sendbuffer; char *readbuffer; + GIConv iconv, oconv; int sentbytes; time_t oldtime; diff --git a/irc_commands.c b/irc_commands.c index 61517614..6a47007a 100644 --- a/irc_commands.c +++ b/irc_commands.c @@ -277,8 +277,7 @@ static void irc_cmd_privmsg( irc_t *irc, char **cmd ) if( cmd[1] != irc->last_target ) { - if( irc->last_target ) - g_free( irc->last_target ); + g_free( irc->last_target ); irc->last_target = g_strdup( cmd[1] ); } } @@ -229,18 +229,3 @@ char *set_eval_ops( set_t *set, char *value ) return value; } - -char *set_eval_charset( set_t *set, char *value ) -{ - GIConv cd; - - if( g_strcasecmp( value, "none" ) == 0 ) - return value; - - cd = g_iconv_open( "UTF-8", value ); - if( cd == (GIConv) -1 ) - return NULL; - - g_iconv_close( cd ); - return value; -} @@ -96,6 +96,5 @@ char *set_eval_bool( set_t *set, char *value ); /* Some not very generic evaluators that really shouldn't be here... */ char *set_eval_to_char( set_t *set, char *value ); char *set_eval_ops( set_t *set, char *value ); -char *set_eval_charset( set_t *set, char *value ); #endif /* __SET_H__ */ |