aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.bzrignore2
-rw-r--r--account.c12
-rw-r--r--bitlbee.c16
-rw-r--r--bitlbee.conf14
-rw-r--r--bitlbee.h6
-rw-r--r--conf.c16
-rw-r--r--conf.h2
-rwxr-xr-xconfigure42
-rw-r--r--debian/changelog6
-rw-r--r--debian/control2
-rw-r--r--doc/CHANGES14
-rw-r--r--doc/README33
-rw-r--r--doc/RELEASE-SPEECH-1.257
-rw-r--r--doc/bitlbee.812
-rw-r--r--doc/user-guide/commands.xml10
-rw-r--r--irc.c296
-rw-r--r--irc.h5
-rw-r--r--irc_commands.c27
-rw-r--r--lib/arc.h4
-rw-r--r--lib/proxy.c11
-rw-r--r--protocols/jabber/jabber.c32
-rw-r--r--protocols/jabber/jabber.h4
-rw-r--r--protocols/jabber/jabber_util.c8
-rw-r--r--protocols/jabber/message.c17
-rw-r--r--protocols/msn/msn.h2
-rw-r--r--protocols/msn/msn_util.c8
-rw-r--r--protocols/msn/ns.c24
-rw-r--r--protocols/nogaim.c17
-rw-r--r--protocols/nogaim.h3
-rw-r--r--protocols/oscar/oscar.c18
-rw-r--r--protocols/yahoo/libyahoo2.c11
-rw-r--r--protocols/yahoo/yahoo.c12
-rw-r--r--query.c7
-rw-r--r--query.h8
-rw-r--r--root_commands.c60
-rw-r--r--set.c15
-rw-r--r--set.h1
-rw-r--r--storage_xml.c7
-rw-r--r--tests/check_irc.c4
39 files changed, 517 insertions, 328 deletions
diff --git a/.bzrignore b/.bzrignore
index 12dd9c10..7d0ad548 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -16,3 +16,5 @@ tests/check
*.gcov
*.gcno
*.o
+coverage
+bitlbee.info
diff --git a/account.c b/account.c
index 4eb78faa..2c6e1069 100644
--- a/account.c
+++ b/account.c
@@ -181,19 +181,17 @@ void account_del( irc_t *irc, account_t *acc )
{
account_t *a, *l = NULL;
+ if( acc->ic )
+ /* Caller should have checked, accounts still in use can't be deleted. */
+ return;
+
for( a = irc->accounts; a; a = (l=a)->next )
if( a == acc )
{
- if( a->ic ) return; /* Caller should have checked, accounts still in use can't be deleted. */
-
if( l )
- {
l->next = a->next;
- }
else
- {
irc->accounts = a->next;
- }
while( a->set )
set_del( &a->set, a->set->key );
@@ -202,7 +200,7 @@ void account_del( irc_t *irc, account_t *acc )
g_free( a->user );
g_free( a->pass );
- if( a->server ) g_free( a->server );
+ g_free( a->server );
if( a->reconnect ) /* This prevents any reconnect still queued to happen */
cancel_auto_reconnect( a );
g_free( a );
diff --git a/bitlbee.c b/bitlbee.c
index 59a417f0..17431546 100644
--- a/bitlbee.c
+++ b/bitlbee.c
@@ -53,11 +53,11 @@ int bitlbee_daemon_init()
#endif
;
- i = getaddrinfo( global.conf->iface, global.conf->port, &hints, &addrinfo_bind );
+ i = getaddrinfo( global.conf->iface_in, global.conf->port, &hints, &addrinfo_bind );
if( i )
{
log_message( LOGLVL_ERROR, "Couldn't parse address `%s': %s",
- global.conf->iface, gai_strerror(i) );
+ global.conf->iface_in, gai_strerror(i) );
return -1;
}
@@ -225,12 +225,16 @@ gboolean bitlbee_io_current_client_write( gpointer data, gint fd, b_input_condit
if( st == size )
{
- g_free( irc->sendbuffer );
- irc->sendbuffer = NULL;
- irc->w_watch_source_id = 0;
-
if( irc->status & USTATUS_SHUTDOWN )
+ {
irc_free( irc );
+ }
+ else
+ {
+ g_free( irc->sendbuffer );
+ irc->sendbuffer = NULL;
+ irc->w_watch_source_id = 0;
+ }
return FALSE;
}
diff --git a/bitlbee.conf b/bitlbee.conf
index 99e8106d..5fce2820 100644
--- a/bitlbee.conf
+++ b/bitlbee.conf
@@ -9,10 +9,9 @@
## RunMode:
##
## Inetd -- Run from inetd (default)
-## Daemon -- Run as a stand-alone daemon -- EXPERIMENTAL! BitlBee is not yet
-## stable enough to serve lots of users from one process. Because of this
-## and other reasons, the use of daemon-mode is *STRONGLY* discouraged,
-## don't even *think* of reporting bugs when you use this.
+## Daemon -- Run as a stand-alone daemon, serving all users from one process.
+## This saves memory if there are more users, the downside is that when one
+## user hits a crash-bug, all other users will also lose their connection.
## ForkDaemon -- Run as a stand-alone daemon, but keep all clients in separate
## child processes. This should be pretty safe and reliable to use instead
## of inetd mode.
@@ -34,6 +33,13 @@
# DaemonInterface = 0.0.0.0
# DaemonPort = 6667
+## ClientInterface:
+##
+## If for any reason, you want BitlBee to use a specific address/interface
+## for outgoing traffic (IM connections, HTTP(S), etc.), set it here.
+##
+# ClientInterface = 0.0.0.0
+
## AuthMode
##
## Open -- Accept connections from anyone, use NickServ for user authentication.
diff --git a/bitlbee.h b/bitlbee.h
index 420ab70a..f10e66d2 100644
--- a/bitlbee.h
+++ b/bitlbee.h
@@ -94,10 +94,6 @@
#undef g_main_quit
#define g_main_quit __PLEASE_USE_B_MAIN_QUIT__
-#ifndef F_OK
-#define F_OK 0
-#endif
-
#ifndef G_GNUC_MALLOC
/* Doesn't exist in GLib <=2.4 while everything else in BitlBee should
work with it, so let's fake this one. */
@@ -159,6 +155,8 @@ void root_command_string( irc_t *irc, user_t *u, char *command, int flags );
void root_command( irc_t *irc, char *command[] );
gboolean bitlbee_shutdown( gpointer data, gint fd, b_input_condition cond );
+char *set_eval_root_nick( set_t *set, char *new_nick );
+
extern global_t global;
#endif
diff --git a/conf.c b/conf.c
index 339af618..2bdead65 100644
--- a/conf.c
+++ b/conf.c
@@ -44,7 +44,8 @@ conf_t *conf_load( int argc, char *argv[] )
conf = g_new0( conf_t, 1 );
- conf->iface = NULL;
+ conf->iface_in = NULL;
+ conf->iface_out = NULL;
conf->port = g_strdup( "6667" );
conf->nofork = 0;
conf->verbose = 0;
@@ -81,7 +82,7 @@ conf_t *conf_load( int argc, char *argv[] )
{
if( opt == 'i' )
{
- conf->iface = g_strdup( optarg );
+ conf->iface_in = g_strdup( optarg );
}
else if( opt == 'p' )
{
@@ -130,7 +131,7 @@ conf_t *conf_load( int argc, char *argv[] )
"An IRC-to-other-chat-networks gateway\n"
"\n"
" -I Classic/InetD mode. (Default)\n"
- " -D Daemon mode. (Still EXPERIMENTAL!)\n"
+ " -D Daemon mode. (one process serves all)\n"
" -F Forking daemon. (one process per client)\n"
" -u Run daemon as specified user.\n"
" -P Specify PID-file (not for inetd mode)\n"
@@ -201,14 +202,19 @@ static int conf_loadini( conf_t *conf, char *file )
}
else if( g_strcasecmp( ini->key, "daemoninterface" ) == 0 )
{
- g_free( conf->iface );
- conf->iface = g_strdup( ini->value );
+ g_free( conf->iface_in );
+ conf->iface_in = g_strdup( ini->value );
}
else if( g_strcasecmp( ini->key, "daemonport" ) == 0 )
{
g_free( conf->port );
conf->port = g_strdup( ini->value );
}
+ else if( g_strcasecmp( ini->key, "clientinterface" ) == 0 )
+ {
+ g_free( conf->iface_out );
+ conf->iface_out = g_strdup( ini->value );
+ }
else if( g_strcasecmp( ini->key, "authmode" ) == 0 )
{
if( g_strcasecmp( ini->value, "registered" ) == 0 )
diff --git a/conf.h b/conf.h
index d21ec577..c41fd096 100644
--- a/conf.h
+++ b/conf.h
@@ -31,7 +31,7 @@ typedef enum authmode { AUTHMODE_OPEN, AUTHMODE_CLOSED, AUTHMODE_REGISTERED } au
typedef struct conf
{
- char *iface;
+ char *iface_in, *iface_out;
char *port;
int nofork;
int verbose;
diff --git a/configure b/configure
index 22989f60..88307d88 100755
--- a/configure
+++ b/configure
@@ -73,6 +73,8 @@ Option Description Default
--events=... Event handler (glib, libevent) $events
--ssl=... SSL library to use (gnutls, nss, openssl, bogus, auto)
$ssl
+
+--target=... Cross compilation target same as host
EOF
exit;
fi
@@ -131,6 +133,13 @@ cat<<EOF>config.h
#define CPU "$cpu"
EOF
+if [ -n "$target" ]; then
+ PKG_CONFIG_PATH=/usr/$target/lib/pkgconfig
+ PATH=/usr/$target/bin:$PATH
+ CC=$target-cc
+ LD=$target-ld
+fi
+
if [ "$debug" = "1" ]; then
[ -z "$CFLAGS" ] && CFLAGS=-g
echo 'DEBUG=1' >> Makefile.settings
@@ -157,15 +166,17 @@ fi
echo "CC=$CC" >> Makefile.settings;
-if [ -n "$LD" ]; then
- echo "LD=$LD" >> Makefile.settings;
-elif type ld > /dev/null 2> /dev/null; then
- echo "LD=ld" >> Makefile.settings;
-else
- echo 'Cannot find ld, aborting.'
- exit 1;
+if [ -z "$LD" ]; then
+ if type ld > /dev/null 2> /dev/null; then
+ LD=ld
+ else
+ echo 'Cannot find ld, aborting.'
+ exit 1;
+ fi
fi
+echo "LD=$LD" >> Makefile.settings
+
if [ -z "$PKG_CONFIG" ]; then
PKG_CONFIG=pkg-config
fi
@@ -212,7 +223,14 @@ echo 'EVENT_HANDLER=events_'$events'.o' >> Makefile.settings
detect_gnutls()
{
- if libgnutls-config --version > /dev/null 2> /dev/null; then
+ if $PKG_CONFIG --exists gnutls; then
+ cat <<EOF>>Makefile.settings
+EFLAGS+=`$PKG_CONFIG --libs gnutls`
+CFLAGS+=`$PKG_CONFIG --cflags gnutls`
+EOF
+ ssl=gnutls
+ ret=1
+ elif libgnutls-config --version > /dev/null 2> /dev/null; then
cat <<EOF>>Makefile.settings
EFLAGS+=`libgnutls-config --libs`
CFLAGS+=`libgnutls-config --cflags`
@@ -374,8 +392,8 @@ else
fi
if [ "$gcov" = "1" ]; then
- echo "CFLAGS+=-ftest-coverage -fprofile-arcs" >> Makefile.settings
- echo "EFLAGS+=-lgcov" >> Makefile.settings
+ echo "CFLAGS+=--coverage" >> Makefile.settings
+ echo "EFLAGS+=--coverage" >> Makefile.settings
fi
if [ "$plugins" = 0 ]; then
@@ -488,6 +506,10 @@ CYGWIN* )
;;
esac
+if [ -n "$target" ]; then
+ echo "Cross-compiling for: $target"
+fi
+
echo
echo 'Configuration done:'
diff --git a/debian/changelog b/debian/changelog
index ff2b4071..a569f4f8 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+bitlbee (1.2-6) UNRELEASED; urgency=low
+
+ * Add Homepage and Vcs-Bzr fields.
+
+ -- Jelmer Vernooij <jelmer@samba.org> Sun, 11 May 2008 14:18:16 +0200
+
bitlbee (1.2-5) unstable; urgency=low
* Add myself to uploaders.
diff --git a/debian/control b/debian/control
index 199df0a6..e6302c13 100644
--- a/debian/control
+++ b/debian/control
@@ -5,6 +5,8 @@ Maintainer: Wilmer van der Gaast <wilmer@gaast.net>
Uploaders: Jelmer Vernooij <jelmer@samba.org>
Standards-Version: 3.8.0
Build-Depends: libglib2.0-dev (>= 2.4), libevent-dev, libgnutls-dev | libnss-dev (>= 1.6), debconf-2.0, po-debconf
+Homepage: http://www.bitlbee.org/
+Vcs-Bzr: http://code.bitlbee.org/bitlbee/
DM-Upload-Allowed: yes
Package: bitlbee
diff --git a/doc/CHANGES b/doc/CHANGES
index 65947617..93ad35e2 100644
--- a/doc/CHANGES
+++ b/doc/CHANGES
@@ -1,3 +1,17 @@
+Version 1.2.1:
+- Fixed proxy support.
+- Fixed stalling issues while connecting to Jabber when using the OpenSSL
+ module.
+- Fixed problem with GLib and ForkDaemon where processes didn't die when
+ the client disconnects.
+- Fixed handling of "set charset none". (Which pretty much breaks the account
+ completely in 1.2.)
+- You can now automatically identify yourself to BitlBee by setting a server
+ password in your IRC client.
+- Compatible with all crazy kinds of line endings that clients can send.
+
+Finished ...
+
Version 1.2:
- Added ForkDaemon mode next to the existing Daemon- and inetd modes. With
ForkDaemon you can run BitlBee as a stand-alone daemon and every connection
diff --git a/doc/README b/doc/README
index ca392573..9e681625 100644
--- a/doc/README
+++ b/doc/README
@@ -55,6 +55,11 @@ it in bitlbee.conf. You probably want to write an init script to start
BitlBee automatically after a reboot. (This is where you realise using
a package from your distro would've been a better idea. :-P)
+Note that the BitlBee code is getting stable enough for daemon mode to be
+useful. Some public servers use it, and it saves a lot of memory by serving
+tens of users from a single process. One crash affects all users, but these
+are becoming quite rare.
+
DEPENDENCIES
============
@@ -99,34 +104,6 @@ versions of make, we'd love to hear it, but it seems this just isn't
possible.
-RUNNING ON SERVERS WITH MANY USERS
-==================================
-
-BitlBee is not yet bug-free. Sometimes a bug causes the program to get into
-an infinite loop. Something you really don't want on a public server,
-especially when that machine is also used for other (mission-critical) things.
-For now we can't do much about it. We haven't seen that happen for a long
-time already on our own machines, but some people still manage to get
-themselves in nasty situations we haven't seen before.
-
-For now the best we can offer against this problem is bitlbeed, which allows
-you to setrlimit() the child processes to use no more than a specified
-number of CPU seconds. Not the best solution (not really a solution anyway),
-but certainly trashing one busy daemon process is better than trashing your
-whole machine.
-
-We don't believe adding a limit for bitlbee to /etc/security/limits.conf will
-work, because that file is only read by PAM (ie just for real login users,
-not daemons).
-
-See utils/bitlbeed.c for more information about the program.
-
-Just a little note: Now that we reach version 1.0, this shouldn't be that
-much of an issue anymore. However, on a public server, especially if you
-also use it for other things, it can't hurt to protect yourself against
-possible problems.
-
-
USAGE
=====
diff --git a/doc/RELEASE-SPEECH-1.2 b/doc/RELEASE-SPEECH-1.2
deleted file mode 100644
index ec7c48b4..00000000
--- a/doc/RELEASE-SPEECH-1.2
+++ /dev/null
@@ -1,57 +0,0 @@
-BitlBee ... is Bitl
--------------------
-
-"I CAN HAS SPEEECH?" This is how Wilmer announced to me that he was going to do
-another BitlBee release. I was as surprised as you are. I thought he had given
-up on this whole releasing business.
-
-There is some humor in using a LOLcats reference to announce a new Bee
-release. The last major BitlBee release (1.0) was done a long time before the
-hype even begun. Between then and now we've celebrated BitlBee's fifth birthday
-and had a handful of releases, but nothing big happened. As a user this lax
-release planning worries me. What if this means that later releases will take
-even longer? I don't think we should fear this. Let us explore why this release
-took so long.
-
-Personally, I blame Google.
-
-There, I've said it. Google. The guys who are so big on "Do No Evil" and all
-that jazz. They caused this release to be so late. Let me explain why.
-
-They made Wilmer an offer. Wilmer, being the sillily naive guy he is, couldn't
-refuse. There were no decapitated horses involved, but he couldn't refuse
-nonetheless. That's not a big problem of course. Lots of guys (and gals, sure)
-work for Google. It wouldn't have become a problem if they hadn't shipped him of
-to Ireland. That's where the trouble starts.
-
-Ireland. Home of the leprechauns. These rascals joined forces with aliens and
-LOLcats to abduct Wilmer. The aliens had been trying for years to kidnap him,
-but they were on his turf and his trusty sidekicks Jelmer and Maurits were there
-to help him. All that changed when he moved to Ireland.
-
-But it wasn't just that Wilmer was all alone in some strange place. It was also
-that the aliens had created the LOLcats and made an alliance with the
-leprechauns--the real rulers of Ireland. Wilmer is cool, but he's not that
-cool. So they abducted him for a few years. When he finally came back, he
-regathered his mad coding skills and hacked a new release together.
-
-By now you're thinking, what has happened to Jelmer and Maurits? Well, they're
-still here and they worked on the Bee while Wilmer was absent. But, like open
-source, they are very Bitl--they're cool, but they're ready when they're
-ready.
-
-Well, whatever you may think of my little theory, they did take forever to
-launch this release. We're not mad at them, because it shows. They have
-added some cool new features and made plenty of changes under the hood. Let me
-give you a sneak preview of some of the new features: Jabber groupchats are
-supported. Configuration files are stored encrypted. You can now use
-ForkDaemon mode, which gives better stability over normal daemon mode, but
-doesn't require inetd. Also, server owners can now use the /OPER command to
-spy on their users. And--as I was specifically asked to mention--this is the
-first stable release that supports plugins. That's some Bitl changes for ya.
-
-BitlBee is cool, but ready when it's ready. Very Bitl.
-
-Sjoerd. LOL.
-
-(LOLBee by Erik Bosman.)
diff --git a/doc/bitlbee.8 b/doc/bitlbee.8
index ae1cfb05..9e634844 100644
--- a/doc/bitlbee.8
+++ b/doc/bitlbee.8
@@ -43,13 +43,8 @@ protocol plugins. BitlBee currently supports Oscar (aim and icq),
MSN, Jabber and Yahoo.
\fBbitlbee\fP should be called by
-.BR inetd (8).
-(Or \fBbitlbeed\fP,
-if you can't run and/or configure \fBinetd\fP.) There is an experimental
-daemon mode too, in which BitlBee will serve all clients in one process
-(and does not require inetd), but this mode is still experimental.
-There are still some bugs left in BitlBee, and if they cause a crash,
-that would terminate the BitlBee connection for all clients.
+.BR inetd (8),
+or you can run it as a stand-alone daemon.
.PP
.SH OPTIONS
.PP
@@ -61,10 +56,9 @@ option.
.IP "-D"
Run in daemon mode. In this mode, BitlBee forks to the background and
waits for new connections. All clients will be served from one process.
-This is still experimental. See the note above for more information.
.IP "-F"
Run in ForkDaemon mode. This is similar to ordinary daemon mode, but every
-client gets its own process. Easier to set up than inetd mode, but without
+client gets its own process. Easier to set up than inetd mode, and without
the possible stability issues.
.IP "-i \fIaddress\fP"
Only useful when running in daemon mode, to specify the network interface
diff --git a/doc/user-guide/commands.xml b/doc/user-guide/commands.xml
index c45727b9..6d77f8cd 100644
--- a/doc/user-guide/commands.xml
+++ b/doc/user-guide/commands.xml
@@ -588,6 +588,16 @@
</description>
</bitlbee-setting>
+ <bitlbee-setting name="root_nick" type="string" scope="global">
+ <default>root</default>
+
+ <description>
+ <para>
+ Normally the "bot" that takes all your BitlBee commands is called "root". If you don't like this name, you can rename it to anything else using the <emphasis>rename</emphasis> command, or by changing this setting.
+ </para>
+ </description>
+ </bitlbee-setting>
+
<bitlbee-setting name="save_on_quit" type="boolean" scope="global">
<default>true</default>
diff --git a/irc.c b/irc.c
index 3589256e..a6220140 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 );
@@ -118,6 +150,7 @@ irc_t *irc_new( int fd )
set_add( &irc->set, "password", NULL, passchange, irc );
set_add( &irc->set, "private", "true", set_eval_bool, irc );
set_add( &irc->set, "query_order", "lifo", NULL, irc );
+ set_add( &irc->set, "root_nick", irc->mynick, set_eval_root_nick, 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 );
@@ -126,6 +159,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 );
}
@@ -163,12 +199,14 @@ void irc_abort( irc_t *irc, int immed, char *format, ... )
irc->status |= USTATUS_SHUTDOWN;
if( irc->sendbuffer && !immed )
{
- /* We won't read from this socket anymore. Instead, we'll connect a timer
- to it that should shut down the connection in a second, just in case
- bitlbee_.._write doesn't do it first. */
+ /* Set up a timeout event that should shut down the connection
+ in a second, just in case ..._write doesn't do it first. */
b_event_remove( irc->r_watch_source_id );
- irc->r_watch_source_id = b_timeout_add( 1000, (b_event_handler) irc_free, irc );
+ irc->r_watch_source_id = 0;
+
+ b_event_remove( irc->ping_source_id );
+ irc->ping_source_id = b_timeout_add( 1000, (b_event_handler) irc_free, irc );
}
else
{
@@ -184,9 +222,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 );
@@ -195,76 +232,86 @@ 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 );
+ if( irc->r_watch_source_id > 0 )
+ 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 );
+
+ 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_hash_table_foreach_remove(irc->watches, irc_free_hashkey, NULL);
- g_hash_table_destroy(irc->watches);
+ g_free( irc->myhost );
+ g_free( irc->mynick );
- g_free(irc);
+ g_free( irc->channel );
+
+ g_free( irc->last_target );
+
+ g_free( irc );
if( global.conf->runmode == RUNMODE_INETD || global.conf->runmode == RUNMODE_FORKDAEMON )
b_main_quit();
@@ -285,7 +332,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,11 +341,10 @@ void irc_process( irc_t *irc )
for( i = 0; *lines[i] != '\0'; i ++ )
{
- char conv[IRC_MAX_LINE+1];
+ char *conv = NULL;
- /* [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] );
@@ -308,10 +354,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: */
@@ -323,15 +373,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 = '?';
@@ -340,11 +393,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 ) )
@@ -368,42 +425,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';
+
+ lines[++j] = buffer + i;
- 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;
+ 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. */
@@ -537,32 +593,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 )
{
@@ -735,12 +794,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 )
diff --git a/irc.h b/irc.h
index eb70ad1c..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;
@@ -68,7 +69,9 @@ typedef struct irc
char *user;
char *host;
char *realname;
- char *password;
+ char *password; /* HACK: Used to save the user's password, but before
+ logging in, this may contain a password we should
+ send to identify after USER/NICK are received. */
char umode[8];
diff --git a/irc_commands.c b/irc_commands.c
index b8bae541..6a47007a 100644
--- a/irc_commands.c
+++ b/irc_commands.c
@@ -29,7 +29,19 @@
static void irc_cmd_pass( irc_t *irc, char **cmd )
{
- if( global.conf->auth_pass &&
+ if( irc->status & USTATUS_LOGGED_IN )
+ {
+ char *send_cmd[] = { "identify", cmd[1], NULL };
+
+ /* We're already logged in, this client seems to send the PASS
+ command last. (Possibly it won't send it at all if it turns
+ out we don't require it, which will break this feature.)
+ Try to identify using the given password. */
+ return root_command( irc, send_cmd );
+ }
+ /* Handling in pre-logged-in state, first see if this server is
+ password-protected: */
+ else if( global.conf->auth_pass &&
( strncmp( global.conf->auth_pass, "md5:", 4 ) == 0 ?
md5_verify_password( cmd[1], global.conf->auth_pass + 4 ) == 0 :
strcmp( cmd[1], global.conf->auth_pass ) == 0 ) )
@@ -37,10 +49,16 @@ static void irc_cmd_pass( irc_t *irc, char **cmd )
irc->status |= USTATUS_AUTHORIZED;
irc_check_login( irc );
}
- else
+ else if( global.conf->auth_pass )
{
irc_reply( irc, 464, ":Incorrect password" );
}
+ else
+ {
+ /* Remember the password and try to identify after USER/NICK. */
+ irc_setpass( irc, cmd[1] );
+ irc_check_login( irc );
+ }
}
static void irc_cmd_user( irc_t *irc, char **cmd )
@@ -259,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] );
}
}
@@ -580,7 +597,7 @@ static void irc_cmd_rehash( irc_t *irc, char **cmd )
}
static const command_t irc_commands[] = {
- { "pass", 1, irc_cmd_pass, IRC_CMD_PRE_LOGIN },
+ { "pass", 1, irc_cmd_pass, 0 },
{ "user", 4, irc_cmd_user, IRC_CMD_PRE_LOGIN },
{ "nick", 1, irc_cmd_nick, 0 },
{ "quit", 0, irc_cmd_quit, 0 },
diff --git a/lib/arc.h b/lib/arc.h
index 58f30d3d..816fa612 100644
--- a/lib/arc.h
+++ b/lib/arc.h
@@ -30,6 +30,10 @@ struct arc_state
unsigned char i, j;
};
+#ifndef G_GNUC_MALLOC
+#define G_GNUC_MALLOC
+#endif
+
G_GNUC_MALLOC 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 pad_to );
diff --git a/lib/proxy.c b/lib/proxy.c
index 53b89d64..91493557 100644
--- a/lib/proxy.c
+++ b/lib/proxy.c
@@ -113,6 +113,7 @@ static gboolean gaim_io_connected(gpointer data, gint source, b_input_condition
static int proxy_connect_none(const char *host, unsigned short port, struct PHB *phb)
{
struct sockaddr_in *sin;
+ struct sockaddr_in me;
int fd = -1;
if (!(sin = gaim_gethostbyname(host, port))) {
@@ -127,6 +128,16 @@ static int proxy_connect_none(const char *host, unsigned short port, struct PHB
sock_make_nonblocking(fd);
+ if( global.conf->iface_out )
+ {
+ me.sin_family = AF_INET;
+ me.sin_port = 0;
+ me.sin_addr.s_addr = inet_addr( global.conf->iface_out );
+
+ if( bind( fd, (struct sockaddr *) &me, sizeof( me ) ) != 0 )
+ event_debug( "bind( %d, \"%s\" ) failure\n", fd, global.conf->iface_out );
+ }
+
event_debug("proxy_connect_none( \"%s\", %d ) = %d\n", host, port, fd);
if (connect(fd, (struct sockaddr *)sin, sizeof(*sin)) < 0 && !sockerr_again()) {
diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c
index 0e23b4d4..52a87d5d 100644
--- a/protocols/jabber/jabber.c
+++ b/protocols/jabber/jabber.c
@@ -36,11 +36,30 @@
GSList *jabber_connections;
+/* First enty is the default */
+static const int jabber_port_list[] = {
+ 5222,
+ 5223,
+ 5220,
+ 5221,
+ 5224,
+ 5225,
+ 5226,
+ 5227,
+ 5228,
+ 5229,
+ 80,
+ 443,
+ 0
+};
+
static void jabber_init( account_t *acc )
{
set_t *s;
+ char str[16];
- s = set_add( &acc->set, "port", JABBER_PORT_DEFAULT, set_eval_int, acc );
+ g_snprintf( str, sizeof( str ), "%d", jabber_port_list[0] );
+ s = set_add( &acc->set, "port", str, set_eval_int, acc );
s->flags |= ACC_SET_OFFLINE_ONLY;
s = set_add( &acc->set, "priority", "0", set_eval_priority, acc );
@@ -71,6 +90,7 @@ static void jabber_login( account_t *acc )
struct jabber_data *jd = g_new0( struct jabber_data, 1 );
struct ns_srv_reply *srv = NULL;
char *connect_to, *s;
+ int i;
/* For now this is needed in the _connected() handlers if using
GLib event handling, to make sure we're not handling events
@@ -176,11 +196,13 @@ static void jabber_login( account_t *acc )
imcb_log( ic, "Connecting" );
- if( set_getint( &acc->set, "port" ) < JABBER_PORT_MIN ||
- set_getint( &acc->set, "port" ) > JABBER_PORT_MAX )
+ for( i = 0; jabber_port_list[i] > 0; i ++ )
+ if( set_getint( &acc->set, "port" ) == jabber_port_list[i] )
+ break;
+
+ if( jabber_port_list[i] == 0 )
{
- imcb_log( ic, "Incorrect port number, must be in the %d-%d range",
- JABBER_PORT_MIN, JABBER_PORT_MAX );
+ imcb_log( ic, "Illegal port number" );
imc_logout( ic, FALSE );
return;
}
diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h
index 1ff0e8dd..023cf0f9 100644
--- a/protocols/jabber/jabber.h
+++ b/protocols/jabber/jabber.h
@@ -134,10 +134,6 @@ struct jabber_chat
#define JABBER_XMLCONSOLE_HANDLE "xmlconsole"
-#define JABBER_PORT_DEFAULT "5222"
-#define JABBER_PORT_MIN 5220
-#define JABBER_PORT_MAX 5229
-
/* Prefixes to use for packet IDs (mainly for IQ packets ATM). Usually the
first one should be used, but when storing a packet in the cache, a
"special" kind of ID is assigned to make it easier later to figure out
diff --git a/protocols/jabber/jabber_util.c b/protocols/jabber/jabber_util.c
index 6e872040..518624f6 100644
--- a/protocols/jabber/jabber_util.c
+++ b/protocols/jabber/jabber_util.c
@@ -245,8 +245,10 @@ struct jabber_buddy_ask_data
char *realname;
};
-static void jabber_buddy_ask_yes( gpointer w, struct jabber_buddy_ask_data *bla )
+static void jabber_buddy_ask_yes( void *data )
{
+ struct jabber_buddy_ask_data *bla = data;
+
presence_send_request( bla->ic, bla->handle, "subscribed" );
if( imcb_find_buddy( bla->ic, bla->handle ) == NULL )
@@ -256,8 +258,10 @@ static void jabber_buddy_ask_yes( gpointer w, struct jabber_buddy_ask_data *bla
g_free( bla );
}
-static void jabber_buddy_ask_no( gpointer w, struct jabber_buddy_ask_data *bla )
+static void jabber_buddy_ask_no( void *data )
{
+ struct jabber_buddy_ask_data *bla = data;
+
presence_send_request( bla->ic, bla->handle, "subscribed" );
g_free( bla->handle );
diff --git a/protocols/jabber/message.c b/protocols/jabber/message.c
index fab62a91..6cb67d42 100644
--- a/protocols/jabber/message.c
+++ b/protocols/jabber/message.c
@@ -48,6 +48,23 @@ xt_status jabber_pkt_message( struct xt_node *node, gpointer data )
else /* "chat", "normal", "headline", no-type or whatever. Should all be pretty similar. */
{
GString *fullmsg = g_string_new( "" );
+
+ for( c = node->children; ( c = xt_find_node( c, "x" ) ); c = c->next )
+ {
+ char *ns = xt_find_attr( c, "xmlns" ), *room;
+ struct xt_node *inv, *reason;
+
+ if( strcmp( ns, XMLNS_MUC_USER ) == 0 &&
+ ( inv = xt_find_node( c->children, "invite" ) ) )
+ {
+ room = from;
+ from = xt_find_attr( inv, "from" ) ? : from;
+
+ g_string_append_printf( fullmsg, "<< \002BitlBee\002 - Invitation to chatroom %s >>\n", room );
+ if( ( reason = xt_find_node( inv->children, "reason" ) ) && reason->text_len > 0 )
+ g_string_append( fullmsg, reason->text );
+ }
+ }
if( ( s = strchr( from, '/' ) ) )
{
diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h
index c8f4f4c6..63759303 100644
--- a/protocols/msn/msn.h
+++ b/protocols/msn/msn.h
@@ -28,7 +28,7 @@
#define TYPING_NOTIFICATION_MESSAGE "\r\r\rBEWARE, ME R TYPINK MESSAGE!!!!\r\r\r"
#define GROUPCHAT_SWITCHBOARD_MESSAGE "\r\r\rME WANT TALK TO MANY PEOPLE\r\r\r"
-#ifdef DEBUG
+#ifdef DEBUG_MSN
#define debug( text... ) imcb_log( ic, text );
#else
#define debug( text... )
diff --git a/protocols/msn/msn_util.c b/protocols/msn/msn_util.c
index fae2877d..58ad22f8 100644
--- a/protocols/msn/msn_util.c
+++ b/protocols/msn/msn_util.c
@@ -89,8 +89,10 @@ struct msn_buddy_ask_data
char *realname;
};
-static void msn_buddy_ask_yes( gpointer w, struct msn_buddy_ask_data *bla )
+static void msn_buddy_ask_yes( void *data )
{
+ struct msn_buddy_ask_data *bla = data;
+
msn_buddy_list_add( bla->ic, "AL", bla->handle, bla->realname );
if( imcb_find_buddy( bla->ic, bla->handle ) == NULL )
@@ -101,8 +103,10 @@ static void msn_buddy_ask_yes( gpointer w, struct msn_buddy_ask_data *bla )
g_free( bla );
}
-static void msn_buddy_ask_no( gpointer w, struct msn_buddy_ask_data *bla )
+static void msn_buddy_ask_no( void *data )
{
+ struct msn_buddy_ask_data *bla = data;
+
msn_buddy_list_add( bla->ic, "BL", bla->handle, bla->realname );
g_free( bla->handle );
diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c
index ff7da6ed..ffaa90a7 100644
--- a/protocols/msn/ns.c
+++ b/protocols/msn/ns.c
@@ -177,7 +177,15 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )
}
debug( "Connecting to a new switchboard with key %s", cmd[5] );
- sb = msn_sb_create( ic, server, port, cmd[5], MSN_SB_NEW );
+
+ if( ( sb = msn_sb_create( ic, server, port, cmd[5], MSN_SB_NEW ) ) == NULL )
+ {
+ /* Although this isn't strictly fatal for the NS connection, it's
+ definitely something serious (we ran out of file descriptors?). */
+ imcb_error( ic, "Could not create new switchboard" );
+ imc_logout( ic, TRUE );
+ return( 0 );
+ }
if( md->msgq )
{
@@ -467,8 +475,18 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )
debug( "Got a call from %s (session %d). Key = %s", cmd[5], session, cmd[4] );
- sb = msn_sb_create( ic, server, port, cmd[4], session );
- sb->who = g_strdup( cmd[5] );
+ if( ( sb = msn_sb_create( ic, server, port, cmd[4], session ) ) == NULL )
+ {
+ /* Although this isn't strictly fatal for the NS connection, it's
+ definitely something serious (we ran out of file descriptors?). */
+ imcb_error( ic, "Could not create new switchboard" );
+ imc_logout( ic, TRUE );
+ return( 0 );
+ }
+ else
+ {
+ sb->who = g_strdup( cmd[5] );
+ }
}
else if( strcmp( cmd[0], "ADD" ) == 0 )
{
diff --git a/protocols/nogaim.c b/protocols/nogaim.c
index 3ce15166..7466e93a 100644
--- a/protocols/nogaim.c
+++ b/protocols/nogaim.c
@@ -342,7 +342,8 @@ void imc_logout( struct im_connection *ic, int allow_reconnect )
/* dialogs.c */
-void imcb_ask( struct im_connection *ic, char *msg, void *data, void *doit, void *dont )
+void imcb_ask( struct im_connection *ic, char *msg, void *data,
+ query_callback doit, query_callback dont )
{
query_add( ic->irc, ic, msg, doit, dont, data );
}
@@ -494,18 +495,20 @@ struct show_got_added_data
char *handle;
};
-void show_got_added_no( gpointer w, struct show_got_added_data *data )
+void show_got_added_no( void *data )
{
- g_free( data->handle );
+ g_free( ((struct show_got_added_data*)data)->handle );
g_free( data );
}
-void show_got_added_yes( gpointer w, struct show_got_added_data *data )
+void show_got_added_yes( void *data )
{
- data->ic->acc->prpl->add_buddy( data->ic, data->handle, NULL );
- /* imcb_add_buddy( data->ic, NULL, data->handle, data->handle ); */
+ struct show_got_added_data *sga = data;
- return show_got_added_no( w, data );
+ sga->ic->acc->prpl->add_buddy( sga->ic, sga->handle, NULL );
+ /* imcb_add_buddy( sga->ic, NULL, sga->handle, sga->handle ); */
+
+ return show_got_added_no( data );
}
void imcb_ask_add( struct im_connection *ic, char *handle, const char *realname )
diff --git a/protocols/nogaim.h b/protocols/nogaim.h
index 7d391edd..bdd8bae2 100644
--- a/protocols/nogaim.h
+++ b/protocols/nogaim.h
@@ -41,6 +41,7 @@
#include "bitlbee.h"
#include "account.h"
#include "proxy.h"
+#include "query.h"
#include "md5.h"
#define BUF_LEN MSG_LEN
@@ -260,7 +261,7 @@ G_MODULE_EXPORT void imcb_error( struct im_connection *ic, char *format, ... ) G
* - '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( struct im_connection *ic, char *msg, void *data, query_callback doit, query_callback dont );
G_MODULE_EXPORT void imcb_ask_add( struct im_connection *ic, char *handle, const char *realname );
/* Buddy management */
diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c
index 9e5de70a..7738c31f 100644
--- a/protocols/oscar/oscar.c
+++ b/protocols/oscar/oscar.c
@@ -1083,8 +1083,8 @@ static int incomingim_chan1(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_
return 1;
}
-void oscar_accept_chat(gpointer w, struct aim_chat_invitation * inv);
-void oscar_reject_chat(gpointer w, struct aim_chat_invitation * inv);
+void oscar_accept_chat(void *data);
+void oscar_reject_chat(void *data);
static int incomingim_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args) {
struct im_connection *ic = sess->aux_data;
@@ -1118,7 +1118,8 @@ static int incomingim_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_
return 1;
}
-static void gaim_icq_authgrant(gpointer w, struct icq_auth *data) {
+static void gaim_icq_authgrant(void *data_) {
+ struct icq_auth *data = data_;
char *uin, message;
struct oscar_data *od = (struct oscar_data *)data->ic->proto_data;
@@ -1133,7 +1134,8 @@ static void gaim_icq_authgrant(gpointer w, struct icq_auth *data) {
g_free(data);
}
-static void gaim_icq_authdeny(gpointer w, struct icq_auth *data) {
+static void gaim_icq_authdeny(void *data_) {
+ struct icq_auth *data = data_;
char *uin, *message;
struct oscar_data *od = (struct oscar_data *)data->ic->proto_data;
@@ -2587,15 +2589,19 @@ struct groupchat *oscar_chat_with(struct im_connection * ic, char *who)
return NULL;
}
-void oscar_accept_chat(gpointer w, struct aim_chat_invitation * inv)
+void oscar_accept_chat(void *data)
{
+ struct aim_chat_invitation * inv = data;
+
oscar_chat_join(inv->ic, inv->name, NULL, NULL);
g_free(inv->name);
g_free(inv);
}
-void oscar_reject_chat(gpointer w, struct aim_chat_invitation * inv)
+void oscar_reject_chat(void *data)
{
+ struct aim_chat_invitation * inv = data;
+
g_free(inv->name);
g_free(inv);
}
diff --git a/protocols/yahoo/libyahoo2.c b/protocols/yahoo/libyahoo2.c
index 80d88a85..897ba27b 100644
--- a/protocols/yahoo/libyahoo2.c
+++ b/protocols/yahoo/libyahoo2.c
@@ -380,7 +380,6 @@ static void del_from_list(struct yahoo_data *yd)
}
/* call repeatedly to get the next one */
-/*
static struct yahoo_input_data * find_input_by_id(int id)
{
YList *l;
@@ -391,7 +390,6 @@ static struct yahoo_input_data * find_input_by_id(int id)
}
return NULL;
}
-*/
static struct yahoo_input_data * find_input_by_id_and_webcam_user(int id, const char * who)
{
@@ -796,6 +794,7 @@ static int yahoo_send_data(int fd, void *data, int len)
void yahoo_close(int id)
{
struct yahoo_data *yd = find_conn_by_id(id);
+
if(!yd)
return;
@@ -3165,7 +3164,7 @@ int yahoo_write_ready(int id, int fd, void *data)
struct data_queue *tx;
LOG(("write callback: id=%d fd=%d data=%p", id, fd, data));
- if(!yid || !yid->txqueues)
+ if(!yid || !yid->txqueues || !find_conn_by_id(id))
return -2;
tx = yid->txqueues->data;
@@ -3841,11 +3840,9 @@ void yahoo_logoff(int id)
}
}
-
-/* do {
+ do {
yahoo_input_close(yid);
- } while((yid = find_input_by_id(id)));*/
-
+ } while((yid = find_input_by_id(id)));
}
void yahoo_get_list(int id)
diff --git a/protocols/yahoo/yahoo.c b/protocols/yahoo/yahoo.c
index 36579d66..c84685e9 100644
--- a/protocols/yahoo/yahoo.c
+++ b/protocols/yahoo/yahoo.c
@@ -453,10 +453,6 @@ gboolean byahoo_write_ready_callback( gpointer data, gint source, b_input_condit
{
struct byahoo_write_ready_data *d = data;
- if( !byahoo_get_ic_by_id( d->id ) )
- /* WTF doesn't libyahoo clean this up? */
- return FALSE;
-
yahoo_write_ready( d->id, d->fd, d->data );
return FALSE;
@@ -796,16 +792,20 @@ int ext_yahoo_connect(const char *host, int port)
return -1;
}
-static void byahoo_accept_conf( gpointer w, struct byahoo_conf_invitation *inv )
+static void byahoo_accept_conf( void *data )
{
+ struct byahoo_conf_invitation *inv = data;
+
yahoo_conference_logon( inv->yid, NULL, inv->members, inv->name );
imcb_chat_add_buddy( inv->c, inv->ic->acc->user );
g_free( inv->name );
g_free( inv );
}
-static void byahoo_reject_conf( gpointer w, struct byahoo_conf_invitation *inv )
+static void byahoo_reject_conf( void *data )
{
+ struct byahoo_conf_invitation *inv = data;
+
yahoo_conference_decline( inv->yid, NULL, inv->members, inv->name, "User rejected groupchat" );
imcb_chat_free( inv->c );
g_free( inv->name );
diff --git a/query.c b/query.c
index 6f9eb77f..e8f69572 100644
--- a/query.c
+++ b/query.c
@@ -29,7 +29,8 @@
static void query_display( irc_t *irc, query_t *q );
static query_t *query_default( irc_t *irc );
-query_t *query_add( irc_t *irc, struct im_connection *ic, char *question, void *yes, void *no, void *data )
+query_t *query_add( irc_t *irc, struct im_connection *ic, char *question,
+ query_callback yes, query_callback no, void *data )
{
query_t *q = g_new0( query_t, 1 );
@@ -143,7 +144,7 @@ void query_answer( irc_t *irc, query_t *q, int ans )
imcb_log( q->ic, "Accepted: %s", q->question );
else
irc_usermsg( irc, "Accepted: %s", q->question );
- q->yes( NULL, q->data );
+ q->yes( q->data );
}
else
{
@@ -151,7 +152,7 @@ void query_answer( irc_t *irc, query_t *q, int ans )
imcb_log( q->ic, "Rejected: %s", q->question );
else
irc_usermsg( irc, "Rejected: %s", q->question );
- q->no( NULL, q->data );
+ q->no( q->data );
}
q->data = NULL;
diff --git a/query.h b/query.h
index b64642c2..e0ca32ec 100644
--- a/query.h
+++ b/query.h
@@ -26,17 +26,19 @@
#ifndef _QUERY_H
#define _QUERY_H
+typedef void (*query_callback) ( void *data );
+
typedef struct query
{
struct im_connection *ic;
char *question;
- void (* yes) ( gpointer w, void *data );
- void (* no) ( gpointer w, void *data );
+ query_callback yes, no;
void *data;
struct query *next;
} query_t;
-query_t *query_add( irc_t *irc, struct im_connection *ic, char *question, void *yes, void *no, void *data );
+query_t *query_add( irc_t *irc, struct im_connection *ic, char *question,
+ query_callback yes, query_callback no, void *data );
void query_del( irc_t *irc, query_t *q );
void query_del_by_conn( irc_t *irc, struct im_connection *ic );
void query_answer( irc_t *irc, query_t *q, int ans );
diff --git a/root_commands.c b/root_commands.c
index 9a60b5af..f55c4b5e 100644
--- a/root_commands.c
+++ b/root_commands.c
@@ -203,24 +203,38 @@ static void cmd_drop( irc_t *irc, char **cmd )
}
}
-void cmd_account_del_yes( gpointer w, void *data )
+struct cmd_account_del_data
{
- account_t *a = data;
- irc_t *irc = a->irc;
+ account_t *a;
+ irc_t *irc;
+};
+
+void cmd_account_del_yes( void *data )
+{
+ struct cmd_account_del_data *cad = data;
+ account_t *a;
+
+ for( a = cad->irc->accounts; a && a != cad->a; a = a->next );
- if( a->ic )
+ if( a == NULL )
{
- irc_usermsg( irc, "Account is still logged in, can't delete" );
+ irc_usermsg( cad->irc, "Account already deleted" );
+ }
+ else if( a->ic )
+ {
+ irc_usermsg( cad->irc, "Account is still logged in, can't delete" );
}
else
{
- account_del( irc, a );
- irc_usermsg( irc, "Account deleted" );
+ account_del( cad->irc, a );
+ irc_usermsg( cad->irc, "Account deleted" );
}
+ g_free( data );
}
-void cmd_account_del_no( gpointer w, void *data )
+void cmd_account_del_no( void *data )
{
+ g_free( data );
}
static void cmd_account( irc_t *irc, char **cmd )
@@ -277,14 +291,19 @@ static void cmd_account( irc_t *irc, char **cmd )
}
else
{
+ struct cmd_account_del_data *cad;
char *msg;
+ cad = g_malloc( sizeof( struct cmd_account_del_data ) );
+ cad->a = a;
+ cad->irc = irc;
+
msg = g_strdup_printf( "If you remove this account (%s(%s)), BitlBee will "
"also forget all your saved nicknames. If you want "
"to change your username/password, use the `account "
"set' command. Are you sure you want to delete this "
"account?", a->prpl->name, a->user );
- query_add( irc, NULL, msg, cmd_account_del_yes, cmd_account_del_no, a );
+ query_add( irc, NULL, msg, cmd_account_del_yes, cmd_account_del_no, cad );
g_free( msg );
}
}
@@ -403,6 +422,12 @@ static void cmd_account( irc_t *irc, char **cmd )
else
acc_handle = g_strdup( cmd[2] );
+ if( !acc_handle )
+ {
+ irc_usermsg( irc, "Not enough parameters given (need %d)", 3 );
+ return;
+ }
+
if( ( tmp = strchr( acc_handle, '/' ) ) )
{
*tmp = 0;
@@ -583,6 +608,9 @@ static void cmd_rename( irc_t *irc, char **cmd )
{
g_free( irc->mynick );
irc->mynick = g_strdup( cmd[2] );
+
+ if( strcmp( cmd[0], "set_rename" ) != 0 )
+ set_setstr( &irc->set, "root_nick", cmd[2] );
}
else if( u->send_handler == buddy_send_handler )
{
@@ -593,6 +621,20 @@ static void cmd_rename( irc_t *irc, char **cmd )
}
}
+char *set_eval_root_nick( set_t *set, char *new_nick )
+{
+ irc_t *irc = set->data;
+
+ if( strcmp( irc->mynick, new_nick ) != 0 )
+ {
+ char *cmd[] = { "set_rename", irc->mynick, new_nick, NULL };
+
+ cmd_rename( irc, cmd );
+ }
+
+ return strcmp( irc->mynick, new_nick ) == 0 ? new_nick : NULL;
+}
+
static void cmd_remove( irc_t *irc, char **cmd )
{
user_t *u;
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__ */
diff --git a/storage_xml.c b/storage_xml.c
index f37fce44..ab7da6e3 100644
--- a/storage_xml.c
+++ b/storage_xml.c
@@ -28,6 +28,7 @@
#include "base64.h"
#include "arc.h"
#include "md5.h"
+#include <glib/gstdio.h>
typedef enum
{
@@ -242,9 +243,9 @@ GMarkupParser xml_parser =
static void xml_init( void )
{
- if( access( global.conf->configdir, F_OK ) != 0 )
+ if( ! g_file_test( global.conf->configdir, G_FILE_TEST_EXISTS ) )
log_message( LOGLVL_WARNING, "The configuration directory `%s' does not exist. Configuration won't be saved.", global.conf->configdir );
- else if( access( global.conf->configdir, R_OK ) != 0 || access( global.conf->configdir, W_OK ) != 0 )
+ else if( ! g_file_test( global.conf->configdir, G_FILE_TEST_EXISTS ) || g_access( global.conf->configdir, W_OK ) != 0 )
log_message( LOGLVL_WARNING, "Permission problem: Can't read/write from/to `%s'.", global.conf->configdir );
}
@@ -371,7 +372,7 @@ static storage_status_t xml_save( irc_t *irc, int overwrite )
g_snprintf( path, sizeof( path ) - 2, "%s%s%s", global.conf->configdir, path2, ".xml" );
g_free( path2 );
- if( !overwrite && access( path, F_OK ) != -1 )
+ if( !overwrite && g_file_test( path, G_FILE_TEST_EXISTS ) )
return STORAGE_ALREADY_EXISTS;
strcat( path, "~" );
diff --git a/tests/check_irc.c b/tests/check_irc.c
index c1cf05a5..66fe0021 100644
--- a/tests/check_irc.c
+++ b/tests/check_irc.c
@@ -36,8 +36,8 @@ START_TEST(test_login)
irc = irc_new(g_io_channel_unix_get_fd(ch1));
- fail_unless(g_io_channel_write_chars(ch2, "NICK bla\r\n"
- "USER a a a a\r\n", -1, NULL, NULL) == G_IO_STATUS_NORMAL);
+ fail_unless(g_io_channel_write_chars(ch2, "NICK bla\r\r\n"
+ "USER a a a a\n", -1, NULL, NULL) == G_IO_STATUS_NORMAL);
fail_unless(g_io_channel_flush(ch2, NULL) == G_IO_STATUS_NORMAL);
g_main_iteration(FALSE);