aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilmer van der Gaast <wilmer@gaast.net>2007-10-12 01:08:58 +0100
committerWilmer van der Gaast <wilmer@gaast.net>2007-10-12 01:08:58 +0100
commiteda54e40d04c83028d84e91c895a550c1929b436 (patch)
tree878f985af2ab5d2b9c59e8c955448bc4e9ddec17
parent82135c7178b6379f35741991f6c06bb308143194 (diff)
parentd444c09e6c7ac6fc3c1686af0e63c09805d8cd00 (diff)
Merge from devel.
-rw-r--r--Makefile2
-rwxr-xr-xconfigure15
-rw-r--r--doc/CHANGES17
-rw-r--r--doc/user-guide/commands.xml10
-rw-r--r--irc.c5
-rw-r--r--lib/Makefile2
-rw-r--r--lib/arc.c (renamed from lib/rc4.c)107
-rw-r--r--lib/arc.h (renamed from lib/rc4.h)16
-rw-r--r--lib/base64.c4
-rw-r--r--lib/base64.h2
-rw-r--r--lib/misc.c48
-rw-r--r--lib/misc.h2
-rw-r--r--lib/ssl_bogus.c5
-rw-r--r--protocols/jabber/sasl.c7
-rw-r--r--protocols/nogaim.c64
-rw-r--r--protocols/nogaim.h96
-rw-r--r--root_commands.c2
-rw-r--r--storage_xml.c23
-rw-r--r--tests/Makefile2
-rw-r--r--tests/check.c4
-rw-r--r--tests/check_arc.c95
-rw-r--r--tests/check_util.c58
-rw-r--r--unix.c13
23 files changed, 466 insertions, 133 deletions
diff --git a/Makefile b/Makefile
index f32dae84..039c202a 100644
--- a/Makefile
+++ b/Makefile
@@ -10,7 +10,7 @@
# Program variables
objects = account.o bitlbee.o conf.o crypting.o help.o ipc.o irc.o irc_commands.o log.o nick.o query.o root_commands.o set.o storage.o $(STORAGE_OBJS) unix.o user.o
-headers = account.h bitlbee.h commands.h conf.h config.h crypting.h help.h ini.h ipc.h irc.h log.h nick.h query.h set.h sock.h storage.h url.h user.h protocols/http_client.h protocols/md5.h protocols/nogaim.h protocols/proxy.h protocols/sha.h protocols/ssl_client.h
+headers = account.h bitlbee.h commands.h conf.h config.h crypting.h help.h ipc.h irc.h log.h nick.h query.h set.h sock.h storage.h user.h lib/events.h lib/http_client.h lib/ini.h lib/md5.h lib/misc.h lib/proxy.h lib/sha.h lib/ssl_client.h lib/url.h protocols/nogaim.h
subdirs = lib protocols
# Expansion of variables
diff --git a/configure b/configure
index bb7ddd7d..ffa0e2f2 100755
--- a/configure
+++ b/configure
@@ -28,6 +28,7 @@ yahoo=1
debug=0
strip=1
gcov=0
+plugins=1
ipv6=1
events=glib
@@ -68,11 +69,10 @@ Option Description Default
--debug=0/1 Disable/enable debugging $debug
--strip=0/1 Disable/enable binary stripping $strip
--gcov=0/1 Disable/enable test coverage reporting $gcov
+--plugins=0/1 Disable/enable plugins support $plugins
--ipv6=0/1 IPv6 socket support $ipv6
---ldap=0/1/auto LDAP support $ldap
-
--events=... Event handler (glib, libevent) $events
--ssl=... SSL library to use (gnutls, nss, openssl, bogus, auto)
$ssl
@@ -139,13 +139,14 @@ if [ "$ipv6" = "1" ]; then
fi
if [ "$debug" = "1" ]; then
- echo 'CFLAGS=-g' >> Makefile.settings
+ [ -z "$CFLAGS" ] && CFLAGS=-g
echo 'DEBUG=1' >> Makefile.settings
echo '#define DEBUG' >> config.h
else
- echo 'CFLAGS=-O3' >> Makefile.settings
+ [ -z "$CFLAGS" ] && CFLAGS=-O3
fi
+echo CFLAGS=$CFLAGS >> Makefile.settings
echo CFLAGS+=-I`pwd` -I`pwd`/lib -I`pwd`/protocols -I. >> Makefile.settings
echo CFLAGS+=-DHAVE_CONFIG_H >> Makefile.settings
@@ -384,6 +385,12 @@ if [ "$gcov" = "1" ]; then
echo "EFLAGS+=-lgcov" >> Makefile.settings
fi
+if [ "$plugins" = 0 ]; then
+ echo '#undef WITH_PLUGINS' >> config.h
+else
+ echo '#define WITH_PLUGINS' >> config.h
+fi
+
echo
if [ -z "$BITLBEE_VERSION" -a -d .bzr ] && type bzr > /dev/null 2> /dev/null; then
nick=`bzr nick`
diff --git a/doc/CHANGES b/doc/CHANGES
index 3f509c46..6c109f25 100644
--- a/doc/CHANGES
+++ b/doc/CHANGES
@@ -1,4 +1,4 @@
-Version 1.1dev:
+Version 1.2:
- First BitlBee development/testing RELEASE. This should be quite stable
though (and for most people more stable than 1.0.x). It just has a couple
of rough edges and needs a bit more testing.
@@ -65,6 +65,21 @@ Version 1.1dev:
resources available for that buddy. (Of course this only works if the
buddy is in your contact list.)
+Finished ???
+
+Version 1.0.4:
+- Removed sethostent(), which causes problems for many people, especially on
+ *BSD. This is basically the reason for this release.
+- "allow" command actually displays the allow list, not the block list.
+- Yahoo away state/msg fix.
+- Don't display "Gender: Male" by default if nothing's filled in (OSCAR
+ "info" command)
+- Fixed account cleanup (possible infinite loop) in irc_free().
+- Fixed configdir error message to not always display the compile-time
+ setting.
+
+Finished 20 Aug 2007
+
Version 1.0.3:
- Fixed ugliness in block/allow list commands (still not perfect though, the
list is empty or not up-to-date for most protocols).
diff --git a/doc/user-guide/commands.xml b/doc/user-guide/commands.xml
index 6646d0db..cf40782f 100644
--- a/doc/user-guide/commands.xml
+++ b/doc/user-guide/commands.xml
@@ -595,6 +595,16 @@
</description>
</bitlbee-setting>
+ <bitlbee-setting name="simulate_netsplit" type="boolean" scope="global">
+ <default>true</default>
+
+ <description>
+ <para>
+ Some IRC clients parse quit messages sent by the IRC server to see if someone really left or just disappeared because of a netsplit. By default, BitlBee tries to simulate netsplit-like quit messages to keep the control channel window clean. If you don't like this (or if your IRC client doesn't support this) you can disable this setting.
+ </para>
+ </description>
+ </bitlbee-setting>
+
<bitlbee-setting name="ssl" type="boolean" scope="account">
<default>false</default>
diff --git a/irc.c b/irc.c
index ee7288bf..72253595 100644
--- a/irc.c
+++ b/irc.c
@@ -131,7 +131,7 @@ irc_t *irc_new( int fd )
set_add( &irc->set, "auto_reconnect_delay", "300", set_eval_int, irc );
set_add( &irc->set, "buddy_sendbuffer", "false", set_eval_bool, irc );
set_add( &irc->set, "buddy_sendbuffer_delay", "200", set_eval_int, irc );
- set_add( &irc->set, "charset", "iso8859-1", set_eval_charset, irc );
+ set_add( &irc->set, "charset", "utf-8", set_eval_charset, irc );
set_add( &irc->set, "debug", "false", set_eval_bool, irc );
set_add( &irc->set, "default_target", "root", NULL, irc );
set_add( &irc->set, "display_namechanges", "false", set_eval_bool, irc );
@@ -142,6 +142,7 @@ irc_t *irc_new( int fd )
set_add( &irc->set, "private", "true", set_eval_bool, irc );
set_add( &irc->set, "query_order", "lifo", NULL, irc );
set_add( &irc->set, "save_on_quit", "true", set_eval_bool, irc );
+ set_add( &irc->set, "simulate_netsplit", "true", set_eval_bool, irc );
set_add( &irc->set, "strip_html", "true", NULL, irc );
set_add( &irc->set, "to_char", ": ", set_eval_to_char, irc );
set_add( &irc->set, "typing_notice", "false", set_eval_bool, irc );
@@ -909,7 +910,7 @@ void irc_kill( irc_t *irc, user_t *u )
char *nick, *s;
char reason[128];
- if( u->ic && u->ic->flags & OPT_LOGGING_OUT )
+ if( u->ic && u->ic->flags & OPT_LOGGING_OUT && set_getbool( &irc->set, "simulate_netsplit" ) )
{
if( u->ic->acc->server )
g_snprintf( reason, sizeof( reason ), "%s %s", irc->myhost,
diff --git a/lib/Makefile b/lib/Makefile
index a9038987..bc1966d9 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -9,7 +9,7 @@
-include ../Makefile.settings
# [SH] Program variables
-objects = base64.o $(EVENT_HANDLER) http_client.o ini.o md5.o misc.o proxy.o rc4.o sha.o $(SSL_CLIENT) url.o
+objects = arc.o base64.o $(EVENT_HANDLER) http_client.o ini.o md5.o misc.o proxy.o sha.o $(SSL_CLIENT) url.o
CFLAGS += -Wall
LFLAGS += -r
diff --git a/lib/rc4.c b/lib/arc.c
index f2c76f54..617f6b96 100644
--- a/lib/rc4.c
+++ b/lib/arc.c
@@ -1,7 +1,7 @@
/***************************************************************************\
* *
* BitlBee - An IRC to IM gateway *
-* Simple (but secure) RC4 implementation for safer password storage. *
+* Simple (but secure) ArcFour implementation for safer password storage. *
* *
* Copyright 2006 Wilmer van der Gaast <wilmer@gaast.net> *
* *
@@ -22,18 +22,21 @@
\***************************************************************************/
/*
- This file implements RC4-encryption, which will mainly be used to save IM
- passwords safely in the new XML-format. Possibly other uses will come up
- later. It's supposed to be quite reliable (thanks to the use of a 6-byte
- IV/seed), certainly compared to the old format. The only realistic way to
- crack BitlBee passwords now is to use a sniffer to get your hands on the
- user's password.
+ This file implements ArcFour-encryption, which will mainly be used to
+ save IM passwords safely in the new XML-format. Possibly other uses will
+ come up later. It's supposed to be quite reliable (thanks to the use of a
+ 6-byte IV/seed), certainly compared to the old format. The only realistic
+ way to crack BitlBee passwords now is to use a sniffer to get your hands
+ on the user's password.
If you see that something's wrong in this implementation (I asked a
couple of people to look at it already, but who knows), please tell me.
- The reason I chose for RC4 is because it's pretty simple but effective,
+ The reason I picked ArcFour is because it's pretty simple but effective,
so it will work without adding several KBs or an extra library dependency.
+
+ (ArcFour is an RC4-compatible cipher. See for details:
+ http://www.mozilla.org/projects/security/pki/nss/draft-kaukonen-cipher-arcfour-03.txt)
*/
@@ -42,55 +45,62 @@
#include <stdlib.h>
#include <string.h>
#include "misc.h"
-#include "rc4.h"
+#include "arc.h"
/* Add some seed to the password, to make sure we *never* use the same key.
This defines how many bytes we use as a seed. */
-#define RC4_IV_LEN 6
+#define ARC_IV_LEN 6
/* To defend against a "Fluhrer, Mantin and Shamir attack", it is recommended
to shuffle S[] just a bit more before you start to use it. This defines how
many bytes we'll request before we'll really use them for encryption. */
-#define RC4_CYCLES 1024
+#define ARC_CYCLES 1024
-struct rc4_state *rc4_keymaker( unsigned char *key, int kl, int cycles )
+struct arc_state *arc_keymaker( unsigned char *key, int kl, int cycles )
{
- struct rc4_state *st;
+ struct arc_state *st;
int i, j, tmp;
+ unsigned char S2[256];
- st = g_malloc( sizeof( struct rc4_state ) );
+ st = g_malloc( sizeof( struct arc_state ) );
st->i = st->j = 0;
- for( i = 0; i < 256; i ++ )
- st->S[i] = i;
-
if( kl <= 0 )
kl = strlen( (char*) key );
+ for( i = 0; i < 256; i ++ )
+ {
+ st->S[i] = i;
+ S2[i] = key[i%kl];
+ }
+
for( i = j = 0; i < 256; i ++ )
{
- j = ( j + st->S[i] + key[i%kl] ) & 0xff;
+ j = ( j + st->S[i] + S2[i] ) & 0xff;
tmp = st->S[i];
st->S[i] = st->S[j];
st->S[j] = tmp;
}
+ memset( S2, 0, 256 );
+ i = j = 0;
+
for( i = 0; i < cycles; i ++ )
- rc4_getbyte( st );
+ arc_getbyte( st );
return st;
}
/*
- For those who don't know, RC4 is basically an algorithm that generates a
- stream of bytes after you give it a key. Just get a byte from it and xor
- it with your cleartext. To decrypt, just give it the same key again and
- start xorring.
+ For those who don't know, ArcFour is basically an algorithm that generates
+ a stream of bytes after you give it a key. Just get a byte from it and
+ xor it with your cleartext. To decrypt, just give it the same key again
+ and start xorring.
- The function above initializes the RC4 byte generator, the next function
- can be used to get bytes from the generator (and shuffle things a bit).
+ The function above initializes the byte generator, the next function can
+ be used to get bytes from the generator (and shuffle things a bit).
*/
-unsigned char rc4_getbyte( struct rc4_state *st )
+unsigned char arc_getbyte( struct arc_state *st )
{
unsigned char tmp;
@@ -100,16 +110,17 @@ unsigned char rc4_getbyte( struct rc4_state *st )
tmp = st->S[st->i];
st->S[st->i] = st->S[st->j];
st->S[st->j] = tmp;
+ tmp = (st->S[st->i] + st->S[st->j]) & 0xff;
- return st->S[(st->S[st->i] + st->S[st->j]) & 0xff];
+ return st->S[tmp];
}
/*
The following two functions can be used for reliable encryption and
decryption. Known plaintext attacks are prevented by adding some (6,
- by default) random bytes to the password before setting up the RC4
+ by default) random bytes to the password before setting up the state
structures. These 6 bytes are also saved in the results, because of
- course we'll need them in rc4_decode().
+ course we'll need them in arc_decode().
Because the length of the resulting string is unknown to the caller,
it should pass a char**. Since the encode/decode functions allocate
@@ -121,50 +132,50 @@ unsigned char rc4_getbyte( struct rc4_state *st )
Both functions return the number of bytes in the result string.
*/
-int rc4_encode( unsigned char *clear, int clear_len, unsigned char **crypt, char *password )
+int arc_encode( char *clear, int clear_len, unsigned char **crypt, char *password )
{
- struct rc4_state *st;
+ struct arc_state *st;
unsigned char *key;
int key_len, i;
- key_len = strlen( password ) + RC4_IV_LEN;
+ key_len = strlen( password ) + ARC_IV_LEN;
if( clear_len <= 0 )
- clear_len = strlen( (char*) clear );
+ clear_len = strlen( clear );
/* Prepare buffers and the key + IV */
- *crypt = g_malloc( clear_len + RC4_IV_LEN );
+ *crypt = g_malloc( clear_len + ARC_IV_LEN );
key = g_malloc( key_len );
strcpy( (char*) key, password );
/* Add the salt. Save it for later (when decrypting) and, of course,
add it to the encryption key. */
- random_bytes( crypt[0], RC4_IV_LEN );
- memcpy( key + key_len - RC4_IV_LEN, crypt[0], RC4_IV_LEN );
+ random_bytes( crypt[0], ARC_IV_LEN );
+ memcpy( key + key_len - ARC_IV_LEN, crypt[0], ARC_IV_LEN );
/* Generate the initial S[] from the IVed key. */
- st = rc4_keymaker( key, key_len, RC4_CYCLES );
+ st = arc_keymaker( key, key_len, ARC_CYCLES );
g_free( key );
for( i = 0; i < clear_len; i ++ )
- crypt[0][i+RC4_IV_LEN] = clear[i] ^ rc4_getbyte( st );
+ crypt[0][i+ARC_IV_LEN] = clear[i] ^ arc_getbyte( st );
g_free( st );
- return clear_len + RC4_IV_LEN;
+ return clear_len + ARC_IV_LEN;
}
-int rc4_decode( unsigned char *crypt, int crypt_len, unsigned char **clear, char *password )
+int arc_decode( unsigned char *crypt, int crypt_len, char **clear, char *password )
{
- struct rc4_state *st;
+ struct arc_state *st;
unsigned char *key;
int key_len, clear_len, i;
- key_len = strlen( password ) + RC4_IV_LEN;
- clear_len = crypt_len - RC4_IV_LEN;
+ key_len = strlen( password ) + ARC_IV_LEN;
+ clear_len = crypt_len - ARC_IV_LEN;
if( clear_len < 0 )
{
- *clear = (unsigned char*) g_strdup( "" );
+ *clear = g_strdup( "" );
return 0;
}
@@ -172,15 +183,15 @@ int rc4_decode( unsigned char *crypt, int crypt_len, unsigned char **clear, char
*clear = g_malloc( clear_len + 1 );
key = g_malloc( key_len );
strcpy( (char*) key, password );
- for( i = 0; i < RC4_IV_LEN; i ++ )
- key[key_len-RC4_IV_LEN+i] = crypt[i];
+ for( i = 0; i < ARC_IV_LEN; i ++ )
+ key[key_len-ARC_IV_LEN+i] = crypt[i];
/* Generate the initial S[] from the IVed key. */
- st = rc4_keymaker( key, key_len, RC4_CYCLES );
+ st = arc_keymaker( key, key_len, ARC_CYCLES );
g_free( key );
for( i = 0; i < clear_len; i ++ )
- clear[0][i] = crypt[i+RC4_IV_LEN] ^ rc4_getbyte( st );
+ clear[0][i] = crypt[i+ARC_IV_LEN] ^ arc_getbyte( st );
clear[0][i] = 0; /* Nice to have for plaintexts. */
g_free( st );
diff --git a/lib/rc4.h b/lib/arc.h
index 2d4d3cc8..882372ed 100644
--- a/lib/rc4.h
+++ b/lib/arc.h
@@ -1,9 +1,9 @@
/***************************************************************************\
* *
* BitlBee - An IRC to IM gateway *
-* Simple (but secure) RC4 implementation for safer password storage. *
+* Simple (but secure) ArcFour implementation for safer password storage. *
* *
-* Copyright 2006 Wilmer van der Gaast <wilmer@gaast.net> *
+* Copyright 2007 Wilmer van der Gaast <wilmer@gaast.net> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
@@ -22,15 +22,15 @@
\***************************************************************************/
-/* See rc4.c for more information. */
+/* See arc.c for more information. */
-struct rc4_state
+struct arc_state
{
unsigned char S[256];
unsigned char i, j;
};
-struct rc4_state *rc4_keymaker( unsigned char *key, int kl, int cycles );
-unsigned char rc4_getbyte( struct rc4_state *st );
-int rc4_encode( unsigned char *clear, int clear_len, unsigned char **crypt, char *password );
-int rc4_decode( unsigned char *crypt, int crypt_len, unsigned char **clear, char *password );
+struct arc_state *arc_keymaker( unsigned char *key, int kl, int cycles );
+unsigned char arc_getbyte( struct arc_state *st );
+int arc_encode( char *clear, int clear_len, unsigned char **crypt, char *password );
+int arc_decode( unsigned char *crypt, int crypt_len, char **clear, char *password );
diff --git a/lib/base64.c b/lib/base64.c
index 69069dae..64e9692a 100644
--- a/lib/base64.c
+++ b/lib/base64.c
@@ -30,10 +30,10 @@ static const char real_b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv
char *tobase64(const char *text)
{
- return base64_encode(text, strlen(text));
+ return base64_encode((const unsigned char *)text, strlen(text));
}
-char *base64_encode(const char *in, int len)
+char *base64_encode(const unsigned char *in, int len)
{
char *out;
diff --git a/lib/base64.h b/lib/base64.h
index 570f2b14..ebd74bf1 100644
--- a/lib/base64.h
+++ b/lib/base64.h
@@ -26,7 +26,7 @@
#include <gmodule.h>
G_MODULE_EXPORT char *tobase64( const char *text );
-G_MODULE_EXPORT char *base64_encode( const char *in, int len );
+G_MODULE_EXPORT char *base64_encode( const unsigned char *in, int len );
G_MODULE_EXPORT int base64_encode_real( const unsigned char *in, int inlen, unsigned char *out, const char *b64digits );
G_MODULE_EXPORT char *frombase64( const char *in );
G_MODULE_EXPORT int base64_decode( const char *in, unsigned char **out );
diff --git a/lib/misc.c b/lib/misc.c
index 9061af39..5e385d4a 100644
--- a/lib/misc.c
+++ b/lib/misc.c
@@ -544,3 +544,51 @@ struct ns_srv_reply *srv_lookup( char *service, char *protocol, char *domain )
return reply;
}
+
+/* Word wrapping. Yes, I know this isn't UTF-8 clean. I'm willing to take the risk. */
+char *word_wrap( char *msg, int line_len )
+{
+ GString *ret = g_string_sized_new( strlen( msg ) + 16 );
+
+ while( strlen( msg ) > line_len )
+ {
+ int i;
+
+ /* First try to find out if there's a newline already. Don't
+ want to add more splits than necessary. */
+ for( i = line_len; i > 0 && msg[i] != '\n'; i -- );
+ if( msg[i] == '\n' )
+ {
+ g_string_append_len( ret, msg, i + 1 );
+ msg += i + 1;
+ continue;
+ }
+
+ for( i = line_len; i > 0; i -- )
+ {
+ if( msg[i] == '-' )
+ {
+ g_string_append_len( ret, msg, i + 1 );
+ g_string_append_c( ret, '\n' );
+ msg += i + 1;
+ break;
+ }
+ else if( msg[i] == ' ' )
+ {
+ g_string_append_len( ret, msg, i );
+ g_string_append_c( ret, '\n' );
+ msg += i + 1;
+ break;
+ }
+ }
+ if( i == 0 )
+ {
+ g_string_append_len( ret, msg, line_len );
+ g_string_append_c( ret, '\n' );
+ msg += line_len;
+ }
+ }
+ g_string_append( ret, msg );
+
+ return g_string_free( ret, FALSE );
+}
diff --git a/lib/misc.h b/lib/misc.h
index 55dabfc4..1d76f7f2 100644
--- a/lib/misc.h
+++ b/lib/misc.h
@@ -63,4 +63,6 @@ G_MODULE_EXPORT int bool2int( char *value );
G_MODULE_EXPORT struct ns_srv_reply *srv_lookup( char *service, char *protocol, char *domain );
+G_MODULE_EXPORT char *word_wrap( char *msg, int line_len );
+
#endif
diff --git a/lib/ssl_bogus.c b/lib/ssl_bogus.c
index 00aaa7c4..5bae3496 100644
--- a/lib/ssl_bogus.c
+++ b/lib/ssl_bogus.c
@@ -51,6 +51,11 @@ int ssl_getfd( void *conn )
return( -1 );
}
+void *ssl_starttls( int fd, ssl_input_function func, gpointer data )
+{
+ return NULL;
+}
+
b_input_condition ssl_getdirection( void *conn )
{
return GAIM_INPUT_READ;
diff --git a/protocols/jabber/sasl.c b/protocols/jabber/sasl.c
index 69199a8b..6eee37b3 100644
--- a/protocols/jabber/sasl.c
+++ b/protocols/jabber/sasl.c
@@ -88,7 +88,7 @@ xt_status sasl_pkt_mechanisms( struct xt_node *node, gpointer data )
s[0] = 0;
strcpy( s + 1, jd->username );
strcpy( s + 2 + strlen( jd->username ), ic->acc->pass );
- reply->text = base64_encode( s, len );
+ reply->text = base64_encode( (unsigned char *)s, len );
reply->text_len = strlen( reply->text );
g_free( s );
}
@@ -184,7 +184,8 @@ xt_status sasl_pkt_challenge( struct xt_node *node, gpointer data )
struct im_connection *ic = data;
struct jabber_data *jd = ic->proto_data;
struct xt_node *reply = NULL;
- char *nonce = NULL, *realm = NULL, *cnonce = NULL, cnonce_bin[30];
+ char *nonce = NULL, *realm = NULL, *cnonce = NULL;
+ unsigned char cnonce_bin[30];
char *digest_uri = NULL;
char *dec = NULL;
char *s = NULL;
@@ -215,7 +216,7 @@ xt_status sasl_pkt_challenge( struct xt_node *node, gpointer data )
if( !realm )
realm = g_strdup( jd->server );
- random_bytes( (unsigned char *) cnonce_bin, sizeof( cnonce_bin ) );
+ random_bytes( cnonce_bin, sizeof( cnonce_bin ) );
cnonce = base64_encode( cnonce_bin, sizeof( cnonce_bin ) );
digest_uri = g_strdup_printf( "%s/%s", "xmpp", jd->server );
diff --git a/protocols/nogaim.c b/protocols/nogaim.c
index 4b0b738b..3307b0f5 100644
--- a/protocols/nogaim.c
+++ b/protocols/nogaim.c
@@ -47,7 +47,7 @@ gboolean load_plugin(char *path)
GModule *mod = g_module_open(path, G_MODULE_BIND_LAZY);
if(!mod) {
- log_message(LOGLVL_ERROR, "Can't find `%s', not loading", path);
+ log_message(LOGLVL_ERROR, "Can't find `%s', not loading (%s)\n", path, g_module_error());
return FALSE;
}
@@ -607,14 +607,27 @@ void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags,
( ( ( u->online != oo ) && !u->away ) || /* Voice joining people */
( ( u->online == oo ) && ( oa == !u->away ) ) ) ) /* (De)voice people changing state */
{
- irc_write( ic->irc, ":%s MODE %s %cv %s", ic->irc->myhost,
- ic->irc->channel, u->away?'-':'+', u->nick );
+ char *from;
+
+ if( set_getbool( &ic->irc->set, "simulate_netsplit" ) )
+ {
+ from = g_strdup( ic->irc->myhost );
+ }
+ else
+ {
+ from = g_strdup_printf( "%s!%s@%s", ic->irc->mynick, ic->irc->mynick,
+ ic->irc->myhost );
+ }
+ irc_write( ic->irc, ":%s MODE %s %cv %s", from, ic->irc->channel,
+ u->away?'-':'+', u->nick );
+ g_free( from );
}
}
void imcb_buddy_msg( struct im_connection *ic, char *handle, char *msg, u_int32_t flags, time_t sent_at )
{
irc_t *irc = ic->irc;
+ char *wrapped;
user_t *u;
u = user_findhandle( ic, handle );
@@ -657,37 +670,9 @@ void imcb_buddy_msg( struct im_connection *ic, char *handle, char *msg, u_int32_
( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )
strip_html( msg );
- while( strlen( msg ) > 425 )
- {
- char tmp, *nl;
-
- tmp = msg[425];
- msg[425] = 0;
-
- /* If there's a newline/space in this string, split up there,
- looks a bit prettier. */
- if( ( nl = strrchr( msg, '\n' ) ) || ( nl = strrchr( msg, ' ' ) ) )
- {
- msg[425] = tmp;
- tmp = *nl;
- *nl = 0;
- }
-
- irc_msgfrom( irc, u->nick, msg );
-
- /* Move on. */
- if( nl )
- {
- *nl = tmp;
- msg = nl + 1;
- }
- else
- {
- msg[425] = tmp;
- msg += 425;
- }
- }
- irc_msgfrom( irc, u->nick, msg );
+ wrapped = word_wrap( msg, 425 );
+ irc_msgfrom( irc, u->nick, wrapped );
+ g_free( wrapped );
}
void imcb_buddy_typing( struct im_connection *ic, char *handle, u_int32_t flags )
@@ -749,6 +734,7 @@ void imcb_chat_free( struct groupchat *c )
void imcb_chat_msg( struct groupchat *c, char *who, char *msg, u_int32_t flags, time_t sent_at )
{
struct im_connection *ic = c->ic;
+ char *wrapped;
user_t *u;
/* Gaim sends own messages through this too. IRC doesn't want this, so kill them */
@@ -761,10 +747,16 @@ void imcb_chat_msg( struct groupchat *c, char *who, char *msg, u_int32_t flags,
( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )
strip_html( msg );
+ wrapped = word_wrap( msg, 425 );
if( c && u )
- irc_privmsg( ic->irc, u, "PRIVMSG", c->channel, "", msg );
+ {
+ irc_privmsg( ic->irc, u, "PRIVMSG", c->channel, "", wrapped );
+ }
else
- imcb_log( ic, "Message from/to conversation %s@0x%x (unknown conv/user): %s", who, (int) c, msg );
+ {
+ imcb_log( ic, "Message from/to conversation %s@0x%x (unknown conv/user): %s", who, (int) c, wrapped );
+ }
+ g_free( wrapped );
}
struct groupchat *imcb_chat_new( struct im_connection *ic, char *handle )
diff --git a/protocols/nogaim.h b/protocols/nogaim.h
index 6aa057ff..5bf6d922 100644
--- a/protocols/nogaim.h
+++ b/protocols/nogaim.h
@@ -97,13 +97,21 @@ struct im_connection
struct groupchat {
struct im_connection *ic;
+ /* stuff used just for chat */
+ /* The in_room variable is a list of handles (not nicks!), kind of
+ * "nick list". This is how you can check who is in the group chat
+ * already, for example to avoid adding somebody two times. */
GList *in_room;
GList *ignored;
struct groupchat *next;
char *channel;
+ /* The title variable contains the ID you gave when you created the
+ * chat using imcb_chat_new(). */
char *title;
char joined;
+ /* This is for you, you can add your own structure here to extend this
+ * structure for your protocol's needs. */
void *data;
};
@@ -122,26 +130,52 @@ struct buddy {
struct prpl {
int options;
+ /* You should set this to the name of your protocol.
+ * - The user sees this name ie. when imcb_log() is used. */
const char *name;
/* Added this one to be able to add per-account settings, don't think
- it should be used for anything else. */
+ * it should be used for anything else. You are supposed to use the
+ * set_add() function to add new settings. */
void (* init) (account_t *);
- /* These should all be pretty obvious. */
+ /* The typical usage of the login() function:
+ * - Create an im_connection using imcb_new() from the account_t parameter.
+ * - Initialize your myproto_data struct - you should store all your protocol-specific data there.
+ * - Save your custom structure to im_connection->proto_data.
+ * - Use proxy_connect() to connect to the server.
+ */
void (* login) (account_t *);
+ /* Implementing this function is optional. */
void (* keepalive) (struct im_connection *);
+ /* In this function you should:
+ * - Tell the server about you are logging out.
+ * - g_free() your myproto_data struct as BitlBee does not know how to
+ * properly do so.
+ */
void (* logout) (struct im_connection *);
+ /* This function is called when the user wants to send a message to a handle.
+ * - 'to' is a handle, not a nick
+ * - 'flags' may be ignored
+ */
int (* buddy_msg) (struct im_connection *, char *to, char *message, int flags);
+ /* This function is called then the user uses the /away IRC command.
+ * - 'state' contains the away reason.
+ * - 'message' may be ignored if your protocol does not support it.
+ */
void (* set_away) (struct im_connection *, char *state, char *message);
+ /* Implementing this function is optional. */
void (* get_away) (struct im_connection *, char *who);
+ /* Implementing this function is optional. */
int (* send_typing) (struct im_connection *, char *who, int flags);
- /* For now BitlBee doesn't really handle groups, just set it to NULL. */
+ /* 'name' is a handle to add/remove. For now BitlBee doesn't really
+ * handle groups, just set it to NULL, so you can ignore that
+ * parameter. */
void (* add_buddy) (struct im_connection *, char *name, char *group);
void (* remove_buddy) (struct im_connection *, char *name, char *group);
- /* Block list stuff. */
+ /* Block list stuff. Implementing these are optional. */
void (* add_permit) (struct im_connection *, char *who);
void (* add_deny) (struct im_connection *, char *who);
void (* rem_permit) (struct im_connection *, char *who);
@@ -150,23 +184,41 @@ struct prpl {
void (* set_permit_deny)(struct im_connection *);
/* Request profile info. Free-formatted stuff, the IM module gives back
- this info via imcb_log(). */
+ this info via imcb_log(). Implementing these are optional. */
void (* get_info) (struct im_connection *, char *who);
void (* set_my_name) (struct im_connection *, char *name);
void (* set_name) (struct im_connection *, char *who, char *name);
/* Group chat stuff. */
+ /* This is called when the user uses the /invite IRC command.
+ * - 'who' may be ignored
+ * - 'message' is a handle to invite
+ */
void (* chat_invite) (struct groupchat *, char *who, char *message);
+ /* This is called when the user uses the /part IRC command in a group
+ * chat. You just should tell the user about it, nothing more. */
void (* chat_leave) (struct groupchat *);
+ /* This is called when the user sends a message to the groupchat.
+ * 'flags' may be ignored. */
void (* chat_msg) (struct groupchat *, char *message, int flags);
+ /* This is called when the user uses the /join #nick IRC command.
+ * - 'who' is the handle of the nick
+ */
struct groupchat *
(* chat_with) (struct im_connection *, char *who);
+ /* This is used when the user uses the /join #channel IRC command. If
+ * your protocol does not support publicly named group chats, then do
+ * not implement this. */
struct groupchat *
(* chat_join) (struct im_connection *, char *room, char *nick, char *password);
+ /* You can tell what away states your protocol supports, so that
+ * BitlBee will try to map the IRC away reasons to them, or use
+ * GAIM_AWAY_CUSTOM when calling skype_set_away(). */
GList *(* away_states)(struct im_connection *ic);
- /* Mainly for AOL, since they think "Bung hole" == "Bu ngho le". *sigh* */
+ /* Mainly for AOL, since they think "Bung hole" == "Bu ngho le". *sigh*
+ * - Most protocols will just want to set this to g_strcasecmp().*/
int (* handle_cmp) (const char *who1, const char *who2);
};
@@ -174,21 +226,40 @@ struct prpl {
void nogaim_init();
G_MODULE_EXPORT GSList *get_connections();
G_MODULE_EXPORT struct prpl *find_protocol( const char *name );
+/* When registering a new protocol, you should allocate space for a new prpl
+ * struct, initialize it (set the function pointers to point to your
+ * functions), finally call this function. */
G_MODULE_EXPORT void register_protocol( struct prpl * );
/* Connection management. */
+/* You will need this function in prpl->login() to get an im_connection from
+ * the account_t parameter. */
G_MODULE_EXPORT struct im_connection *imcb_new( account_t *acc );
G_MODULE_EXPORT void imcb_free( struct im_connection *ic );
+/* Once you're connected, you should call this function, so that the user will
+ * see the success. */
G_MODULE_EXPORT void imcb_connected( struct im_connection *ic );
+/* This can be used to disconnect when something went wrong (ie. read error
+ * from the server). You probably want to set the second parameter to TRUE. */
G_MODULE_EXPORT void imc_logout( struct im_connection *ic, int allow_reconnect );
/* Communicating with the user. */
+/* A printf()-like function to tell the user anything you want. */
G_MODULE_EXPORT void imcb_log( struct im_connection *ic, char *format, ... ) G_GNUC_PRINTF( 2, 3 );
+/* To tell the user an error, ie. before logging out when an error occurs. */
G_MODULE_EXPORT void imcb_error( struct im_connection *ic, char *format, ... ) G_GNUC_PRINTF( 2, 3 );
+/* To ask a your about something.
+ * - 'msg' is the question.
+ * - 'data' can be your custom struct - it will be passed to the callbacks.
+ * - 'doit' or 'dont' will be called depending of the answer of the user.
+ */
G_MODULE_EXPORT void imcb_ask( struct im_connection *ic, char *msg, void *data, void *doit, void *dont );
G_MODULE_EXPORT void imcb_ask_add( struct im_connection *ic, char *handle, const char *realname );
/* Buddy management */
+/* This function should be called for each handle which are visible to the
+ * user, usually after a login, or if the user added a buddy and the IM
+ * server confirms that the add was successful. Don't forget to do this! */
G_MODULE_EXPORT void imcb_add_buddy( struct im_connection *ic, char *handle, char *group );
G_MODULE_EXPORT void imcb_remove_buddy( struct im_connection *ic, char *handle, char *group );
G_MODULE_EXPORT struct buddy *imcb_find_buddy( struct im_connection *ic, char *handle );
@@ -196,17 +267,30 @@ G_MODULE_EXPORT void imcb_rename_buddy( struct im_connection *ic, char *handle,
G_MODULE_EXPORT void imcb_buddy_nick_hint( struct im_connection *ic, char *handle, char *nick );
/* Buddy activity */
+/* To manipulate the status of a handle.
+ * - flags can be |='d with OPT_* constants. You will need at least:
+ * OPT_LOGGED_IN and OPT_AWAY.
+ * - 'state' and 'message' can be NULL */
G_MODULE_EXPORT void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, const char *state, const char *message );
/* Not implemented yet! */ G_MODULE_EXPORT void imcb_buddy_times( struct im_connection *ic, const char *handle, time_t login, time_t idle );
+/* Call when a handle says something. 'flags' and 'sent_at may be just 0. */
G_MODULE_EXPORT void imcb_buddy_msg( struct im_connection *ic, char *handle, char *msg, u_int32_t flags, time_t sent_at );
G_MODULE_EXPORT void imcb_buddy_typing( struct im_connection *ic, char *handle, u_int32_t flags );
G_MODULE_EXPORT void imcb_clean_handle( struct im_connection *ic, char *handle );
/* Groupchats */
G_MODULE_EXPORT void imcb_chat_invited( struct im_connection *ic, char *handle, char *who, char *msg, GList *data );
+/* These two functions are to create a group chat.
+ * - imcb_chat_new(): the 'handle' parameter identifies the chat, like the
+ * channel name on IRC.
+ * - After you have a groupchat pointer, you should add the handles, finally
+ * the user her/himself. At that point the group chat will be visible to the
+ * user, too. */
G_MODULE_EXPORT struct groupchat *imcb_chat_new( struct im_connection *ic, char *handle );
G_MODULE_EXPORT void imcb_chat_add_buddy( struct groupchat *b, char *handle );
+/* To remove a handle from a group chat. Reason can be NULL. */
G_MODULE_EXPORT void imcb_chat_remove_buddy( struct groupchat *b, char *handle, char *reason );
+/* To tell BitlBee 'who' said 'msg' in 'c'. 'flags' and 'sent_at' can be 0. */
G_MODULE_EXPORT void imcb_chat_msg( struct groupchat *c, char *who, char *msg, u_int32_t flags, time_t sent_at );
G_MODULE_EXPORT void imcb_chat_free( struct groupchat *c );
diff --git a/root_commands.c b/root_commands.c
index 0f9f776c..e8c796d3 100644
--- a/root_commands.c
+++ b/root_commands.c
@@ -382,7 +382,7 @@ static void cmd_account( irc_t *irc, char **cmd )
return;
}
- if( cmd[3] )
+ if( cmd[3] && set_name )
{
set_t *s = set_find( &a->set, set_name );
diff --git a/storage_xml.c b/storage_xml.c
index 00fca425..8618c5fe 100644
--- a/storage_xml.c
+++ b/storage_xml.c
@@ -26,7 +26,7 @@
#define BITLBEE_CORE
#include "bitlbee.h"
#include "base64.h"
-#include "rc4.h"
+#include "arc.h"
#include "md5.h"
typedef enum
@@ -131,7 +131,8 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na
else if( g_strcasecmp( element_name, "account" ) == 0 )
{
char *protocol, *handle, *server, *password = NULL, *autoconnect;
- char *pass_b64 = NULL, *pass_rc4 = NULL;
+ char *pass_b64 = NULL;
+ unsigned char *pass_cr = NULL;
int pass_len;
struct prpl *prpl = NULL;
@@ -150,9 +151,8 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na
else if( !prpl )
g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
"Unknown protocol: %s", protocol );
- else if( ( pass_len = base64_decode( pass_b64, (unsigned char**) &pass_rc4 ) ) &&
- rc4_decode( (unsigned char*) pass_rc4, pass_len,
- (unsigned char**) &password, xd->given_pass ) )
+ else if( ( pass_len = base64_decode( pass_b64, (unsigned char**) &pass_cr ) ) &&
+ arc_decode( pass_cr, pass_len, &password, xd->given_pass ) )
{
xd->current_account = account_add( irc, prpl, handle, password );
if( server )
@@ -168,7 +168,7 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na
"Error while decrypting account password" );
}
- g_free( pass_rc4 );
+ g_free( pass_cr );
g_free( password );
}
else if( g_strcasecmp( element_name, "setting" ) == 0 )
@@ -409,7 +409,7 @@ static storage_status_t xml_save( irc_t *irc, int overwrite )
md5_append( &md5_state, pass_md5 + 16, 5 ); /* Add the salt. */
md5_finish( &md5_state, pass_md5 );
/* Save the hash in base64-encoded form. */
- pass_buf = base64_encode( (char*) pass_md5, 21 );
+ pass_buf = base64_encode( pass_md5, 21 );
if( !xml_printf( fd, 0, "<user nick=\"%s\" password=\"%s\" version=\"%d\">\n", irc->nick, pass_buf, XML_FORMAT_VERSION ) )
goto write_error;
@@ -423,12 +423,13 @@ static storage_status_t xml_save( irc_t *irc, int overwrite )
for( acc = irc->accounts; acc; acc = acc->next )
{
- char *pass_rc4, *pass_b64;
+ unsigned char *pass_cr;
+ char *pass_b64;
int pass_len;
- pass_len = rc4_encode( (unsigned char*) acc->pass, strlen( acc->pass ), (unsigned char**) &pass_rc4, irc->password );
- pass_b64 = base64_encode( pass_rc4, pass_len );
- g_free( pass_rc4 );
+ pass_len = arc_encode( acc->pass, strlen( acc->pass ), (unsigned char**) &pass_cr, irc->password );
+ pass_b64 = base64_encode( pass_cr, pass_len );
+ g_free( pass_cr );
if( !xml_printf( fd, 1, "<account protocol=\"%s\" handle=\"%s\" password=\"%s\" autoconnect=\"%d\"", acc->prpl->name, acc->user, pass_b64, acc->auto_connect ) )
{
diff --git a/tests/Makefile b/tests/Makefile
index 4d4ed8d3..5bc3fbde 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -12,7 +12,7 @@ distclean: clean
main_objs = account.o bitlbee.o conf.o crypting.o help.o ipc.o irc.o irc_commands.o log.o nick.o query.o root_commands.o set.o storage.o storage_xml.o storage_text.o user.o
-test_objs = check.o check_util.o check_nick.o check_md5.o check_irc.o check_help.o check_user.o check_crypting.o check_set.o
+test_objs = check.o check_util.o check_nick.o check_md5.o check_arc.o check_irc.o check_help.o check_user.o check_crypting.o check_set.o
check: $(test_objs) $(addprefix ../, $(main_objs)) ../protocols/protocols.o ../lib/lib.o
@echo '*' Linking $@
diff --git a/tests/check.c b/tests/check.c
index 488d9608..043889d6 100644
--- a/tests/check.c
+++ b/tests/check.c
@@ -47,6 +47,9 @@ Suite *nick_suite(void);
/* From check_md5.c */
Suite *md5_suite(void);
+/* From check_arc.c */
+Suite *arc_suite(void);
+
/* From check_irc.c */
Suite *irc_suite(void);
@@ -101,6 +104,7 @@ int main (int argc, char **argv)
sr = srunner_create(util_suite());
srunner_add_suite(sr, nick_suite());
srunner_add_suite(sr, md5_suite());
+ srunner_add_suite(sr, arc_suite());
srunner_add_suite(sr, irc_suite());
srunner_add_suite(sr, help_suite());
srunner_add_suite(sr, user_suite());
diff --git a/tests/check_arc.c b/tests/check_arc.c
new file mode 100644
index 00000000..989a0a66
--- /dev/null
+++ b/tests/check_arc.c
@@ -0,0 +1,95 @@
+#include <stdlib.h>
+#include <glib.h>
+#include <gmodule.h>
+#include <check.h>
+#include <string.h>
+#include <stdio.h>
+#include "arc.h"
+
+char *password = "TotT";
+
+char *clear_tests[] =
+{
+ "Wie dit leest is gek :-)",
+ "ItllBeBitlBee",
+ "One more boring password",
+ NULL
+};
+
+static void check_codec(int l)
+{
+ int i;
+
+ for( i = 0; clear_tests[i]; i++ )
+ {
+ tcase_fn_start (clear_tests[i], __FILE__, __LINE__);
+ unsigned char *crypted;
+ char *decrypted;
+ int len;
+
+ len = arc_encode( clear_tests[i], 0, &crypted, password );
+ len = arc_decode( crypted, len, &decrypted, password );
+
+ fail_if( strcmp( clear_tests[i], decrypted ) != 0,
+ "%s didn't decrypt back properly", clear_tests[i] );
+
+ g_free( crypted );
+ g_free( decrypted );
+ }
+}
+
+struct
+{
+ unsigned char crypted[24];
+ int len;
+ char *decrypted;
+} decrypt_tests[] = {
+ {
+ {
+ 0xc3, 0x0d, 0x43, 0xc3, 0xee, 0x80, 0xe2, 0x8c, 0x0b, 0x29, 0x32, 0x7e,
+ 0x38, 0x05, 0x82, 0x10, 0x21, 0x1c, 0x4a, 0x00, 0x2c
+ }, 21, "Debugging sucks"
+ },
+ {
+ {
+ 0xb0, 0x00, 0x57, 0x0d, 0x0d, 0x0d, 0x70, 0xe1, 0xc0, 0x00, 0xa4, 0x25,
+ 0x7d, 0xbe, 0x03, 0xcc, 0x24, 0xd1, 0x0c
+ }, 19, "Testing rocks"
+ },
+ {
+ {
+ 0xb6, 0x92, 0x59, 0xe4, 0xf9, 0xc1, 0x7a, 0xf6, 0xf3, 0x18, 0xea, 0x28,
+ 0x73, 0x6d, 0xb3, 0x0a, 0x6f, 0x0a, 0x2b, 0x43, 0x57, 0xe9, 0x3e, 0x63
+ }, 24, "OSCAR is creepy..."
+ }
+};
+
+static void check_decod(int l)
+{
+ int i;
+
+ for( i = 0; clear_tests[i]; i++ )
+ {
+ tcase_fn_start (decrypt_tests[i].decrypted, __FILE__, __LINE__);
+ char *decrypted;
+ int len;
+
+ len = arc_decode( decrypt_tests[i].crypted, decrypt_tests[i].len,
+ &decrypted, password );
+
+ fail_if( strcmp( decrypt_tests[i].decrypted, decrypted ) != 0,
+ "%s didn't decrypt properly", clear_tests[i] );
+
+ g_free( decrypted );
+ }
+}
+
+Suite *arc_suite (void)
+{
+ Suite *s = suite_create("ArcFour");
+ TCase *tc_core = tcase_create("Core");
+ suite_add_tcase (s, tc_core);
+ tcase_add_test (tc_core, check_codec);
+ tcase_add_test (tc_core, check_decod);
+ return s;
+}
diff --git a/tests/check_util.c b/tests/check_util.c
index 284ddba3..b00d645b 100644
--- a/tests/check_util.c
+++ b/tests/check_util.c
@@ -103,6 +103,63 @@ START_TEST(test_set_url_username_pwd)
fail_unless (url.port == 1080);
END_TEST
+struct
+{
+ char *orig;
+ int line_len;
+ char *wrapped;
+} word_wrap_tests[] = {
+ {
+ "Line-wrapping is not as easy as it seems?",
+ 16,
+ "Line-wrapping is\nnot as easy as\nit seems?"
+ },
+ {
+ "Line-wrapping is not as easy as it seems?",
+ 8,
+ "Line-\nwrapping\nis not\nas easy\nas it\nseems?"
+ },
+ {
+ "Line-wrapping is\nnot as easy as it seems?",
+ 8,
+ "Line-\nwrapping\nis\nnot as\neasy as\nit\nseems?"
+ },
+ {
+ "a aa aaa aaaa aaaaa aaaaaa aaaaaaa aaaaaaaa",
+ 5,
+ "a aa\naaa\naaaa\naaaaa\naaaaa\na\naaaaa\naa\naaaaa\naaa",
+ },
+ {
+ "aaaaaaaa aaaaaaa aaaaaa aaaaa aaaa aaa aa a",
+ 5,
+ "aaaaa\naaa\naaaaa\naa\naaaaa\na\naaaaa\naaaa\naaa\naa a",
+ },
+ {
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ 5,
+ "aaaaa\naaaaa\naaaaa\naaaaa\naaaaa\naaaaa\naaaaa\na",
+ },
+ {
+ NULL
+ }
+};
+
+START_TEST(test_word_wrap)
+ int i;
+
+ for( i = 0; word_wrap_tests[i].orig && *word_wrap_tests[i].orig; i ++ )
+ {
+ char *wrapped = word_wrap( word_wrap_tests[i].orig, word_wrap_tests[i].line_len );
+
+ fail_unless( strcmp( word_wrap_tests[i].wrapped, wrapped ) == 0,
+ "%s (line_len = %d) should wrap to `%s', not to `%s'",
+ word_wrap_tests[i].orig, word_wrap_tests[i].line_len,
+ word_wrap_tests[i].wrapped, wrapped );
+
+ g_free( wrapped );
+ }
+END_TEST
+
Suite *util_suite (void)
{
Suite *s = suite_create("Util");
@@ -115,5 +172,6 @@ Suite *util_suite (void)
tcase_add_test (tc_core, test_set_url_port);
tcase_add_test (tc_core, test_set_url_username);
tcase_add_test (tc_core, test_set_url_username_pwd);
+ tcase_add_test (tc_core, test_word_wrap);
return s;
}
diff --git a/unix.c b/unix.c
index 2be16b2b..0abf43ea 100644
--- a/unix.c
+++ b/unix.c
@@ -46,19 +46,18 @@ int main( int argc, char *argv[], char **envp )
memset( &global, 0, sizeof( global_t ) );
- b_main_init();
log_init();
- nogaim_init();
-
- srand( time( NULL ) ^ getpid() );
-
CONF_FILE = g_strdup( CONF_FILE_DEF );
- global.helpfile = g_strdup( HELP_FILE );
-
global.conf = conf_load( argc, argv );
if( global.conf == NULL )
return( 1 );
+ b_main_init();
+ nogaim_init();
+
+ srand( time( NULL ) ^ getpid() );
+ global.helpfile = g_strdup( HELP_FILE );
+
if( global.conf->runmode == RUNMODE_INETD )
{
i = bitlbee_inetd_init();