diff options
author | ulim <a.sporto+bee@gmail.com> | 2008-02-15 18:38:57 +0100 |
---|---|---|
committer | ulim <a.sporto+bee@gmail.com> | 2008-02-15 18:38:57 +0100 |
commit | 1ba7e8f1d28c4876ea0b787f1e4ebb5607f48895 (patch) | |
tree | 5ba8bed0e1ba83c56a855059e88e3d2a205fe88c | |
parent | 0fbd3a6d26d8fe747bd5e061748e75f397801064 (diff) | |
parent | eeb85a8a880fefe655eb31b6322136b61ee969e2 (diff) |
Merged with upstream r328
Wilmer van der Gaast 2008-02-11 Got rid of some noise at startup: complaining when the default configuration
Wilmer van der Gaast 2008-02-10 Added support for password-protected Jabber chatrooms.
Wilmer van der Gaast 2008-02-10 Making AI_ADDRCONFIG optional, it doesn't exist on at least NetBSD and
Wilmer van der Gaast 2008-02-09 Restored "add -tmp". A bit hackish, but it will do for now.
Wilmer van der Gaast 2008-02-07 Fixed getnameinfo() calls, this fixes Solaris stability issues. Thanks to
Wilmer van der Gaast 2008-02-04 Added bogus G_GNUC_MALLOC to restore GLib 2.4 compatibility (hopefully).
Wilmer van der Gaast 2008-02-03 Messages from the user are also included in backlogs when joining a Jabber
Wilmer van der Gaast 2008-02-03 Disabling "Unknown command" warnings since they're very noisy and pretty
Wilmer van der Gaast 2008-02-03 Implemented XEP-0115. This adds some info to the <presence/> tags so
Wilmer van der Gaast 2008-02-03 Saner garbage collection of cached packets in the Jabber module. Now
Wilmer van der Gaast 2008-02-02 Added help_free() and cleaned up some very stale help-related stuff I
Wilmer van der Gaast 2008-01-30 Fixed handling of OSCAR multi-part messages... They're not arrays, they're
Wilmer van der Gaast 2008-01-24 Keeping track of valid Jabber connections so _connected() events will be
Wilmer van der Gaast 2008-01-24 Fixed two valgrind warnings (partially uninitialized "struct tm" vars.)
Wilmer van der Gaast 2008-01-20 The Jabber module now uses imcb_chat_log() instead of imcb_log() where
Wilmer van der Gaast 2008-01-20 Added imcb_chat_log() for chatroom system messages, so they can be
Wilmer van der Gaast 2008-01-20 GET_BUDDY_FIRST wasn't actually implemented, even though it was in use
Wilmer van der Gaast 2008-01-19 Using test -f instead of test -e. This breaks if the include files are
Wilmer van der Gaast 2008-01-19 Added byte swapping code to the new MD5 checksumming code to make it work
Wilmer van der Gaast 2008-01-18 Moving imcb_chat_new() to a saner location (no code changes) and fixing
Wilmer van der Gaast 2008-01-17 Apparently ext_yahoo_got_im can be called with msg=NULL, so it should be
Wilmer van der Gaast 2008-01-17 Fixing some Solaris compiler warnings (u_int->uint, adding some typecasts
Wilmer van der Gaast 2008-01-13 Fixed handing of failed groupchat joins.
Wilmer van der Gaast 2008-01-13 Fixed "Conditional jump or move depends on uninitialised value(s)" at
Wilmer van der Gaast 2008-01-13 Fixed quickstart2. (Bug #349.)
Wilmer van der Gaast 2008-01-13 Different handling of charset mismatches before login time. Ignoring a
Wilmer van der Gaast 2008-01-12 When a switchboard connection dies (at the TCP level) and there are still
Wilmer van der Gaast 2008-01-12 Killed info_string_append() and now showing the IP address of ICQ users
Wilmer van der Gaast 2008-01-11 Fixing bug #344, now away states should always be correct, even when people
Wilmer van der Gaast 2008-01-11 Adding own handle to protocol name in blist output for people with multiple
Wilmer van der Gaast 2008-01-10 Now setting odata->icq properly again, this got lost some time ago, which
Wilmer van der Gaast 2008-01-06 More consistency in error/warning errors. Until now "WARNING:" was usually
Wilmer van der Gaast 2008-01-06 Changed warning message about unsent MSN messages. It should show the actual
Wilmer van der Gaast 2008-01-05 Added "mail_notifications" setting. Who needs those notifications anyway?
Wilmer van der Gaast 2008-01-05 Build fix from vmiklos.
Wilmer van der Gaast 2008-01-05 Added handling of MSN switchboard NAK messages. Untested, but hey, it
Wilmer van der Gaast 2008-01-05 Removed closure->result. I was planning to add some more stuff, but will
Miklos Vajna 2007-12-31 encode: md5.c is no longer in protocols/, it's in lib/
Wilmer van der Gaast 2007-12-28 Fixed return value check in proxy_connect(), since on some systems
Wilmer van der Gaast 2007-12-28 Added missing return in jabber_login().
Wilmer van der Gaast 2007-12-16 Implemented XEP-0199 (patch from misc@mandriva.org).
Wilmer van der Gaast 2007-12-12 Checking conn->xcred before trying to clean it up since GnuTLS doesn't
Wilmer van der Gaast 2007-12-12 Killed the <server> parameter to "account add" and changed the default
Wilmer van der Gaast 2007-12-12 Fixed sockerr_again() usage in Jabber module to (hopefully) fix a 100% CPU
Wilmer van der Gaast 2007-12-10 Don't allow nicks that start with a number.
Wilmer van der Gaast 2007-12-10 Fixed "set xxx" syntax (it showed all settings instead of just xxx).
Wilmer van der Gaast 2007-12-09 If I keep forgetting to credit people in commit msgs I should probably add
Wilmer van der Gaast 2007-12-09 Added /invite support for Jabber chatrooms (and fixed the argument order
43 files changed, 744 insertions, 454 deletions
@@ -115,7 +115,7 @@ ifndef DEBUG endif encode: crypting.c - $(CC) crypting.c protocols/md5.c $(CFLAGS) -o encode -DCRYPTING_MAIN $(CFLAGS) $(EFLAGS) $(LFLAGS) + $(CC) crypting.c lib/md5.c $(CFLAGS) -o encode -DCRYPTING_MAIN $(CFLAGS) $(EFLAGS) $(LFLAGS) decode: encode cp encode decode @@ -47,7 +47,11 @@ int bitlbee_daemon_init() memset( &hints, 0, sizeof( hints ) ); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE; + hints.ai_flags = AI_PASSIVE +#ifdef AI_ADDRCONFIG + | AI_ADDRCONFIG +#endif + ; i = getaddrinfo( global.conf->iface, global.conf->port, &hints, &addrinfo_bind ); if( i ) @@ -278,7 +282,7 @@ static gboolean bitlbee_io_new_client( gpointer data, gint fd, b_input_condition child->ipc_inpa = b_input_add( child->ipc_fd, GAIM_INPUT_READ, ipc_master_read, child ); child_list = g_slist_append( child_list, child ); - log_message( LOGLVL_INFO, "Creating new subprocess with pid %d.", client_pid ); + log_message( LOGLVL_INFO, "Creating new subprocess with pid %d.", (int) client_pid ); /* Close some things we don't need in the parent process. */ close( new_socket ); @@ -98,6 +98,12 @@ #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. */ +#define G_GNUC_MALLOC +#endif + #define _( x ) x #define ROOT_NICK "root" @@ -115,8 +121,6 @@ #define HELP_FILE VARDIR "help.txt" #define CONF_FILE_DEF ETCDIR "bitlbee.conf" -extern char *CONF_FILE; - #include "irc.h" #include "storage.h" #include "set.h" @@ -138,6 +142,7 @@ typedef struct global { int listen_socket; gint listen_watch_source_id; help_t *help; + char *conf_file; conf_t *conf; GList *storage; /* The first backend in the list will be used for saving */ char *helpfile; @@ -35,14 +35,12 @@ #include "proxy.h" -char *CONF_FILE; - static int conf_loadini( conf_t *conf, char *file ); conf_t *conf_load( int argc, char *argv[] ) { conf_t *conf; - int opt, i; + int opt, i, config_missing = 0; conf = g_new0( conf_t, 1 ); @@ -66,15 +64,17 @@ conf_t *conf_load( int argc, char *argv[] ) conf->max_filetransfer_size = G_MAXUINT; proxytype = 0; - i = conf_loadini( conf, CONF_FILE ); + i = conf_loadini( conf, global.conf_file ); if( i == 0 ) { - fprintf( stderr, "Error: Syntax error in configuration file `%s'.\n", CONF_FILE ); - return( NULL ); + fprintf( stderr, "Error: Syntax error in configuration file `%s'.\n", global.conf_file ); + return NULL; } else if( i == -1 ) { - fprintf( stderr, "Warning: Unable to read configuration file `%s'.\n", CONF_FILE ); + config_missing ++; + /* Whine after parsing the options if there was no -c pointing + at a *valid* configuration file. */ } while( argc > 0 && ( opt = getopt( argc, argv, "i:p:P:nvIDFc:d:hR:u:" ) ) >= 0 ) @@ -106,16 +106,16 @@ conf_t *conf_load( int argc, char *argv[] ) conf->runmode = RUNMODE_FORKDAEMON; else if( opt == 'c' ) { - if( strcmp( CONF_FILE, optarg ) != 0 ) + if( strcmp( global.conf_file, optarg ) != 0 ) { - g_free( CONF_FILE ); - CONF_FILE = g_strdup( optarg ); + g_free( global.conf_file ); + global.conf_file = g_strdup( optarg ); g_free( conf ); /* Re-evaluate arguments. Don't use this option twice, you'll end up in an infinite loop! Hope this trick works with all libcs BTW.. */ optind = 1; - return( conf_load( argc, argv ) ); + return conf_load( argc, argv ); } } else if( opt == 'd' ) @@ -143,7 +143,7 @@ conf_t *conf_load( int argc, char *argv[] ) " -c Load alternative configuration file\n" " -d Specify alternative user configuration directory\n" " -h Show this help page.\n" ); - return( NULL ); + return NULL; } else if( opt == 'R' ) { @@ -169,7 +169,10 @@ conf_t *conf_load( int argc, char *argv[] ) conf->configdir = s; } - return( conf ); + if( config_missing ) + fprintf( stderr, "Warning: Unable to read configuration file `%s'.\n", global.conf_file ); + + return conf; } static int conf_loadini( conf_t *conf, char *file ) @@ -178,7 +181,7 @@ static int conf_loadini( conf_t *conf, char *file ) int i; ini = ini_open( file ); - if( ini == NULL ) return( -1 ); + if( ini == NULL ) return -1; while( ini_read( ini ) ) { if( g_strcasecmp( ini->section, "settings" ) == 0 ) @@ -256,7 +259,7 @@ static int conf_loadini( conf_t *conf, char *file ) if( sscanf( ini->value, "%d", &i ) != 1 ) { fprintf( stderr, "Invalid %s value: %s\n", ini->key, ini->value ); - return( 0 ); + return 0; } conf->ping_interval = i; } @@ -265,7 +268,7 @@ static int conf_loadini( conf_t *conf, char *file ) if( sscanf( ini->value, "%d", &i ) != 1 ) { fprintf( stderr, "Invalid %s value: %s\n", ini->key, ini->value ); - return( 0 ); + return 0; } conf->ping_timeout = i; } @@ -277,7 +280,7 @@ static int conf_loadini( conf_t *conf, char *file ) { fprintf( stderr, "Invalid %s value: %s\n", ini->key, ini->value ); g_free( url ); - return( 0 ); + return 0; } strncpy( proxyhost, url->host, sizeof( proxyhost ) ); @@ -301,7 +304,7 @@ static int conf_loadini( conf_t *conf, char *file ) else { fprintf( stderr, "Error: Unknown setting `%s` in configuration file.\n", ini->key ); - return( 0 ); + return 0; /* For now just ignore unknown keys... */ } } @@ -309,19 +312,19 @@ static int conf_loadini( conf_t *conf, char *file ) { fprintf( stderr, "Error: Unknown section [%s] in configuration file. " "BitlBee configuration must be put in a [settings] section!\n", ini->section ); - return( 0 ); + return 0; } } ini_close( ini ); - return( 1 ); + return 1; } void conf_loaddefaults( irc_t *irc ) { ini_t *ini; - ini = ini_open( CONF_FILE ); + ini = ini_open( global.conf_file ); if( ini == NULL ) return; while( ini_read( ini ) ) { @@ -188,7 +188,7 @@ else fi if [ "$events" = "libevent" ]; then - if ! [ -e "${libevent}include/event.h" ]; then + if ! [ -f "${libevent}include/event.h" ]; then echo echo 'Warning: Could not find event.h, you might have to install it and/or specify' echo 'its location using the --libevent= argument. (Example: If event.h is in' @@ -323,7 +323,7 @@ fi; echo 'SSL_CLIENT=ssl_'$ssl'.o' >> Makefile.settings for i in /lib /usr/lib /usr/local/lib; do - if [ -e $i/libresolv.a ]; then + if [ -f $i/libresolv.a ]; then echo '#define HAVE_RESOLV_A' >> config.h echo 'EFLAGS+='$i'/libresolv.a' >> Makefile.settings break @@ -453,7 +453,7 @@ else fi if [ "$protocols" = "PROTOCOLS = " ]; then - echo "WARNING: You haven't selected any communication protocol to compile!" + echo "Warning: You haven't selected any communication protocol to compile!" echo " BitlBee will run, but you will be unable to connect to IM servers!" fi @@ -28,10 +28,7 @@ included if CRYPTING_MAIN is defined. Or just do "make decode" and the programs will be built. */ -#include <string.h> -#include <stdio.h> -#include <stdlib.h> -#include <glib.h> +#include <bitlbee.h> #include "md5.h" #include "crypting.h" diff --git a/doc/user-guide/commands.xml b/doc/user-guide/commands.xml index 090acff3..0832e3d2 100644 --- a/doc/user-guide/commands.xml +++ b/doc/user-guide/commands.xml @@ -474,6 +474,17 @@ </bitlbee-setting> + <bitlbee-setting name="mail_notifications" type="boolean" scope="account"> + <default>false</default> + + <description> + <para> + Some protocols (MSN, Yahoo!) can notify via IM about new e-mail. Since most people use their Hotmail/Yahoo! addresses as a spam-box, this is disabled default. If you want these notifications, you can enable this setting. + </para> + </description> + + </bitlbee-setting> + <bitlbee-setting name="ops" type="string" scope="global"> <default>both</default> <possible-values>both, root, user, none</possible-values> diff --git a/doc/user-guide/quickstart.xml b/doc/user-guide/quickstart.xml index fcb06c6b..7735a8d7 100644 --- a/doc/user-guide/quickstart.xml +++ b/doc/user-guide/quickstart.xml @@ -33,7 +33,7 @@ To add an account to the account list you will need to use the <emphasis>account </para> <para> -For instance, suppose you have an ICQ account with UIN <emphasis>72696705</emphasis> with password <emphasis>QuickStart</emphasis>, you would: +For instance, suppose you have a Jabber account at jabber.org with handle <emphasis>bitlbee@jabber.org</emphasis> with password <emphasis>QuickStart</emphasis>, you would: </para> <ircexample> @@ -42,7 +42,7 @@ For instance, suppose you have an ICQ account with UIN <emphasis>72696705</empha </ircexample> <para> -Other available IM protocols are msn, oscar, and yahoo. Oscar is the protocol used by ICQ and AOL. +Other available IM protocols are msn, oscar, and yahoo. OSCAR is the protocol used by ICQ and AOL. For more information about the <emphasis>account add</emphasis> command, see <emphasis>help account add</emphasis>. </para> <para> @@ -70,21 +70,20 @@ help_t *help_init( help_t **help, const char *helpfile ) if( !( t = strstr( s, "\n%\n" ) ) || s[0] != '?' ) { /* FIXME: Clean up */ -// help_close( *help ); - *help = NULL; + help_free( help ); g_free( s ); - return( NULL ); + return NULL; } i = strchr( s, '\n' ) - s; - if( h->string ) + if( h->title ) { h = h->next = g_new0( help_t, 1 ); } - h->string = g_new ( char, i ); + h->title = g_new ( char, i ); - strncpy( h->string, s + 1, i - 1 ); - h->string[i-1] = 0; + strncpy( h->title, s + 1, i - 1 ); + h->title[i-1] = 0; h->fd = (*help)->fd; h->offset.file_offset = lseek( h->fd, 0, SEEK_CUR ) - buflen + i + 1; h->length = t - s - i - 1; @@ -102,7 +101,31 @@ help_t *help_init( help_t **help, const char *helpfile ) return( *help ); } -char *help_get( help_t **help, char *string ) +void help_free( help_t **help ) +{ + help_t *h, *oh; + int last_fd = -1; /* Weak de-dupe */ + + if( help == NULL || *help == NULL ) + return; + + h = *help; + while( h ) + { + if( h->fd != last_fd ) + { + close( h->fd ); + last_fd = h->fd; + } + g_free( h->title ); + h = (oh=h)->next; + g_free( oh ); + } + + *help = NULL; +} + +char *help_get( help_t **help, char *title ) { time_t mtime; struct stat stat[1]; @@ -110,28 +133,29 @@ char *help_get( help_t **help, char *string ) for( h = *help; h; h = h->next ) { - if( h->string != NULL && - g_strcasecmp( h->string, string ) == 0 ) + if( h->title != NULL && g_strcasecmp( h->title, title ) == 0 ) break; } if( h && h->length > 0 ) { char *s = g_new( char, h->length + 1 ); - if( fstat( h->fd, stat ) != 0 ) - { - g_free( h ); - *help = NULL; - return NULL; - } - mtime = stat->st_mtime; - - if( mtime > h->mtime ) - return NULL; - s[h->length] = 0; if( h->fd >= 0 ) { + if( fstat( h->fd, stat ) != 0 ) + { + g_free( s ); + return NULL; + } + mtime = stat->st_mtime; + + if( mtime > h->mtime ) + { + g_free( s ); + return NULL; + } + lseek( h->fd, h->offset.file_offset, SEEK_SET ); read( h->fd, s, h->length ); } @@ -36,13 +36,14 @@ typedef struct help { int fd; time_t mtime; - char *string; + char *title; help_off_t offset; int length; struct help *next; } help_t; G_GNUC_MALLOC help_t *help_init( help_t **help, const char *helpfile ); -char *help_get( help_t **help, char *string ); +void help_free( help_t **help ); +char *help_get( help_t **help, char *title ); #endif @@ -51,7 +51,7 @@ static void ipc_master_cmd_client( irc_t *data, char **cmd ) if( g_strcasecmp( cmd[0], "CLIENT" ) == 0 ) ipc_to_children_str( "OPERMSG :Client connecting (PID=%d): %s@%s (%s)\r\n", - child ? child->pid : -1, cmd[2], cmd[1], cmd[3] ); + (int) ( child ? child->pid : -1 ), cmd[2], cmd[1], cmd[3] ); } static void ipc_master_cmd_die( irc_t *data, char **cmd ) @@ -445,7 +445,7 @@ char *ipc_master_save_state() fprintf( fp, "%d\n", i ); for( l = child_list; l; l = l->next ) - fprintf( fp, "%d %d\n", ((struct bitlbee_child*)l->data)->pid, + fprintf( fp, "%d %d\n", (int) ((struct bitlbee_child*)l->data)->pid, ((struct bitlbee_child*)l->data)->ipc_fd ); if( fclose( fp ) == 0 ) @@ -550,7 +550,7 @@ int ipc_master_load_state() { child = g_new0( struct bitlbee_child, 1 ); - if( fscanf( fp, "%d %d", &child->pid, &child->ipc_fd ) != 2 ) + if( fscanf( fp, "%d %d", (int *) &child->pid, &child->ipc_fd ) != 2 ) { log_message( LOGLVL_WARNING, "Unexpected end of file: Only processed %d clients.", i ); g_free( child ); @@ -77,7 +77,7 @@ irc_t *irc_new( int fd ) char buf[NI_MAXHOST+1]; if( getnameinfo( (struct sockaddr *) &sock, socklen, buf, - NI_MAXHOST, NULL, -1, 0 ) == 0 ) + NI_MAXHOST, NULL, 0, 0 ) == 0 ) { irc->myhost = g_strdup( ipv6_unwrap( buf ) ); } @@ -88,7 +88,7 @@ irc_t *irc_new( int fd ) char buf[NI_MAXHOST+1]; if( getnameinfo( (struct sockaddr *)&sock, socklen, buf, - NI_MAXHOST, NULL, -1, 0 ) == 0 ) + NI_MAXHOST, NULL, 0, 0 ) == 0 ) { irc->host = g_strdup( ipv6_unwrap( buf ) ); } @@ -192,7 +192,6 @@ void irc_free(irc_t * irc) { account_t *account; user_t *user, *usertmp; - help_t *helpnode, *helpnodetmp; log_message( LOGLVL_INFO, "Destroying connection with fd %d", irc->fd ); @@ -269,16 +268,6 @@ void irc_free(irc_t * irc) g_hash_table_foreach_remove(irc->watches, irc_free_hashkey, NULL); g_hash_table_destroy(irc->watches); - if (irc->help != NULL) { - helpnode = irc->help; - while (helpnode != NULL) { - g_free(helpnode->string); - - helpnodetmp = helpnode; - helpnode = helpnode->next; - g_free(helpnodetmp); - } - } g_free(irc); if( global.conf->runmode == RUNMODE_INETD || global.conf->runmode == RUNMODE_FORKDAEMON ) @@ -328,15 +317,29 @@ void irc_process( irc_t *irc ) conv[IRC_MAX_LINE] = 0; if( do_iconv( cs, "UTF-8", lines[i], conv, 0, IRC_MAX_LINE - 2 ) == -1 ) { + /* GLib can do strange things if things are not in the expected charset, + so let's be a little bit paranoid here: */ if( irc->status & USTATUS_LOGGED_IN ) - irc_usermsg( irc, "ERROR: Charset mismatch detected. The charset " + { + irc_usermsg( irc, "Error: Charset mismatch detected. The charset " "setting is currently set to %s, so please make " "sure your IRC client will send and accept text in " "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; + *conv = 0; + } + else + { + irc_write( irc, ":%s NOTICE AUTH :%s", irc->myhost, + "Warning: invalid (non-UTF8) characters received at login time." ); + + strncpy( conv, lines[i], IRC_MAX_LINE ); + for( temp = conv; *temp; temp ++ ) + if( *temp & 0x80 ) + *temp = '?'; + } } lines[i] = conv; } @@ -89,7 +89,6 @@ typedef struct irc GHashTable *userhash; GHashTable *watches; struct __NICK *nicks; - struct help *help; struct set *set; gint r_watch_source_id; diff --git a/irc_commands.c b/irc_commands.c index 65f0d6c6..68db4617 100644 --- a/irc_commands.c +++ b/irc_commands.c @@ -555,7 +555,7 @@ static void irc_cmd_completions( irc_t *irc, char **cmd ) irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", commands[i].command ); for( h = global.help; h; h = h->next ) - irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS help ", h->string ); + irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS help ", h->title ); for( s = irc->set; s; s = s->next ) irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS set ", s->key ); @@ -570,7 +570,7 @@ static void irc_cmd_rehash( irc_t *irc, char **cmd ) else ipc_to_master( cmd ); - irc_reply( irc, 382, "%s :Rehashing", CONF_FILE ); + irc_reply( irc, 382, "%s :Rehashing", global.conf_file ); } static const command_t irc_commands[] = { diff --git a/lib/events_glib.c b/lib/events_glib.c index 38938380..1198dba6 100644 --- a/lib/events_glib.c +++ b/lib/events_glib.c @@ -47,7 +47,6 @@ typedef struct _GaimIOClosure { b_event_handler function; - guint result; gpointer data; } GaimIOClosure; @@ -100,6 +99,7 @@ gint b_input_add(gint source, b_input_condition condition, b_event_handler funct GaimIOClosure *closure = g_new0(GaimIOClosure, 1); GIOChannel *channel; GIOCondition cond = 0; + int st; closure->function = function; closure->data = data; @@ -110,13 +110,13 @@ gint b_input_add(gint source, b_input_condition condition, b_event_handler funct cond |= GAIM_WRITE_COND; channel = g_io_channel_unix_new(source); - closure->result = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond, - gaim_io_invoke, closure, gaim_io_destroy); + st = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond, + gaim_io_invoke, closure, gaim_io_destroy); - event_debug( "b_input_add( %d, %d, 0x%x, 0x%x ) = %d (0x%x)\n", source, condition, function, data, closure->result, closure ); + event_debug( "b_input_add( %d, %d, 0x%x, 0x%x ) = %d (%p)\n", source, condition, function, data, st, closure ); g_io_channel_unref(channel); - return closure->result; + return st; } gint b_timeout_add(gint timeout, b_event_handler func, gpointer data) @@ -25,7 +25,7 @@ #include <string.h> /* for memcpy() */ #include "md5.h" -static void md5_transform(u_int32_t buf[4], u_int32_t const in[16]); +static void md5_transform(uint32_t buf[4], uint32_t const in[16]); /* * Wrapper function for all-in-one MD5 @@ -34,6 +34,29 @@ static void md5_transform(u_int32_t buf[4], u_int32_t const in[16]); * 20021120 */ +/* Turns out MD5 was designed for little-endian machines. If we're running + on a big-endian machines, we have to swap some bytes. Since detecting + endianness at compile time reliably seems pretty hard, let's do it at + run-time. It's not like we're going to checksum megabytes of data... */ +static uint32_t cvt32(uint32_t val) +{ + static int little_endian = -1; + + if (little_endian == -1) + { + little_endian = 1; + little_endian = *((char*) &little_endian); + } + + if (little_endian) + return val; + else + return (val >> 24) | + ((val >> 8) & 0xff00) | + ((val << 8) & 0xff0000) | + (val << 24); +} + void md5_init(struct MD5Context *ctx) { ctx->buf[0] = 0x67452301; @@ -52,12 +75,12 @@ void md5_init(struct MD5Context *ctx) void md5_append(struct MD5Context *ctx, const md5_byte_t *buf, unsigned int len) { - u_int32_t t; + uint32_t t; /* Update bitcount */ t = ctx->bits[0]; - if ((ctx->bits[0] = t + ((u_int32_t) len << 3)) < t) + if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) ctx->bits[1]++; /* Carry from low to high */ ctx->bits[1] += len >> 29; @@ -74,7 +97,7 @@ void md5_append(struct MD5Context *ctx, const md5_byte_t *buf, return; } memcpy(p, buf, t); - md5_transform(ctx->buf, (u_int32_t *) ctx->in); + md5_transform(ctx->buf, (uint32_t *) ctx->in); buf += t; len -= t; } @@ -82,7 +105,7 @@ void md5_append(struct MD5Context *ctx, const md5_byte_t *buf, while (len >= 64) { memcpy(ctx->in, buf, 64); - md5_transform(ctx->buf, (u_int32_t *) ctx->in); + md5_transform(ctx->buf, (uint32_t *) ctx->in); buf += 64; len -= 64; } @@ -116,7 +139,7 @@ void md5_finish(struct MD5Context *ctx, md5_byte_t digest[16]) if (count < 8) { /* Two lots of padding: Pad the first block to 64 bytes */ memset(p, 0, count); - md5_transform(ctx->buf, (u_int32_t *) ctx->in); + md5_transform(ctx->buf, (uint32_t *) ctx->in); /* Now fill the next block with 56 bytes */ memset(ctx->in, 0, 56); @@ -126,10 +149,14 @@ void md5_finish(struct MD5Context *ctx, md5_byte_t digest[16]) } /* Append length in bits and transform */ - ((u_int32_t *) ctx->in)[14] = ctx->bits[0]; - ((u_int32_t *) ctx->in)[15] = ctx->bits[1]; - - md5_transform(ctx->buf, (u_int32_t *) ctx->in); + ((uint32_t *) ctx->in)[14] = cvt32(ctx->bits[0]); + ((uint32_t *) ctx->in)[15] = cvt32(ctx->bits[1]); + + md5_transform(ctx->buf, (uint32_t *) ctx->in); + ctx->buf[0] = cvt32(ctx->buf[0]); + ctx->buf[1] = cvt32(ctx->buf[1]); + ctx->buf[2] = cvt32(ctx->buf[2]); + ctx->buf[3] = cvt32(ctx->buf[3]); memcpy(digest, ctx->buf, 16); memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ } @@ -151,82 +178,82 @@ void md5_finish(struct MD5Context *ctx, md5_byte_t digest[16]) * reflect the addition of 16 longwords of new data. MD5Update blocks * the data and converts bytes into longwords for this routine. */ -static void md5_transform(u_int32_t buf[4], u_int32_t const in[16]) +static void md5_transform(uint32_t buf[4], uint32_t const in[16]) { - register u_int32_t a, b, c, d; + register uint32_t a, b, c, d; a = buf[0]; b = buf[1]; c = buf[2]; d = buf[3]; - MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); - MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); - MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); - MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); - MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); - MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); - MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); - MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); - MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); - MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); - MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); - MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); - MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); - MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); - MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); - MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); - - MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); - MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); - MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); - MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); - MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); - MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); - MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); - MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); - MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); - MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); - MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); - MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); - MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); - MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); - MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); - MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); - - MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); - MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); - MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); - MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); - MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); - MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); - MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); - MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); - MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); - MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); - MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); - MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); - MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); - MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); - MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); - MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); - - MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); - MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); - MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); - MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); - MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); - MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); - MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); - MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); - MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); - MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); - MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); - MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); - MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); - MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); - MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); - MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + MD5STEP(F1, a, b, c, d, cvt32(in[0]) + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, cvt32(in[1]) + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, cvt32(in[2]) + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, cvt32(in[3]) + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, cvt32(in[4]) + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, cvt32(in[5]) + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, cvt32(in[6]) + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, cvt32(in[7]) + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, cvt32(in[8]) + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, cvt32(in[9]) + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, cvt32(in[10]) + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, cvt32(in[11]) + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, cvt32(in[12]) + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, cvt32(in[13]) + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, cvt32(in[14]) + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, cvt32(in[15]) + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, cvt32(in[1]) + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, cvt32(in[6]) + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, cvt32(in[11]) + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, cvt32(in[0]) + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, cvt32(in[5]) + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, cvt32(in[10]) + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, cvt32(in[15]) + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, cvt32(in[4]) + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, cvt32(in[9]) + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, cvt32(in[14]) + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, cvt32(in[3]) + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, cvt32(in[8]) + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, cvt32(in[13]) + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, cvt32(in[2]) + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, cvt32(in[7]) + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, cvt32(in[12]) + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, cvt32(in[5]) + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, cvt32(in[8]) + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, cvt32(in[11]) + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, cvt32(in[14]) + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, cvt32(in[1]) + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, cvt32(in[4]) + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, cvt32(in[7]) + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, cvt32(in[10]) + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, cvt32(in[13]) + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, cvt32(in[0]) + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, cvt32(in[3]) + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, cvt32(in[6]) + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, cvt32(in[9]) + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, cvt32(in[12]) + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, cvt32(in[15]) + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, cvt32(in[2]) + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, cvt32(in[0]) + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, cvt32(in[7]) + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, cvt32(in[14]) + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, cvt32(in[5]) + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, cvt32(in[12]) + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, cvt32(in[3]) + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, cvt32(in[10]) + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, cvt32(in[1]) + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, cvt32(in[8]) + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, cvt32(in[15]) + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, cvt32(in[6]) + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, cvt32(in[13]) + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, cvt32(in[4]) + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, cvt32(in[11]) + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, cvt32(in[2]) + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, cvt32(in[9]) + 0xeb86d391, 21); buf[0] += a; buf[1] += b; @@ -26,11 +26,12 @@ #include <sys/types.h> #include <gmodule.h> +#include <stdint.h> -typedef u_int8_t md5_byte_t; +typedef uint8_t md5_byte_t; typedef struct MD5Context { - u_int32_t buf[4]; - u_int32_t bits[2]; + uint32_t buf[4]; + uint32_t bits[2]; unsigned char in[64]; } md5_state_t; @@ -89,12 +89,14 @@ time_t get_time(int year, int month, int day, int hour, int min, int sec) { struct tm tm; + memset(&tm, 0, sizeof(struct tm)); tm.tm_year = year - 1900; tm.tm_mon = month - 1; tm.tm_mday = day; tm.tm_hour = hour; tm.tm_min = min; tm.tm_sec = sec >= 0 ? sec : time(NULL) % 60; + return mktime(&tm); } @@ -244,12 +246,6 @@ char *escape_html( const char *html ) return( str ); } -void info_string_append(GString *str, char *newline, char *name, char *value) -{ - if( value && value[0] ) - g_string_sprintfa( str, "%s%s: %s", newline, name, value ); -} - /* Decode%20a%20file%20name */ void http_decode( char *s ) { @@ -41,7 +41,6 @@ G_MODULE_EXPORT void strip_linefeed( gchar *text ); G_MODULE_EXPORT char *add_cr( char *text ); G_MODULE_EXPORT char *strip_newlines(char *source); G_MODULE_EXPORT char *normalize( const char *s ); -G_MODULE_EXPORT void info_string_append( GString *str, char *newline, char *name, char *value ); G_MODULE_EXPORT time_t get_time( int year, int month, int day, int hour, int min, int sec ); double gettime( void ); diff --git a/lib/proxy.c b/lib/proxy.c index dff5d0a4..0e1c8f07 100644 --- a/lib/proxy.c +++ b/lib/proxy.c @@ -129,18 +129,17 @@ static int proxy_connect_none(const char *host, unsigned short port, struct PHB event_debug("proxy_connect_none( \"%s\", %d ) = %d\n", host, port, fd); - if (connect(fd, (struct sockaddr *)sin, sizeof(*sin)) < 0) { - if (sockerr_again()) { - phb->inpa = b_input_add(fd, GAIM_INPUT_WRITE, gaim_io_connected, phb); - phb->fd = fd; - } else { - closesocket(fd); - g_free(phb); - return -1; - } + if (connect(fd, (struct sockaddr *)sin, sizeof(*sin)) < 0 && !sockerr_again()) { + closesocket(fd); + g_free(phb); + + return -1; + } else { + phb->inpa = b_input_add(fd, GAIM_INPUT_WRITE, gaim_io_connected, phb); + phb->fd = fd; + + return fd; } - - return fd; } @@ -110,7 +110,7 @@ void nick_dedupe( account_t *acc, const char *handle, char nick[MAX_NICK_LENGTH+ { int i; - irc_usermsg( acc->irc, "WARNING: Almost had an infinite loop in nick_get()! " + irc_usermsg( acc->irc, "Warning: Almost had an infinite loop in nick_get()! " "This used to be a fatal BitlBee bug, but we tried to fix it. " "This message should *never* appear anymore. " "If it does, please *do* send us a bug report! " diff --git a/protocols/jabber/conference.c b/protocols/jabber/conference.c index 074412ec..79fdd053 100644 --- a/protocols/jabber/conference.c +++ b/protocols/jabber/conference.c @@ -36,6 +36,8 @@ struct groupchat *jabber_chat_join( struct im_connection *ic, char *room, char * node = xt_new_node( "x", NULL, NULL ); xt_add_attr( node, "xmlns", XMLNS_MUC ); node = jabber_make_packet( "presence", NULL, roomjid, node ); + if( password ) + xt_add_child( node, xt_new_node( "password", password, NULL ) ); jabber_cache_add( ic, node, jabber_chat_join_failed ); if( !jabber_write_packet( ic, node ) ) @@ -72,17 +74,16 @@ static xt_status jabber_chat_join_failed( struct im_connection *ic, struct xt_no char *room; room = xt_find_attr( orig, "to" ); - if( ( bud = jabber_buddy_by_jid( ic, room, 0 ) ) ) - jabber_chat_free( jabber_chat_by_jid( ic, bud->bare_jid ) ); - + bud = jabber_buddy_by_jid( ic, room, 0 ); err = jabber_error_parse( xt_find_node( node->children, "error" ), XMLNS_STANZA_ERROR ); if( err ) { - imcb_error( ic, "Error joining groupchat %s: %s%s%s", - bud->bare_jid, err->code, err->text ? ": " : "", - err->text ? err->text : "" ); + imcb_error( ic, "Error joining groupchat %s: %s%s%s", room, err->code, + err->text ? ": " : "", err->text ? err->text : "" ); jabber_error_free( err ); } + if( bud ) + jabber_chat_free( jabber_chat_by_jid( ic, bud->bare_jid ) ); return XT_HANDLED; } @@ -123,6 +124,8 @@ int jabber_chat_msg( struct groupchat *c, char *message, int flags ) struct jabber_chat *jc = c->data; struct xt_node *node; + jc->flags |= JCFLAG_MESSAGE_SENT; + node = xt_new_node( "body", message, NULL ); node = jabber_make_packet( "message", "groupchat", jc->name, node ); @@ -295,22 +298,59 @@ void jabber_chat_pkt_message( struct im_connection *ic, struct jabber_buddy *bud { struct xt_node *subject = xt_find_node( node->children, "subject" ); struct xt_node *body = xt_find_node( node->children, "body" ); - struct groupchat *chat; + struct groupchat *chat = bud ? jabber_chat_by_jid( ic, bud->bare_jid ) : NULL; + struct jabber_chat *jc = chat ? chat->data : NULL; char *s; - if( bud == NULL ) + if( bud == NULL || ( jc && ~jc->flags & JCFLAG_MESSAGE_SENT && bud == jc->me ) ) { + char *nick; + + if( body == NULL || body->text_len == 0 ) + /* Meh. Empty messages aren't very interesting, no matter + how much some servers love to send them. */ + return; + s = xt_find_attr( node, "from" ); /* pkt_message() already NULL-checked this one. */ - if( strchr( s, '/' ) == NULL ) + nick = strchr( s, '/' ); + if( nick ) + { + /* If this message included a resource/nick we don't know, + we might still know the groupchat itself. */ + *nick = 0; + chat = jabber_chat_by_jid( ic, s ); + *nick = '/'; + + nick ++; + } + else + { + /* message.c uses the EXACT_JID option, so bud should + always be NULL here for bare JIDs. */ + chat = jabber_chat_by_jid( ic, s ); + } + + if( nick == NULL ) + { /* This is fine, the groupchat itself isn't in jd->buddies. */ - imcb_log( ic, "System message from groupchat %s: %s", s, body? body->text : "NULL" ); + if( chat ) + imcb_chat_log( chat, "From conference server: %s", body->text ); + else + imcb_log( ic, "System message from unknown groupchat %s: %s", s, body->text ); + } else - /* This, however, isn't fine! */ - imcb_log( ic, "Groupchat message from unknown participant %s: %s", s, body ? body->text : "NULL" ); + { + /* This can happen too, at least when receiving a backlog when + just joining a channel. */ + if( chat ) + imcb_chat_log( chat, "Message from unknown participant %s: %s", nick, body->text ); + else + imcb_log( ic, "Groupchat message from unknown JID %s: %s", s, body->text ); + } return; } - else if( ( chat = jabber_chat_by_jid( ic, bud->bare_jid ) ) == NULL ) + else if( chat == NULL ) { /* How could this happen?? We could do kill( self, 11 ) now or just wait for the OS to do it. :-) */ diff --git a/protocols/jabber/io.c b/protocols/jabber/io.c index 29561b86..86c216ef 100644 --- a/protocols/jabber/io.c +++ b/protocols/jabber/io.c @@ -248,6 +248,9 @@ gboolean jabber_connected_plain( gpointer data, gint source, b_input_condition c { struct im_connection *ic = data; + if( g_slist_find( jabber_connections, ic ) == NULL ) + return FALSE; + if( source == -1 ) { imcb_error( ic, "Could not connect to server" ); @@ -263,7 +266,12 @@ gboolean jabber_connected_plain( gpointer data, gint source, b_input_condition c gboolean jabber_connected_ssl( gpointer data, void *source, b_input_condition cond ) { struct im_connection *ic = data; - struct jabber_data *jd = ic->proto_data; + struct jabber_data *jd; + + if( g_slist_find( jabber_connections, ic ) == NULL ) + return FALSE; + + jd = ic->proto_data; if( source == NULL ) { diff --git a/protocols/jabber/iq.c b/protocols/jabber/iq.c index 2f0959b0..d45b7625 100644 --- a/protocols/jabber/iq.c +++ b/protocols/jabber/iq.c @@ -53,7 +53,7 @@ xt_status jabber_pkt_iq( struct xt_node *node, gpointer data ) ( c = xt_find_node( node->children, "ping" ) ) ) || /* O_o WHAT is wrong with just <query/> ????? */ !( s = xt_find_attr( c, "xmlns" ) ) ) { - imcb_log( ic, "WARNING: Received incomplete IQ-%s packet", type ); + imcb_log( ic, "Warning: Received incomplete IQ-%s packet", type ); return XT_HANDLED; } @@ -91,7 +91,8 @@ xt_status jabber_pkt_iq( struct xt_node *node, gpointer data ) } else if( strcmp( s, XMLNS_DISCO_INFO ) == 0 ) { - const char *features[] = { XMLNS_VERSION, + const char *features[] = { XMLNS_DISCO_INFO, + XMLNS_VERSION, XMLNS_TIME, XMLNS_CHATSTATES, XMLNS_MUC, @@ -131,7 +132,7 @@ xt_status jabber_pkt_iq( struct xt_node *node, gpointer data ) } else if( !( c = xt_find_node( node->children, "query" ) ) || !( s = xt_find_attr( c, "xmlns" ) ) ) { - imcb_log( ic, "WARNING: Received incomplete IQ-%s packet", type ); + imcb_log( ic, "Warning: Received incomplete IQ-%s packet", type ); return XT_HANDLED; } else if( strcmp( s, XMLNS_ROSTER ) == 0 ) { @@ -151,7 +152,7 @@ xt_status jabber_pkt_iq( struct xt_node *node, gpointer data ) } else { - imcb_log( ic, "WARNING: %s tried to fake a roster push!", s ? s : "(unknown)" ); + imcb_log( ic, "Warning: %s tried to fake a roster push!", s ? s : "(unknown)" ); xt_free_node( reply ); reply = jabber_make_error_packet( node, "not-allowed", "cancel", NULL ); @@ -219,7 +220,7 @@ static xt_status jabber_do_iq_auth( struct im_connection *ic, struct xt_node *no if( !( query = xt_find_node( node->children, "query" ) ) ) { - imcb_log( ic, "WARNING: Received incomplete IQ packet while authenticating" ); + imcb_log( ic, "Warning: Received incomplete IQ packet while authenticating" ); imc_logout( ic, FALSE ); return XT_HANDLED; } @@ -277,7 +278,7 @@ static xt_status jabber_finish_iq_auth( struct im_connection *ic, struct xt_node if( !( type = xt_find_attr( node, "type" ) ) ) { - imcb_log( ic, "WARNING: Received incomplete IQ packet while authenticating" ); + imcb_log( ic, "Warning: Received incomplete IQ packet while authenticating" ); imc_logout( ic, FALSE ); return XT_HANDLED; } @@ -353,7 +354,7 @@ static xt_status jabber_parse_roster( struct im_connection *ic, struct xt_node * if( !( query = xt_find_node( node->children, "query" ) ) ) { - imcb_log( ic, "WARNING: Received NULL roster packet" ); + imcb_log( ic, "Warning: Received NULL roster packet" ); return XT_HANDLED; } diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index d028655a..07d760a5 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -34,6 +34,8 @@ #include "md5.h" #include "base64.h" +GSList *jabber_connections; + static void jabber_init( account_t *acc ) { set_t *s; @@ -70,6 +72,11 @@ static void jabber_login( account_t *acc ) struct ns_srv_reply *srv = NULL; char *connect_to, *s; + /* For now this is needed in the _connected() handlers if using + GLib event handling, to make sure we're not handling events + on dead connections. */ + jabber_connections = g_slist_prepend( jabber_connections, ic ); + jd->ic = ic; ic->proto_data = jd; @@ -196,6 +203,8 @@ static void jabber_login( account_t *acc ) { imcb_error( ic, "Could not connect to server" ); imc_logout( ic, TRUE ); + + return; } if( set_getbool( &acc->set, "xmlconsole" ) ) @@ -260,6 +269,8 @@ static void jabber_logout( struct im_connection *ic ) g_free( jd->away_message ); g_free( jd->username ); g_free( jd ); + + jabber_connections = g_slist_remove( jabber_connections, ic ); } static int jabber_buddy_msg( struct im_connection *ic, char *who, char *message, int flags ) diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h index 3251b49b..fc315710 100644 --- a/protocols/jabber/jabber.h +++ b/protocols/jabber/jabber.h @@ -29,6 +29,8 @@ #include "xmltree.h" #include "bitlbee.h" +extern GSList *jabber_connections; + typedef enum { JFLAG_STREAM_STARTED = 1, /* Set when we detected the beginning of the stream @@ -46,13 +48,13 @@ typedef enum typedef enum { - JBFLAG_PROBED_XEP85 = 1, /* Set this when we sent our probe packet to make + JBFLAG_PROBED_XEP85 = 1, /* Set this when we sent our probe packet to make sure it gets sent only once. */ - JBFLAG_DOES_XEP85 = 2, /* Set this when the resource seems to support + JBFLAG_DOES_XEP85 = 2, /* Set this when the resource seems to support XEP85 (typing notification shite). */ - JBFLAG_IS_CHATROOM = 4, /* It's convenient to use this JID thingy for + JBFLAG_IS_CHATROOM = 4, /* It's convenient to use this JID thingy for groupchat state info too. */ - JBFLAG_IS_ANONYMOUS = 8, /* For anonymous chatrooms, when we don't have + JBFLAG_IS_ANONYMOUS = 8, /* For anonymous chatrooms, when we don't have have a real JID. */ } jabber_buddy_flags_t; @@ -64,6 +66,12 @@ typedef struct char port[6]; } jabber_streamhost_t; +typedef enum +{ + JCFLAG_MESSAGE_SENT = 1, /* Set this after sending the first message, so + we can detect echoes/backlogs. */ +} jabber_chat_flags_t; + struct jabber_data { struct im_connection *ic; @@ -104,6 +112,7 @@ typedef xt_status (*jabber_cache_event) ( struct im_connection *ic, struct xt_no struct jabber_cache_entry { + time_t saved_at; struct xt_node *node; jabber_cache_event func; }; @@ -175,6 +184,10 @@ struct jabber_transfer #define JABBER_PACKET_ID "BeeP" #define JABBER_CACHED_ID "BeeC" +/* The number of seconds to keep cached packets before garbage collecting + them. This gc is done on every keepalive (every minute). */ +#define JABBER_CACHE_MAX_AGE 600 + /* RFC 392[01] stuff */ #define XMLNS_TLS "urn:ietf:params:xml:ns:xmpp-tls" #define XMLNS_SASL "urn:ietf:params:xml:ns:xmpp-sasl" @@ -197,6 +210,7 @@ struct jabber_transfer #define XMLNS_DISCO_ITEMS "http://jabber.org/protocol/disco#items" /* XEP-0030 */ #define XMLNS_MUC "http://jabber.org/protocol/muc" /* XEP-0045 */ #define XMLNS_MUC_USER "http://jabber.org/protocol/muc#user" /* XEP-0045 */ +#define XMLNS_CAPS "http://jabber.org/protocol/caps" /* XEP-0115 */ #define XMLNS_FEATURE "http://jabber.org/protocol/feature-neg" /* XEP-0020 */ #define XMLNS_SI "http://jabber.org/protocol/si" /* XEP-0095 */ #define XMLNS_FILETRANSFER "http://jabber.org/protocol/si/profile/file-transfer" /* XEP-0096 */ diff --git a/protocols/jabber/jabber_util.c b/protocols/jabber/jabber_util.c index 7350eaf4..c8470b57 100644 --- a/protocols/jabber/jabber_util.c +++ b/protocols/jabber/jabber_util.c @@ -145,6 +145,7 @@ void jabber_cache_add( struct im_connection *ic, struct xt_node *node, jabber_ca entry->node = node; entry->func = func; + entry->saved_at = time( NULL ); g_hash_table_insert( jd->node_cache, xt_find_attr( node, "id" ), entry ); } @@ -166,22 +167,17 @@ gboolean jabber_cache_clean_entry( gpointer key, gpointer entry, gpointer nullpo void jabber_cache_clean( struct im_connection *ic ) { struct jabber_data *jd = ic->proto_data; + time_t threshold = time( NULL ) - JABBER_CACHE_MAX_AGE; - g_hash_table_foreach_remove( jd->node_cache, jabber_cache_clean_entry, NULL ); + g_hash_table_foreach_remove( jd->node_cache, jabber_cache_clean_entry, &threshold ); } -gboolean jabber_cache_clean_entry( gpointer key, gpointer entry_, gpointer nullpointer ) +gboolean jabber_cache_clean_entry( gpointer key, gpointer entry_, gpointer threshold_ ) { struct jabber_cache_entry *entry = entry_; - struct xt_node *node = entry->node; + time_t *threshold = threshold_; - if( node->flags & XT_SEEN ) - return TRUE; - else - { - node->flags |= XT_SEEN; - return FALSE; - } + return entry->saved_at < *threshold; } xt_status jabber_cache_handle_packet( struct im_connection *ic, struct xt_node *node ) @@ -203,7 +199,7 @@ xt_status jabber_cache_handle_packet( struct im_connection *ic, struct xt_node * if( entry == NULL ) { - imcb_log( ic, "WARNING: Received %s-%s packet with unknown/expired ID %s!", + imcb_log( ic, "Warning: Received %s-%s packet with unknown/expired ID %s!", node->name, xt_find_attr( node, "type" ) ? : "(no type)", s ); } else if( entry->func ) @@ -402,19 +398,26 @@ struct jabber_buddy *jabber_buddy_by_jid( struct im_connection *ic, char *jid_, *s = 0; if( ( bud = g_hash_table_lookup( jd->buddies, jid ) ) ) { + /* Just return the first one for this bare JID. */ + if( flags & GET_BUDDY_FIRST ) + { + *s = '/'; + g_free( jid ); + return bud; + } + /* Is this one of those no-resource buddies? */ if( bud->resource == NULL ) { + *s = '/'; g_free( jid ); return NULL; } - else - { - /* See if there's an exact match. */ - for( ; bud; bud = bud->next ) - if( g_strcasecmp( bud->resource, s + 1 ) == 0 ) - break; - } + + /* See if there's an exact match. */ + for( ; bud; bud = bud->next ) + if( g_strcasecmp( bud->resource, s + 1 ) == 0 ) + break; } else { @@ -423,6 +426,8 @@ struct jabber_buddy *jabber_buddy_by_jid( struct im_connection *ic, char *jid_, for this JID, even if it's an unknown buddy. This is done to handle conferences properly. */ none_found = 1; + /* TODO(wilmer): Find out what I was thinking when I + wrote this??? And then fix it. This makes me sad... */ } if( bud == NULL && ( flags & GET_BUDDY_CREAT ) && ( imcb_find_buddy( ic, jid ) || !none_found ) ) @@ -453,6 +458,9 @@ struct jabber_buddy *jabber_buddy_by_jid( struct im_connection *ic, char *jid_, else if( ( bud->resource == NULL || bud->next == NULL ) ) /* No need for selection if there's only one option. */ return bud; + else if( flags & GET_BUDDY_FIRST ) + /* Looks like the caller doesn't care about details. */ + return bud; best_prio = best_time = bud; for( ; bud; bud = bud->next ) diff --git a/protocols/jabber/presence.c b/protocols/jabber/presence.c index c3d7dced..6fc360b7 100644 --- a/protocols/jabber/presence.c +++ b/protocols/jabber/presence.c @@ -28,9 +28,9 @@ xt_status jabber_pkt_presence( struct xt_node *node, gpointer data ) struct im_connection *ic = data; char *from = xt_find_attr( node, "from" ); char *type = xt_find_attr( node, "type" ); /* NULL should mean the person is online. */ - struct xt_node *c; - struct jabber_buddy *bud; - int is_chat = 0, is_away = 0; + struct xt_node *c, *cap; + struct jabber_buddy *bud, *send_presence = NULL; + int is_chat = 0; char *s; if( !from ) @@ -49,7 +49,7 @@ xt_status jabber_pkt_presence( struct xt_node *node, gpointer data ) if( !( bud = jabber_buddy_by_jid( ic, from, GET_BUDDY_EXACT | GET_BUDDY_CREAT ) ) ) { if( set_getbool( &ic->irc->set, "debug" ) ) - imcb_log( ic, "WARNING: Could not handle presence information from JID: %s", from ); + imcb_log( ic, "Warning: Could not handle presence information from JID: %s", from ); return XT_HANDLED; } @@ -62,8 +62,6 @@ xt_status jabber_pkt_presence( struct xt_node *node, gpointer data ) if( ( c = xt_find_node( node->children, "show" ) ) && c->text_len > 0 ) { bud->away_state = (void*) jabber_away_state_by_code( c->text ); - if( strcmp( c->text, "chat" ) != 0 ) - is_away = OPT_AWAY; } else { @@ -78,19 +76,37 @@ xt_status jabber_pkt_presence( struct xt_node *node, gpointer data ) else bud->priority = 0; + if( bud && ( cap = xt_find_node( node->children, "c" ) ) && + ( s = xt_find_attr( cap, "xmlns" ) ) && strcmp( s, XMLNS_CAPS ) == 0 ) + { + /* This <presence> stanza includes an XEP-0115 + capabilities part. Not too interesting, but we can + see if it has an ext= attribute. */ + s = xt_find_attr( cap, "ext" ); + if( s && ( strstr( s, "cstates" ) || strstr( s, "chatstate" ) ) ) + bud->flags |= JBFLAG_DOES_XEP85; + + /* This field can contain more information like xhtml + support, but we don't support that ourselves. + Officially the ext= tag was deprecated, but enough + clients do send it. + + (I'm aware that this is not the right way to use + this field.) See for an explanation of ext=: + http://www.xmpp.org/extensions/attic/xep-0115-1.3.html*/ + } + if( is_chat ) jabber_chat_pkt_presence( ic, bud, node ); - else if( bud == jabber_buddy_by_jid( ic, bud->bare_jid, 0 ) ) - imcb_buddy_status( ic, bud->bare_jid, OPT_LOGGED_IN | is_away, - ( is_away && bud->away_state ) ? bud->away_state->full_name : NULL, - bud->away_message ); + else + send_presence = jabber_buddy_by_jid( ic, bud->bare_jid, 0 ); } else if( strcmp( type, "unavailable" ) == 0 ) { if( ( bud = jabber_buddy_by_jid( ic, from, 0 ) ) == NULL ) { if( set_getbool( &ic->irc->set, "debug" ) ) - imcb_log( ic, "WARNING: Received presence information from unknown JID: %s", from ); + imcb_log( ic, "Warning: Received presence information from unknown JID: %s", from ); return XT_HANDLED; } @@ -118,17 +134,7 @@ xt_status jabber_pkt_presence( struct xt_node *node, gpointer data ) /* If another resource is still available, send its presence information. */ - if( ( bud = jabber_buddy_by_jid( ic, from, 0 ) ) ) - { - if( bud->away_state && ( *bud->away_state->code == 0 || - strcmp( bud->away_state->code, "chat" ) == 0 ) ) - is_away = OPT_AWAY; - - imcb_buddy_status( ic, bud->bare_jid, OPT_LOGGED_IN | is_away, - ( is_away && bud->away_state ) ? bud->away_state->full_name : NULL, - bud->away_message ); - } - else + if( ( send_presence = jabber_buddy_by_jid( ic, from, 0 ) ) == NULL ) { /* Otherwise, count him/her as offline now. */ imcb_buddy_status( ic, from, 0, NULL, NULL ); @@ -176,6 +182,20 @@ xt_status jabber_pkt_presence( struct xt_node *node, gpointer data ) jabber_error_free( err ); } */ } + + if( send_presence ) + { + int is_away = 0; + + if( send_presence->away_state && !( *send_presence->away_state->code == 0 || + strcmp( send_presence->away_state->code, "chat" ) == 0 ) ) + is_away = OPT_AWAY; + + imcb_buddy_status( ic, send_presence->bare_jid, OPT_LOGGED_IN | is_away, + ( is_away && send_presence->away_state ) ? + send_presence->away_state->full_name : NULL, + send_presence->away_message ); + } return XT_HANDLED; } @@ -185,7 +205,7 @@ xt_status jabber_pkt_presence( struct xt_node *node, gpointer data ) int presence_send_update( struct im_connection *ic ) { struct jabber_data *jd = ic->proto_data; - struct xt_node *node; + struct xt_node *node, *cap; char *show = jd->away_state->code; char *status = jd->away_message; struct groupchat *c; @@ -198,6 +218,16 @@ int presence_send_update( struct im_connection *ic ) if( status ) xt_add_child( node, xt_new_node( "status", status, NULL ) ); + /* This makes the packet slightly bigger, but clients interested in + capabilities can now cache the discovery info. This reduces the + usual post-login iq-flood. See XEP-0115. At least libpurple and + Trillian seem to do this right. */ + cap = xt_new_node( "c", NULL, NULL ); + xt_add_attr( cap, "xmlns", XMLNS_CAPS ); + xt_add_attr( cap, "node", "http://bitlbee.org/xmpp/caps" ); + xt_add_attr( cap, "ver", BITLBEE_VERSION ); /* The XEP wants this hashed, but nobody's doing that. */ + xt_add_child( node, cap ); + st = jabber_write_packet( ic, node ); /* Have to send this update to all groupchats too, the server won't diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c index aa05dbdd..a2e8519a 100644 --- a/protocols/msn/msn.c +++ b/protocols/msn/msn.c @@ -34,6 +34,8 @@ static void msn_init( account_t *acc ) s = set_add( &acc->set, "display_name", NULL, msn_set_display_name, acc ); s->flags |= ACC_SET_NOSAVE | ACC_SET_ONLINE_ONLY; + + s = set_add( &acc->set, "mail_notifications", "false", set_eval_bool, acc ); } static void msn_login( account_t *acc ) @@ -87,21 +89,7 @@ static void msn_logout( struct im_connection *ic ) while( md->switchboards ) msn_sb_destroy( md->switchboards->data ); - if( md->msgq ) - { - struct msn_message *m; - - for( l = md->msgq; l; l = l->next ) - { - m = l->data; - - imcb_log( ic, "Warning: Closing down MSN connection with unsent message to %s, you'll have to resend it.", m->who ); - g_free( m->who ); - g_free( m->text ); - g_free( m ); - } - g_slist_free( md->msgq ); - } + msn_msgq_purge( ic, &md->msgq ); while( md->groupcount > 0 ) g_free( md->grouplist[--md->groupcount] ); diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h index 721466d6..c8f4f4c6 100644 --- a/protocols/msn/msn.h +++ b/protocols/msn/msn.h @@ -28,11 +28,9 @@ #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 _WIN32 -#define debug +#ifdef DEBUG +#define debug( text... ) imcb_log( ic, text ); #else -#define debug( text... ) irc_usermsg( IRC, text ); -#undef debug #define debug( text... ) #endif @@ -65,8 +63,10 @@ struct msn_data GSList *msgq; GSList *switchboards; - const struct msn_away_state *away_state; + int sb_failures; + time_t first_sb_failure; + const struct msn_away_state *away_state; int buddycount; int groupcount; char **grouplist; @@ -157,6 +157,7 @@ char *msn_findheader( char *text, char *header, int len ); char **msn_linesplit( char *line ); int msn_handler( struct msn_handler_data *h ); char *msn_http_encode( const char *input ); +void msn_msgq_purge( struct im_connection *ic, GSList **list ); /* tables.c */ const struct msn_away_state *msn_away_state_by_number( int number ); diff --git a/protocols/msn/msn_util.c b/protocols/msn/msn_util.c index c9eb5ee2..fae2877d 100644 --- a/protocols/msn/msn_util.c +++ b/protocols/msn/msn_util.c @@ -338,3 +338,37 @@ char *msn_http_encode( const char *input ) return ret; } + +void msn_msgq_purge( struct im_connection *ic, GSList **list ) +{ + struct msn_message *m; + GString *ret; + GSList *l; + + l = *list; + if( l == NULL ) + return; + + m = l->data; + ret = g_string_sized_new( 1024 ); + g_string_printf( ret, "Warning: Cleaning up MSN (switchboard) connection with unsent " + "messages to %s:", m->who ? m->who : "unknown recipient" ); + + while( l ) + { + m = l->data; + + g_string_append_printf( ret, "\n%s", m->text ); + + g_free( m->who ); + g_free( m->text ); + g_free( m ); + + l = l->next; + } + g_slist_free( *list ); + *list = NULL; + + imcb_log( ic, ret->str ); + g_string_free( ret, TRUE ); +} diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index 9bd7f152..0bb84a74 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -583,7 +583,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) } else { - debug( "Received unknown command from main server: %s", cmd[0] ); + /* debug( "Received unknown command from main server: %s", cmd[0] ); */ } return( 1 ); @@ -642,7 +642,7 @@ static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int char *inbox = msn_findheader( body, "Inbox-Unread:", blen ); char *folders = msn_findheader( body, "Folders-Unread:", blen ); - if( inbox && folders ) + if( inbox && folders && set_getbool( &ic->acc->set, "mail_notifications" ) ) { imcb_log( ic, "INBOX contains %s new messages, plus %s messages in other folders.", inbox, folders ); } @@ -652,7 +652,7 @@ static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int char *from = msn_findheader( body, "From-Addr:", blen ); char *fromname = msn_findheader( body, "From:", blen ); - if( from && fromname ) + if( from && fromname && set_getbool( &ic->acc->set, "mail_notifications" ) ) { imcb_log( ic, "Received an e-mail message from %s <%s>.", fromname, from ); } diff --git a/protocols/msn/sb.c b/protocols/msn/sb.c index cb9e2cab..18c41ef5 100644 --- a/protocols/msn/sb.c +++ b/protocols/msn/sb.c @@ -127,7 +127,7 @@ int msn_sb_sendmessage( struct msn_switchboard *sb, char *text ) /* Build the message. Convert LF to CR-LF for normal messages. */ if( strcmp( text, TYPING_NOTIFICATION_MESSAGE ) != 0 ) { - buf = g_new0( char, sizeof( MSN_MESSAGE_HEADERS ) + strlen( text ) * 2 ); + buf = g_new0( char, sizeof( MSN_MESSAGE_HEADERS ) + strlen( text ) * 2 + 1 ); i = strlen( MSN_MESSAGE_HEADERS ); strcpy( buf, MSN_MESSAGE_HEADERS ); @@ -206,25 +206,7 @@ void msn_sb_destroy( struct msn_switchboard *sb ) debug( "Destroying switchboard: %s", sb->who ? sb->who : sb->key ? sb->key : "" ); - if( sb->msgq ) - { - struct msn_message *m; - GSList *l; - - for( l = sb->msgq; l; l = l->next ) - { - m = l->data; - - g_free( m->who ); - g_free( m->text ); - g_free( m ); - } - g_slist_free( sb->msgq ); - - imcb_log( ic, "Warning: Closing down MSN switchboard connection with " - "unsent message to %s, you'll have to resend it.", - sb->who ? sb->who : "(unknown)" ); - } + msn_msgq_purge( ic, &sb->msgq ); if( sb->key ) g_free( sb->key ); if( sb->who ) g_free( sb->who ); @@ -265,7 +247,7 @@ gboolean msn_sb_connected( gpointer data, gint source, b_input_condition cond ) if( source != sb->fd ) { - debug( "ERROR %d while connecting to switchboard server", 1 ); + debug( "Error %d while connecting to switchboard server", 1 ); msn_sb_destroy( sb ); return FALSE; } @@ -286,7 +268,7 @@ gboolean msn_sb_connected( gpointer data, gint source, b_input_condition cond ) if( msn_sb_write( sb, buf, strlen( buf ) ) ) sb->inp = b_input_add( sb->fd, GAIM_INPUT_READ, msn_sb_callback, sb ); else - debug( "ERROR %d while connecting to switchboard server", 2 ); + debug( "Error %d while connecting to switchboard server", 2 ); return FALSE; } @@ -294,16 +276,59 @@ gboolean msn_sb_connected( gpointer data, gint source, b_input_condition cond ) static gboolean msn_sb_callback( gpointer data, gint source, b_input_condition cond ) { struct msn_switchboard *sb = data; + struct im_connection *ic = sb->ic; + struct msn_data *md = ic->proto_data; if( msn_handler( sb->handler ) == -1 ) { - debug( "ERROR: Switchboard died" ); + time_t now = time( NULL ); + + if( now - md->first_sb_failure > 600 ) + { + /* It's not really the first one, but the start of this "series". + With this, the warning below will be shown only if this happens + at least three times in ten minutes. This algorithm isn't + perfect, but for this purpose it will do. */ + md->first_sb_failure = now; + md->sb_failures = 0; + } + + debug( "Error: Switchboard died" ); + if( ++ md->sb_failures >= 3 ) + imcb_log( ic, "Warning: Many switchboard failures on MSN connection. " + "There might be problems delivering your messages." ); + + if( sb->msgq != NULL ) + { + char buf[1024]; + + if( md->msgq == NULL ) + { + md->msgq = sb->msgq; + } + else + { + GSList *l; + + for( l = md->msgq; l->next; l = l->next ); + l->next = sb->msgq; + } + sb->msgq = NULL; + + debug( "Moved queued messages back to the main queue, creating a new switchboard to retry." ); + g_snprintf( buf, sizeof( buf ), "XFR %d SB\r\n", ++md->trId ); + if( !msn_write( ic, buf, strlen( buf ) ) ) + return FALSE; + } + msn_sb_destroy( sb ); return FALSE; } else + { return TRUE; + } } static int msn_sb_command( gpointer data, char **cmd, int num_parts ) @@ -490,6 +515,17 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts ) return( 0 ); } } + else if( strcmp( cmd[0], "NAK" ) == 0 ) + { + if( sb->who ) + { + imcb_log( ic, "The MSN servers could not deliver one of your messages to %s.", sb->who ); + } + else + { + imcb_log( ic, "The MSN servers could not deliver one of your groupchat messages to all participants." ); + } + } else if( strcmp( cmd[0], "BYE" ) == 0 ) { if( num_parts < 2 ) @@ -543,24 +579,13 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts ) { if( sb->who ) { - struct msn_message *m; - GSList *l; - /* Apparently some invitation failed. We might want to use this board later, so keep it as a spare. */ g_free( sb->who ); sb->who = NULL; /* Also clear the msgq, otherwise someone else might get them. */ - for( l = sb->msgq; l; l = l->next ) - { - m = l->data; - g_free( m->who ); - g_free( m->text ); - g_free( m ); - } - g_slist_free( sb->msgq ); - sb->msgq = NULL; + msn_msgq_purge( ic, &sb->msgq ); } /* Do NOT return 0 here, we want to keep this sb. */ @@ -568,7 +593,7 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts ) } else { - debug( "Received unknown command from switchboard server: %s", cmd[0] ); + /* debug( "Received unknown command from switchboard server: %s", cmd[0] ); */ } return( 1 ); diff --git a/protocols/nogaim.c b/protocols/nogaim.c index 5e698902..3ce15166 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -624,7 +624,7 @@ void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, } } -void imcb_buddy_msg( struct im_connection *ic, char *handle, char *msg, u_int32_t flags, time_t sent_at ) +void imcb_buddy_msg( struct im_connection *ic, char *handle, char *msg, uint32_t flags, time_t sent_at ) { irc_t *irc = ic->irc; char *wrapped; @@ -675,7 +675,7 @@ void imcb_buddy_msg( struct im_connection *ic, char *handle, char *msg, u_int32_ g_free( wrapped ); } -void imcb_buddy_typing( struct im_connection *ic, char *handle, u_int32_t flags ) +void imcb_buddy_typing( struct im_connection *ic, char *handle, uint32_t flags ) { user_t *u; @@ -691,6 +691,31 @@ void imcb_buddy_typing( struct im_connection *ic, char *handle, u_int32_t flags } } +struct groupchat *imcb_chat_new( struct im_connection *ic, char *handle ) +{ + struct groupchat *c; + + /* This one just creates the conversation structure, user won't see anything yet */ + + if( ic->groupchats ) + { + for( c = ic->groupchats; c->next; c = c->next ); + c = c->next = g_new0( struct groupchat, 1 ); + } + else + ic->groupchats = c = g_new0( struct groupchat, 1 ); + + c->ic = ic; + c->title = g_strdup( handle ); + c->channel = g_strdup_printf( "&chat_%03d", ic->irc->c_id++ ); + c->topic = g_strdup_printf( "BitlBee groupchat: \"%s\". Please keep in mind that root-commands won't work here. Have fun!", c->title ); + + if( set_getbool( &ic->irc->set, "debug" ) ) + imcb_log( ic, "Creating new conversation: (id=%p,handle=%s)", c, handle ); + + return c; +} + void imcb_chat_free( struct groupchat *c ) { struct im_connection *ic = c->ic; @@ -727,11 +752,12 @@ void imcb_chat_free( struct groupchat *c ) g_list_free( c->in_room ); g_free( c->channel ); g_free( c->title ); + g_free( c->topic ); g_free( c ); } } -void imcb_chat_msg( struct groupchat *c, char *who, char *msg, u_int32_t flags, time_t sent_at ) +void imcb_chat_msg( struct groupchat *c, char *who, char *msg, uint32_t flags, time_t sent_at ) { struct im_connection *ic = c->ic; char *wrapped; @@ -759,6 +785,24 @@ void imcb_chat_msg( struct groupchat *c, char *who, char *msg, u_int32_t flags, g_free( wrapped ); } +void imcb_chat_log( struct groupchat *c, char *format, ... ) +{ + irc_t *irc = c->ic->irc; + va_list params; + char *text; + user_t *u; + + va_start( params, format ); + text = g_strdup_vprintf( format, params ); + va_end( params ); + + u = user_find( irc, irc->mynick ); + + irc_privmsg( irc, u, "PRIVMSG", c->channel, "System message: ", text ); + + g_free( text ); +} + void imcb_chat_topic( struct groupchat *c, char *who, char *topic, time_t set_at ) { struct im_connection *ic = c->ic; @@ -782,31 +826,6 @@ void imcb_chat_topic( struct groupchat *c, char *who, char *topic, time_t set_at irc_write( ic->irc, ":%s!%s@%s TOPIC %s :%s", u->nick, u->user, u->host, c->channel, topic ); } -struct groupchat *imcb_chat_new( struct im_connection *ic, char *handle ) -{ - struct groupchat *c; - - /* This one just creates the conversation structure, user won't see anything yet */ - - if( ic->groupchats ) - { - for( c = ic->groupchats; c->next; c = c->next ); - c = c->next = g_new0( struct groupchat, 1 ); - } - else - ic->groupchats = c = g_new0( struct groupchat, 1 ); - - c->ic = ic; - c->title = g_strdup( handle ); - c->channel = g_strdup_printf( "&chat_%03d", ic->irc->c_id++ ); - c->topic = g_strdup_printf( "%s :BitlBee groupchat: \"%s\". Please keep in mind that root-commands won't work here. Have fun!", c->channel, c->title ); - - if( set_getbool( &ic->irc->set, "debug" ) ) - imcb_log( ic, "Creating new conversation: (id=%p,handle=%s)", c, handle ); - - return c; -} - /* buddy_chat.c */ diff --git a/protocols/nogaim.h b/protocols/nogaim.h index f17c5a1e..37232493 100644 --- a/protocols/nogaim.h +++ b/protocols/nogaim.h @@ -68,7 +68,7 @@ struct im_connection { account_t *acc; - u_int32_t flags; + uint32_t flags; /* each connection then can have its own protocol-specific data */ void *proto_data; @@ -285,8 +285,8 @@ G_MODULE_EXPORT void imcb_buddy_nick_hint( struct im_connection *ic, char *handl G_MODULE_EXPORT void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, const char *state, const char *message ); /* Not implemented yet! */ G_MODULE_EXPORT void imcb_buddy_times( struct im_connection *ic, const char *handle, time_t login, time_t idle ); /* Call when a handle says something. 'flags' and 'sent_at may be just 0. */ -G_MODULE_EXPORT void imcb_buddy_msg( struct im_connection *ic, char *handle, char *msg, u_int32_t flags, time_t sent_at ); -G_MODULE_EXPORT void imcb_buddy_typing( struct im_connection *ic, char *handle, u_int32_t flags ); +G_MODULE_EXPORT void imcb_buddy_msg( struct im_connection *ic, char *handle, char *msg, uint32_t flags, time_t sent_at ); +G_MODULE_EXPORT void imcb_buddy_typing( struct im_connection *ic, char *handle, uint32_t flags ); G_MODULE_EXPORT void imcb_clean_handle( struct im_connection *ic, char *handle ); /* Groupchats */ @@ -302,7 +302,9 @@ G_MODULE_EXPORT void imcb_chat_add_buddy( struct groupchat *b, char *handle ); /* To remove a handle from a group chat. Reason can be NULL. */ G_MODULE_EXPORT void imcb_chat_remove_buddy( struct groupchat *b, char *handle, char *reason ); /* To tell BitlBee 'who' said 'msg' in 'c'. 'flags' and 'sent_at' can be 0. */ -G_MODULE_EXPORT void imcb_chat_msg( struct groupchat *c, char *who, char *msg, u_int32_t flags, time_t sent_at ); +G_MODULE_EXPORT void imcb_chat_msg( struct groupchat *c, char *who, char *msg, uint32_t flags, time_t sent_at ); +/* System messages specific to a groupchat, so they can be displayed in the right context. */ +G_MODULE_EXPORT void imcb_chat_log( struct groupchat *c, char *format, ... ) G_GNUC_PRINTF( 2, 3 ); /* To tell BitlBee 'who' changed the topic of 'c' to 'topic'. */ G_MODULE_EXPORT void imcb_chat_topic( struct groupchat *c, char *who, char *topic, time_t set_at ); G_MODULE_EXPORT void imcb_chat_free( struct groupchat *c ); diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c index c4683046..9e5de70a 100644 --- a/protocols/oscar/oscar.c +++ b/protocols/oscar/oscar.c @@ -90,6 +90,8 @@ struct oscar_data { gboolean killme; gboolean icq; GSList *evilhack; + + GHashTable *ips; struct { guint maxbuddies; /* max users you can watch */ @@ -355,9 +357,10 @@ static void oscar_login(account_t *acc) { struct im_connection *ic = imcb_new(acc); struct oscar_data *odata = ic->proto_data = g_new0(struct oscar_data, 1); - if (!isdigit(acc->user[0])) { + if (isdigit(acc->user[0])) + odata->icq = TRUE; + else ic->flags |= OPT_DOES_HTML; - } sess = g_new0(aim_session_t, 1); @@ -410,6 +413,8 @@ static void oscar_logout(struct im_connection *ic) { odata->create_rooms = g_slist_remove(odata->create_rooms, cr); g_free(cr); } + if (odata->ips) + g_hash_table_destroy(odata->ips); if (odata->email) g_free(odata->email); if (odata->newp) @@ -986,6 +991,16 @@ static int gaim_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...) { if (info->present & AIM_USERINFO_PRESENT_SESSIONLEN) signon = time(NULL) - info->sessionlen; + if (info->present & AIM_USERINFO_PRESENT_ICQIPADDR) { + uint32_t *uin = g_new0(uint32_t, 1); + + if (od->ips == NULL) + od->ips = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, NULL); + + if (sscanf(info->sn, "%d", uin) == 1) + g_hash_table_insert(od->ips, uin, (gpointer) (long) info->icqinfo.ipaddr); + } + tmp = g_strdup(normalize(ic->acc->user)); if (!strcmp(tmp, normalize(info->sn))) g_snprintf(ic->displayname, sizeof(ic->displayname), "%s", info->sn); @@ -1050,12 +1065,14 @@ static int incomingim_chan1(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_ } else if (args->mpmsg.numparts == 0) { g_snprintf(tmp, BUF_LONG, "%s", args->msg); } else { - int i; + aim_mpmsg_section_t *part; *tmp = 0; - for (i = 0; i < args->mpmsg.numparts; i ++) { - g_strlcat(tmp, (char*) args->mpmsg.parts[i].data, BUF_LONG); - g_strlcat(tmp, "\n", BUF_LONG); + for (part = args->mpmsg.parts; part; part = part->next) { + if (part->data) { + g_strlcat(tmp, (char*) part->data, BUF_LONG); + g_strlcat(tmp, "\n", BUF_LONG); + } } } @@ -2218,87 +2235,94 @@ static GList *oscar_away_states(struct im_connection *ic) static int gaim_icqinfo(aim_session_t *sess, aim_frame_t *fr, ...) { - struct im_connection *ic = sess->aux_data; - gchar who[16]; - GString *str; - va_list ap; - struct aim_icq_info *info; - - va_start(ap, fr); - info = va_arg(ap, struct aim_icq_info *); - va_end(ap); - - if (!info->uin) - return 0; - - str = g_string_sized_new(100); - g_snprintf(who, sizeof(who), "%u", info->uin); - - g_string_sprintfa(str, "%s: %s - %s: %s", _("UIN"), who, _("Nick"), - info->nick ? info->nick : "-"); - info_string_append(str, "\n", _("First Name"), info->first); - info_string_append(str, "\n", _("Last Name"), info->last); - info_string_append(str, "\n", _("Email Address"), info->email); - if (info->numaddresses && info->email2) { - int i; - for (i = 0; i < info->numaddresses; i++) { - info_string_append(str, "\n", _("Email Address"), info->email2[i]); - } - } - info_string_append(str, "\n", _("Mobile Phone"), info->mobile); - if (info->gender != 0) - info_string_append(str, "\n", _("Gender"), info->gender==1 ? _("Female") : _("Male")); - if (info->birthyear || info->birthmonth || info->birthday) { - char date[30]; - struct tm tm; - tm.tm_mday = (int)info->birthday; - tm.tm_mon = (int)info->birthmonth-1; - tm.tm_year = (int)info->birthyear%100; - strftime(date, sizeof(date), "%Y-%m-%d", &tm); - info_string_append(str, "\n", _("Birthday"), date); - } - if (info->age) { - char age[5]; - g_snprintf(age, sizeof(age), "%hhd", info->age); - info_string_append(str, "\n", _("Age"), age); - } - info_string_append(str, "\n", _("Personal Web Page"), info->personalwebpage); - if (info->info && info->info[0]) { - g_string_sprintfa(str, "\n%s:\n%s\n%s", _("Additional Information"), - info->info, _("End of Additional Information")); - } - g_string_sprintfa(str, "\n"); - if ((info->homeaddr && (info->homeaddr[0])) || (info->homecity && info->homecity[0]) || (info->homestate && info->homestate[0]) || (info->homezip && info->homezip[0])) { - g_string_sprintfa(str, "%s:", _("Home Address")); - info_string_append(str, "\n", _("Address"), info->homeaddr); - info_string_append(str, "\n", _("City"), info->homecity); - info_string_append(str, "\n", _("State"), info->homestate); - info_string_append(str, "\n", _("Zip Code"), info->homezip); - g_string_sprintfa(str, "\n"); - } - if ((info->workaddr && info->workaddr[0]) || (info->workcity && info->workcity[0]) || (info->workstate && info->workstate[0]) || (info->workzip && info->workzip[0])) { - g_string_sprintfa(str, "%s:", _("Work Address")); - info_string_append(str, "\n", _("Address"), info->workaddr); - info_string_append(str, "\n", _("City"), info->workcity); - info_string_append(str, "\n", _("State"), info->workstate); - info_string_append(str, "\n", _("Zip Code"), info->workzip); - g_string_sprintfa(str, "\n"); - } - if ((info->workcompany && info->workcompany[0]) || (info->workdivision && info->workdivision[0]) || (info->workposition && info->workposition[0]) || (info->workwebpage && info->workwebpage[0])) { - g_string_sprintfa(str, "%s:", _("Work Information")); - info_string_append(str, "\n", _("Company"), info->workcompany); - info_string_append(str, "\n", _("Division"), info->workdivision); - info_string_append(str, "\n", _("Position"), info->workposition); - if (info->workwebpage && info->workwebpage[0]) { - info_string_append(str, "\n", _("Web Page"), info->workwebpage); - } - g_string_sprintfa(str, "\n"); - } - - imcb_log(ic, "%s\n%s", _("User Info"), str->str); - g_string_free(str, TRUE); - - return 1; + struct im_connection *ic = sess->aux_data; + struct oscar_data *od = ic->proto_data; + gchar who[16]; + GString *str; + va_list ap; + struct aim_icq_info *info; + uint32_t ip; + + va_start(ap, fr); + info = va_arg(ap, struct aim_icq_info *); + va_end(ap); + + if (!info->uin) + return 0; + + str = g_string_sized_new(512); + g_snprintf(who, sizeof(who), "%u", info->uin); + + g_string_printf(str, "%s: %s - %s: %s", _("UIN"), who, _("Nick"), + info->nick ? info->nick : "-"); + g_string_append_printf(str, "\n%s: %s", _("First Name"), info->first); + g_string_append_printf(str, "\n%s: %s", _("Last Name"), info->last); + g_string_append_printf(str, "\n%s: %s", _("Email Address"), info->email); + if (info->numaddresses && info->email2) { + int i; + for (i = 0; i < info->numaddresses; i++) { + g_string_append_printf(str, "\n%s: %s", _("Email Address"), info->email2[i]); + } + } + if ((ip = (long) g_hash_table_lookup(od->ips, &info->uin)) != 0) { + g_string_append_printf(str, "\n%s: %d.%d.%d.%d", _("Last used IP address"), + (ip >> 24), (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff); + } + g_string_append_printf(str, "\n%s: %s", _("Mobile Phone"), info->mobile); + if (info->gender != 0) + g_string_append_printf(str, "\n%s: %s", _("Gender"), info->gender==1 ? _("Female") : _("Male")); + if (info->birthyear || info->birthmonth || info->birthday) { + char date[30]; + struct tm tm; + memset(&tm, 0, sizeof(struct tm)); + tm.tm_mday = (int)info->birthday; + tm.tm_mon = (int)info->birthmonth-1; + tm.tm_year = (int)info->birthyear%100; + strftime(date, sizeof(date), "%Y-%m-%d", &tm); + g_string_append_printf(str, "\n%s: %s", _("Birthday"), date); + } + if (info->age) { + char age[5]; + g_snprintf(age, sizeof(age), "%hhd", info->age); + g_string_append_printf(str, "\n%s: %s", _("Age"), age); + } + g_string_append_printf(str, "\n%s: %s", _("Personal Web Page"), info->personalwebpage); + if (info->info && info->info[0]) { + g_string_sprintfa(str, "\n%s:\n%s\n%s", _("Additional Information"), + info->info, _("End of Additional Information")); + } + g_string_append_c(str, '\n'); + if ((info->homeaddr && (info->homeaddr[0])) || (info->homecity && info->homecity[0]) || (info->homestate && info->homestate[0]) || (info->homezip && info->homezip[0])) { + g_string_append_printf(str, "%s:", _("Home Address")); + g_string_append_printf(str, "\n%s: %s", _("Address"), info->homeaddr); + g_string_append_printf(str, "\n%s: %s", _("City"), info->homecity); + g_string_append_printf(str, "\n%s: %s", _("State"), info->homestate); + g_string_append_printf(str, "\n%s: %s", _("Zip Code"), info->homezip); + g_string_append_c(str, '\n'); + } + if ((info->workaddr && info->workaddr[0]) || (info->workcity && info->workcity[0]) || (info->workstate && info->workstate[0]) || (info->workzip && info->workzip[0])) { + g_string_append_printf(str, "%s:", _("Work Address")); + g_string_append_printf(str, "\n%s: %s", _("Address"), info->workaddr); + g_string_append_printf(str, "\n%s: %s", _("City"), info->workcity); + g_string_append_printf(str, "\n%s: %s", _("State"), info->workstate); + g_string_append_printf(str, "\n%s: %s", _("Zip Code"), info->workzip); + g_string_append_c(str, '\n'); + } + if ((info->workcompany && info->workcompany[0]) || (info->workdivision && info->workdivision[0]) || (info->workposition && info->workposition[0]) || (info->workwebpage && info->workwebpage[0])) { + g_string_append_printf(str, "%s:", _("Work Information")); + g_string_append_printf(str, "\n%s: %s", _("Company"), info->workcompany); + g_string_append_printf(str, "\n%s: %s", _("Division"), info->workdivision); + g_string_append_printf(str, "\n%s: %s", _("Position"), info->workposition); + if (info->workwebpage && info->workwebpage[0]) { + g_string_append_printf(str, "\n%s: %s", _("Web Page"), info->workwebpage); + } + g_string_append_c(str, '\n'); + } + + imcb_log(ic, "%s\n%s", _("User Info"), str->str); + g_string_free(str, TRUE); + + return 1; } @@ -2432,7 +2456,7 @@ int gaim_parsemtn(aim_session_t *sess, aim_frame_t *fr, ...) else { /* User has stopped typing */ imcb_buddy_typing(ic, sn, 0); - } + } return 1; } diff --git a/protocols/oscar/service.c b/protocols/oscar/service.c index 3a180780..acd09150 100644 --- a/protocols/oscar/service.c +++ b/protocols/oscar/service.c @@ -893,7 +893,7 @@ int aim_sendmemblock(aim_session_t *sess, aim_conn_t *conn, guint32 offset, guin aimbs_put32(&fr->data, 0xecf8427e); */ } else - imcb_error(sess->aux_data, "WARNING: unknown hash request"); + imcb_error(sess->aux_data, "Warning: unknown hash request"); } diff --git a/protocols/oscar/txqueue.c b/protocols/oscar/txqueue.c index 4416025a..d38986d0 100644 --- a/protocols/oscar/txqueue.c +++ b/protocols/oscar/txqueue.c @@ -79,7 +79,7 @@ static int aim_tx_enqueue__queuebased(aim_session_t *sess, aim_frame_t *fr) { if (!fr->conn) { - imcb_error(sess->aux_data, "WARNING: enqueueing packet with no connection"); + imcb_error(sess->aux_data, "Warning: enqueueing packet with no connection"); fr->conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS); } diff --git a/protocols/yahoo/yahoo.c b/protocols/yahoo/yahoo.c index 625f3d1c..9f9ffcf7 100644 --- a/protocols/yahoo/yahoo.c +++ b/protocols/yahoo/yahoo.c @@ -126,6 +126,11 @@ static char *byahoo_strip( const char *in ) return( g_strndup( in, len ) ); } +static void byahoo_init( account_t *acc ) +{ + set_add( &acc->set, "mail_notifications", "false", set_eval_bool, acc ); +} + static void byahoo_login( account_t *acc ) { struct im_connection *ic = imcb_new( acc ); @@ -348,6 +353,7 @@ void byahoo_initmodule( ) { struct prpl *ret = g_new0(struct prpl, 1); ret->name = "yahoo"; + ret->init = byahoo_init; ret->login = byahoo_login; ret->keepalive = byahoo_keepalive; @@ -617,10 +623,14 @@ void ext_yahoo_status_changed( int id, const char *who, int stat, const char *ms void ext_yahoo_got_im( int id, const char *me, const char *who, const char *msg, long tm, int stat, int utf8 ) { struct im_connection *ic = byahoo_get_ic_by_id( id ); - char *m = byahoo_strip( msg ); + char *m; - imcb_buddy_msg( ic, (char*) who, (char*) m, 0, 0 ); - g_free( m ); + if( msg ) + { + m = byahoo_strip( msg ); + imcb_buddy_msg( ic, (char*) who, (char*) m, 0, 0 ); + g_free( m ); + } } void ext_yahoo_got_file( int id, @@ -922,7 +932,9 @@ void ext_yahoo_mail_notify( int id, const char *from, const char *subj, int cnt { struct im_connection *ic = byahoo_get_ic_by_id( id ); - if( from && subj ) + if( !set_getbool( &ic->acc->set, "mail_notifications" ) ) + ; /* The user doesn't care. */ + else if( from && subj ) imcb_log( ic, "Received e-mail message from %s with subject `%s'", from, subj ); else if( cnt > 0 ) imcb_log( ic, "Received %d new e-mails", cnt ); diff --git a/root_commands.c b/root_commands.c index eea16178..30b01b4a 100644 --- a/root_commands.c +++ b/root_commands.c @@ -448,7 +448,7 @@ static void cmd_add( irc_t *irc, char **cmd ) if( g_strcasecmp( cmd[1], "-tmp" ) == 0 ) { add_on_server = 0; - cmd ++; /* So evil... :-D */ + cmd ++; } if( !( a = account_get( irc, cmd[1] ) ) ) @@ -480,12 +480,13 @@ static void cmd_add( irc_t *irc, char **cmd ) } } - /* By making this optional, you can talk to people without having to - add them to your *real* (server-side) contact list. */ if( add_on_server ) a->ic->acc->prpl->add_buddy( a->ic, cmd[2], NULL ); - - /* add_buddy( a->ic, NULL, cmd[2], cmd[2] ); */ + else + /* Yeah, officially this is a call-*back*... So if we just + called add_buddy, we'll wait for the IM server to respond + before we do this. */ + imcb_add_buddy( a->ic, cmd[2], NULL ); irc_usermsg( irc, "Adding `%s' to your contact list", cmd[2] ); } @@ -820,7 +821,7 @@ static void cmd_blist( irc_t *irc, char **cmd ) { if( online == 1 ) { - g_snprintf( s, sizeof( s ) - 1, "%s@%s (%s)", u->user, u->host, u->ic->acc->prpl->name ); + g_snprintf( s, sizeof( s ) - 1, "%s@%s %s(%s)", u->user, u->host, u->ic->acc->prpl->name, u->ic->acc->user ); irc_usermsg( irc, format, u->nick, s, "Online" ); } @@ -831,7 +832,7 @@ static void cmd_blist( irc_t *irc, char **cmd ) { if( away == 1 ) { - g_snprintf( s, sizeof( s ) - 1, "%s@%s (%s)", u->user, u->host, u->ic->acc->prpl->name ); + g_snprintf( s, sizeof( s ) - 1, "%s@%s %s(%s)", u->user, u->host, u->ic->acc->prpl->name, u->ic->acc->user ); irc_usermsg( irc, format, u->nick, s, u->away ); } n_away ++; @@ -841,7 +842,7 @@ static void cmd_blist( irc_t *irc, char **cmd ) { if( offline == 1 ) { - g_snprintf( s, sizeof( s ) - 1, "%s@%s (%s)", u->user, u->host, u->ic->acc->prpl->name ); + g_snprintf( s, sizeof( s ) - 1, "%s@%s %s(%s)", u->user, u->host, u->ic->acc->prpl->name, u->ic->acc->user ); irc_usermsg( irc, format, u->nick, s, "Offline" ); } n_offline ++; diff --git a/storage_text.c b/storage_text.c index 7c29d95a..5ee6438d 100644 --- a/storage_text.c +++ b/storage_text.c @@ -29,10 +29,10 @@ static void text_init (void) { - if( access( global.conf->configdir, F_OK ) != 0 ) - 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 ) - log_message( LOGLVL_WARNING, "Permission problem: Can't read/write from/to %s.", global.conf->configdir ); + /* Don't complain about the configuration directory anymore, leave it + up to the XML storage module, which uses the same directory for it + anyway. Nobody should be using just the text plugin anymore since + it's read only! */ } static storage_status_t text_load ( const char *my_nick, const char* password, irc_t *irc ) diff --git a/storage_xml.c b/storage_xml.c index 4c372cde..19070a74 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -262,9 +262,9 @@ GMarkupParser xml_parser = static void xml_init( void ) { if( access( global.conf->configdir, F_OK ) != 0 ) - log_message( LOGLVL_WARNING, "The configuration directory %s does not exist. Configuration won't be saved.", global.conf->configdir ); + 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 ) - log_message( LOGLVL_WARNING, "Permission problem: Can't read/write from/to %s.", global.conf->configdir ); + log_message( LOGLVL_WARNING, "Permission problem: Can't read/write from/to `%s'.", global.conf->configdir ); } static storage_status_t xml_load_real( const char *my_nick, const char *password, irc_t *irc, xml_pass_st action ) @@ -46,7 +46,7 @@ int main( int argc, char *argv[], char **envp ) struct sigaction sig, old; log_init(); - CONF_FILE = g_strdup( CONF_FILE_DEF ); + global.conf_file = g_strdup( CONF_FILE_DEF ); global.conf = conf_load( argc, argv ); if( global.conf == NULL ) return( 1 ); @@ -123,11 +123,14 @@ int main( int argc, char *argv[], char **envp ) if( !getuid() || !geteuid() ) log_message( LOGLVL_WARNING, "BitlBee is running with root privileges. Why?" ); - if( help_init( &(global.help), global.helpfile ) == NULL ) + if( help_init( &global.help, global.helpfile ) == NULL ) log_message( LOGLVL_WARNING, "Error opening helpfile %s.", HELP_FILE ); b_main_run(); + /* Mainly good for restarting, to make sure we close the help.txt fd. */ + help_free( &global.help ); + if( global.restart ) { char *fn = ipc_master_save_state(); @@ -196,9 +199,9 @@ static void sighandler( int signal ) while( ( pid = waitpid( 0, &st, WNOHANG ) ) > 0 ) { if( WIFSIGNALED( st ) ) - log_message( LOGLVL_INFO, "Client %d terminated normally. (status = %d)", pid, WEXITSTATUS( st ) ); + log_message( LOGLVL_INFO, "Client %d terminated normally. (status = %d)", (int) pid, WEXITSTATUS( st ) ); else if( WIFEXITED( st ) ) - log_message( LOGLVL_INFO, "Client %d killed by signal %d.", pid, WTERMSIG( st ) ); + log_message( LOGLVL_INFO, "Client %d killed by signal %d.", (int) pid, WTERMSIG( st ) ); } } else if( signal != SIGPIPE ) |