aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilmer van der Gaast <wilmer@gaast.net>2008-03-30 22:26:16 +0100
committerWilmer van der Gaast <wilmer@gaast.net>2008-03-30 22:26:16 +0100
commitf9756bd2e2711d58e06ad2a33ad3292ff10fc6da (patch)
tree213bb64648b12e823a0a427da26883e7b6a87436
parent5ecf96b935c6f6c0fba00d84cf7616ee04b06aed (diff)
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.
-rw-r--r--irc.c102
-rw-r--r--irc.h1
-rw-r--r--irc_commands.c3
-rw-r--r--set.c15
-rw-r--r--set.h1
5 files changed, 81 insertions, 41 deletions
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 )
{
diff --git a/irc.h b/irc.h
index eaf531b7..b8c52925 100644
--- a/irc.h
+++ b/irc.h
@@ -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] );
}
}
diff --git a/set.c b/set.c
index 90b29f91..112e6937 100644
--- a/set.c
+++ b/set.c
@@ -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;
-}
diff --git a/set.h b/set.h
index 7dcbb869..8c722877 100644
--- a/set.h
+++ b/set.h
@@ -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__ */