diff options
39 files changed, 517 insertions, 328 deletions
@@ -16,3 +16,5 @@ tests/check *.gcov *.gcno *.o +coverage +bitlbee.info @@ -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 ); @@ -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. @@ -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 @@ -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 ) @@ -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; @@ -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 @@ -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> @@ -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 ) @@ -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 }, @@ -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 ); @@ -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; @@ -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; @@ -229,18 +229,3 @@ char *set_eval_ops( set_t *set, char *value ) return value; } - -char *set_eval_charset( set_t *set, char *value ) -{ - GIConv cd; - - if( g_strcasecmp( value, "none" ) == 0 ) - return value; - - cd = g_iconv_open( "UTF-8", value ); - if( cd == (GIConv) -1 ) - return NULL; - - g_iconv_close( cd ); - return value; -} @@ -96,6 +96,5 @@ char *set_eval_bool( set_t *set, char *value ); /* Some not very generic evaluators that really shouldn't be here... */ char *set_eval_to_char( set_t *set, char *value ); char *set_eval_ops( set_t *set, char *value ); -char *set_eval_charset( set_t *set, char *value ); #endif /* __SET_H__ */ 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); |