aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--bitlbee.c8
-rw-r--r--bitlbee.h9
-rw-r--r--conf.c45
-rwxr-xr-xconfigure6
-rw-r--r--crypting.c5
-rw-r--r--doc/user-guide/commands.xml11
-rw-r--r--doc/user-guide/quickstart.xml4
-rw-r--r--help.c66
-rw-r--r--help.h5
-rw-r--r--ipc.c6
-rw-r--r--irc.c33
-rw-r--r--irc.h1
-rw-r--r--irc_commands.c4
-rw-r--r--lib/events_glib.c10
-rw-r--r--lib/md5.c185
-rw-r--r--lib/md5.h7
-rw-r--r--lib/misc.c8
-rw-r--r--lib/misc.h1
-rw-r--r--lib/proxy.c21
-rw-r--r--nick.c2
-rw-r--r--protocols/jabber/conference.c66
-rw-r--r--protocols/jabber/io.c10
-rw-r--r--protocols/jabber/iq.c15
-rw-r--r--protocols/jabber/jabber.c11
-rw-r--r--protocols/jabber/jabber.h22
-rw-r--r--protocols/jabber/jabber_util.c44
-rw-r--r--protocols/jabber/presence.c76
-rw-r--r--protocols/msn/msn.c18
-rw-r--r--protocols/msn/msn.h11
-rw-r--r--protocols/msn/msn_util.c34
-rw-r--r--protocols/msn/ns.c6
-rw-r--r--protocols/msn/sb.c97
-rw-r--r--protocols/nogaim.c75
-rw-r--r--protocols/nogaim.h10
-rw-r--r--protocols/oscar/oscar.c200
-rw-r--r--protocols/oscar/service.c2
-rw-r--r--protocols/oscar/txqueue.c2
-rw-r--r--protocols/yahoo/yahoo.c20
-rw-r--r--root_commands.c17
-rw-r--r--storage_text.c8
-rw-r--r--storage_xml.c4
-rw-r--r--unix.c11
43 files changed, 744 insertions, 454 deletions
diff --git a/Makefile b/Makefile
index 1f250420..5d7ce9e0 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/bitlbee.c b/bitlbee.c
index 3f488b46..59a417f0 100644
--- a/bitlbee.c
+++ b/bitlbee.c
@@ -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 );
diff --git a/bitlbee.h b/bitlbee.h
index 23ec64b1..c118d7fc 100644
--- a/bitlbee.h
+++ b/bitlbee.h
@@ -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;
diff --git a/conf.c b/conf.c
index e1a44710..7aac7d9a 100644
--- a/conf.c
+++ b/conf.c
@@ -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 ) )
{
diff --git a/configure b/configure
index 15e22623..22989f60 100755
--- a/configure
+++ b/configure
@@ -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
diff --git a/crypting.c b/crypting.c
index 2a17a913..34b99034 100644
--- a/crypting.c
+++ b/crypting.c
@@ -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>
diff --git a/help.c b/help.c
index 756eb12a..587b9940 100644
--- a/help.c
+++ b/help.c
@@ -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 );
}
diff --git a/help.h b/help.h
index 32aba723..5421220c 100644
--- a/help.h
+++ b/help.h
@@ -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
diff --git a/ipc.c b/ipc.c
index d0d2dff3..384a9c33 100644
--- a/ipc.c
+++ b/ipc.c
@@ -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 );
diff --git a/irc.c b/irc.c
index 736ae863..b0ca18d6 100644
--- a/irc.c
+++ b/irc.c
@@ -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;
}
diff --git a/irc.h b/irc.h
index d581e813..fde19212 100644
--- a/irc.h
+++ b/irc.h
@@ -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)
diff --git a/lib/md5.c b/lib/md5.c
index 08c298a2..3c39eccd 100644
--- a/lib/md5.c
+++ b/lib/md5.c
@@ -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;
diff --git a/lib/md5.h b/lib/md5.h
index 86568b7a..094507b2 100644
--- a/lib/md5.h
+++ b/lib/md5.h
@@ -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;
diff --git a/lib/misc.c b/lib/misc.c
index d6795ec9..18d98f9e 100644
--- a/lib/misc.c
+++ b/lib/misc.c
@@ -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 )
{
diff --git a/lib/misc.h b/lib/misc.h
index e0468d73..7804bfb1 100644
--- a/lib/misc.h
+++ b/lib/misc.h
@@ -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;
}
diff --git a/nick.c b/nick.c
index 4b05f4a7..52f9e5ad 100644
--- a/nick.c
+++ b/nick.c
@@ -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 )
diff --git a/unix.c b/unix.c
index 75ffcf95..d25aeb2e 100644
--- a/unix.c
+++ b/unix.c
@@ -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 )