aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Moritz Hallberg <sm@khjk.org>2008-02-16 18:15:31 +0100
committerSven Moritz Hallberg <sm@khjk.org>2008-02-16 18:15:31 +0100
commit4eb4c0f4beeb87e07bd6b10daed8fe8e48fb4206 (patch)
treea54ec7b6b4622aa35ef7bd1efc58ab8ec45749ae
parent896195002cc903ec4b1ef7e1468f73c1dc08df9e (diff)
parentca605509d0b49e6012d10ae5d1553ced007e6ce7 (diff)
merge in upstream changes
-rw-r--r--Makefile1
-rw-r--r--bitlbee.c6
-rw-r--r--bitlbee.h9
-rw-r--r--conf.c45
-rw-r--r--crypting.c5
-rw-r--r--debian/watch2
-rw-r--r--help.c66
-rw-r--r--help.h5
-rw-r--r--irc.c16
-rw-r--r--irc.h1
-rw-r--r--irc_commands.c4
-rw-r--r--lib/Makefile2
-rw-r--r--protocols/Makefile2
-rw-r--r--protocols/jabber/Makefile2
-rw-r--r--protocols/jabber/conference.c11
-rw-r--r--protocols/jabber/iq.c3
-rw-r--r--protocols/jabber/jabber.h20
-rw-r--r--protocols/jabber/jabber_util.c16
-rw-r--r--protocols/jabber/presence.c34
-rw-r--r--protocols/jabber/sasl.c27
-rw-r--r--protocols/msn/Makefile2
-rw-r--r--protocols/msn/ns.c2
-rw-r--r--protocols/msn/sb.c2
-rw-r--r--protocols/oscar/Makefile2
-rw-r--r--protocols/oscar/oscar.c10
-rw-r--r--protocols/yahoo/Makefile2
-rw-r--r--root_commands.c11
-rw-r--r--storage_text.c8
-rw-r--r--storage_xml.c4
-rw-r--r--tests/Makefile4
-rw-r--r--tests/check.c4
-rw-r--r--tests/check_arc.c5
-rw-r--r--tests/check_jabber_sasl.c117
-rw-r--r--unix.c7
34 files changed, 332 insertions, 125 deletions
diff --git a/Makefile b/Makefile
index 10c671d9..ffd43ae5 100644
--- a/Makefile
+++ b/Makefile
@@ -49,7 +49,6 @@ distclean: clean $(subdirs)
check: all
$(MAKE) -C tests
-lcov:
gcov: check
gcov *.c
diff --git a/bitlbee.c b/bitlbee.c
index 8785ecf0..52acafa4 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 )
diff --git a/bitlbee.h b/bitlbee.h
index b60d4b90..7f5da5f2 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"
@@ -139,6 +143,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 f87eb983..f9835a27 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->user = NULL;
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 )
@@ -261,7 +264,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;
}
@@ -270,7 +273,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;
}
@@ -282,7 +285,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 ) );
@@ -306,7 +309,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... */
}
}
@@ -314,19 +317,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/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/debian/watch b/debian/watch
new file mode 100644
index 00000000..66ab4504
--- /dev/null
+++ b/debian/watch
@@ -0,0 +1,2 @@
+version=2
+http://get.bitlbee.org/src/bitlbee-(.*).tar.gz
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/irc.c b/irc.c
index 3ea0d755..ae275216 100644
--- a/irc.c
+++ b/irc.c
@@ -76,7 +76,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 ) );
}
@@ -87,7 +87,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 ) );
}
@@ -198,7 +198,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 );
@@ -275,17 +274,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);
- }
- }
-
otr_free(irc->otr);
g_free(irc);
diff --git a/irc.h b/irc.h
index e9f47082..de11e226 100644
--- a/irc.h
+++ b/irc.h
@@ -90,7 +90,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/Makefile b/lib/Makefile
index a79f7c4c..975deceb 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -17,7 +17,7 @@ LFLAGS += -r
# [SH] Phony targets
all: lib.o
check: all
-lcov:
+lcov: check
gcov:
gcov *.c
diff --git a/protocols/Makefile b/protocols/Makefile
index f7d76e0f..18d79e8d 100644
--- a/protocols/Makefile
+++ b/protocols/Makefile
@@ -26,7 +26,7 @@ LFLAGS += -r
# [SH] Phony targets
all: protocols.o
check: all
-lcov:
+lcov: check
gcov:
gcov *.c
diff --git a/protocols/jabber/Makefile b/protocols/jabber/Makefile
index e042f812..3ce78127 100644
--- a/protocols/jabber/Makefile
+++ b/protocols/jabber/Makefile
@@ -17,7 +17,7 @@ LFLAGS += -r
# [SH] Phony targets
all: jabber_mod.o
check: all
-lcov:
+lcov: check
gcov:
gcov *.c
diff --git a/protocols/jabber/conference.c b/protocols/jabber/conference.c
index 515194fc..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 ) )
@@ -122,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 );
@@ -294,10 +298,11 @@ 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 = NULL;
+ 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;
@@ -345,7 +350,7 @@ void jabber_chat_pkt_message( struct im_connection *ic, struct jabber_buddy *bud
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/iq.c b/protocols/jabber/iq.c
index e1bab29e..c88bc0b0 100644
--- a/protocols/jabber/iq.c
+++ b/protocols/jabber/iq.c
@@ -91,7 +91,8 @@ xt_status jabber_pkt_iq( struct xt_node *node, gpointer data )
}
else if( strcmp( s, XMLNS_DISCOVER ) == 0 )
{
- const char *features[] = { XMLNS_VERSION,
+ const char *features[] = { XMLNS_DISCOVER,
+ XMLNS_VERSION,
XMLNS_TIME,
XMLNS_CHATSTATES,
XMLNS_MUC,
diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h
index cf0f8e6a..1ff0e8dd 100644
--- a/protocols/jabber/jabber.h
+++ b/protocols/jabber/jabber.h
@@ -48,16 +48,22 @@ 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;
+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;
@@ -94,6 +100,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;
};
@@ -140,6 +147,10 @@ struct jabber_chat
#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"
@@ -160,6 +171,7 @@ struct jabber_chat
#define XMLNS_DISCOVER "http://jabber.org/protocol/disco#info" /* 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 */
/* iq.c */
xt_status jabber_pkt_iq( struct xt_node *node, gpointer data );
diff --git a/protocols/jabber/jabber_util.c b/protocols/jabber/jabber_util.c
index 794a1040..6e872040 100644
--- a/protocols/jabber/jabber_util.c
+++ b/protocols/jabber/jabber_util.c
@@ -141,6 +141,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 );
}
@@ -162,22 +163,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 )
diff --git a/protocols/jabber/presence.c b/protocols/jabber/presence.c
index 2c49b800..6fc360b7 100644
--- a/protocols/jabber/presence.c
+++ b/protocols/jabber/presence.c
@@ -28,7 +28,7 @@ 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 xt_node *c, *cap;
struct jabber_buddy *bud, *send_presence = NULL;
int is_chat = 0;
char *s;
@@ -76,6 +76,26 @@ 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
@@ -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/jabber/sasl.c b/protocols/jabber/sasl.c
index 87059051..53248ef3 100644
--- a/protocols/jabber/sasl.c
+++ b/protocols/jabber/sasl.c
@@ -21,6 +21,8 @@
* *
\***************************************************************************/
+#include <ctype.h>
+
#include "jabber.h"
#include "base64.h"
@@ -106,12 +108,17 @@ xt_status sasl_pkt_mechanisms( struct xt_node *node, gpointer data )
return XT_HANDLED;
}
-static char *sasl_get_part( char *data, char *field )
+/* Non-static function, but not mentioned in jabber.h because it's for internal
+ use, just that the unittest should be able to reach it... */
+char *sasl_get_part( char *data, char *field )
{
int i, len;
len = strlen( field );
+ while( isspace( *data ) || *data == ',' )
+ data ++;
+
if( g_strncasecmp( data, field, len ) == 0 && data[len] == '=' )
{
i = strlen( field ) + 1;
@@ -128,13 +135,19 @@ static char *sasl_get_part( char *data, char *field )
i ++;
}
- /* If we got a comma, we got a new field. Check it. */
- if( data[i] == ',' &&
- g_strncasecmp( data + i + 1, field, len ) == 0 &&
- data[i+len+1] == '=' )
+ /* If we got a comma, we got a new field. Check it,
+ find the next key after it. */
+ if( data[i] == ',' )
{
- i += len + 2;
- break;
+ while( isspace( data[i] ) || data[i] == ',' )
+ i ++;
+
+ if( g_strncasecmp( data + i, field, len ) == 0 &&
+ data[i+len] == '=' )
+ {
+ i += len + 1;
+ break;
+ }
}
}
}
diff --git a/protocols/msn/Makefile b/protocols/msn/Makefile
index 3440658d..6a588613 100644
--- a/protocols/msn/Makefile
+++ b/protocols/msn/Makefile
@@ -17,7 +17,7 @@ LFLAGS += -r
# [SH] Phony targets
all: msn_mod.o
check: all
-lcov:
+lcov: check
gcov:
gcov *.c
diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c
index 3735aad6..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 );
diff --git a/protocols/msn/sb.c b/protocols/msn/sb.c
index cdf2e8ad..18c41ef5 100644
--- a/protocols/msn/sb.c
+++ b/protocols/msn/sb.c
@@ -593,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/oscar/Makefile b/protocols/oscar/Makefile
index 95e85ec2..2792f22a 100644
--- a/protocols/oscar/Makefile
+++ b/protocols/oscar/Makefile
@@ -17,7 +17,7 @@ LFLAGS += -r
# [SH] Phony targets
all: oscar_mod.o
check: all
-lcov:
+lcov: check
gcov:
gcov *.c
diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c
index 9167f6a3..120ebc3e 100644
--- a/protocols/oscar/oscar.c
+++ b/protocols/oscar/oscar.c
@@ -1065,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);
+ }
}
}
diff --git a/protocols/yahoo/Makefile b/protocols/yahoo/Makefile
index 2cfd147b..b4fe56e2 100644
--- a/protocols/yahoo/Makefile
+++ b/protocols/yahoo/Makefile
@@ -17,7 +17,7 @@ LFLAGS += -r
# [SH] Phony targets
all: yahoo_mod.o
check: all
-lcov:
+lcov: check
gcov:
gcov *.c
diff --git a/root_commands.c b/root_commands.c
index d47a8b1d..5b64052f 100644
--- a/root_commands.c
+++ b/root_commands.c
@@ -453,7 +453,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] ) ) )
@@ -485,12 +485,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] );
}
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/tests/Makefile b/tests/Makefile
index 5bc3fbde..ae76fef5 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -10,9 +10,9 @@ clean:
distclean: clean
-main_objs = account.o bitlbee.o conf.o crypting.o help.o ipc.o irc.o irc_commands.o log.o nick.o query.o root_commands.o set.o storage.o storage_xml.o storage_text.o user.o
+main_objs = account.o bitlbee.o conf.o crypting.o help.o ipc.o irc.o irc_commands.o log.o nick.o query.o root_commands.o set.o storage.o storage_xml.o storage_text.o user.o
-test_objs = check.o check_util.o check_nick.o check_md5.o check_arc.o check_irc.o check_help.o check_user.o check_crypting.o check_set.o
+test_objs = check.o check_util.o check_nick.o check_md5.o check_arc.o check_irc.o check_help.o check_user.o check_crypting.o check_set.o check_jabber_sasl.o
check: $(test_objs) $(addprefix ../, $(main_objs)) ../protocols/protocols.o ../lib/lib.o
@echo '*' Linking $@
diff --git a/tests/check.c b/tests/check.c
index 043889d6..b3ffb957 100644
--- a/tests/check.c
+++ b/tests/check.c
@@ -65,6 +65,9 @@ Suite *crypting_suite(void);
/* From check_set.c */
Suite *set_suite(void);
+/* From check_jabber_sasl.c */
+Suite *jabber_sasl_suite(void);
+
int main (int argc, char **argv)
{
int nf;
@@ -110,6 +113,7 @@ int main (int argc, char **argv)
srunner_add_suite(sr, user_suite());
srunner_add_suite(sr, crypting_suite());
srunner_add_suite(sr, set_suite());
+ srunner_add_suite(sr, jabber_sasl_suite());
if (no_fork)
srunner_set_fork_status(sr, CK_NOFORK);
srunner_run_all (sr, verbose?CK_VERBOSE:CK_NORMAL);
diff --git a/tests/check_arc.c b/tests/check_arc.c
index 989a0a66..a430f899 100644
--- a/tests/check_arc.c
+++ b/tests/check_arc.c
@@ -61,14 +61,15 @@ struct
0xb6, 0x92, 0x59, 0xe4, 0xf9, 0xc1, 0x7a, 0xf6, 0xf3, 0x18, 0xea, 0x28,
0x73, 0x6d, 0xb3, 0x0a, 0x6f, 0x0a, 0x2b, 0x43, 0x57, 0xe9, 0x3e, 0x63
}, 24, "OSCAR is creepy..."
- }
+ },
+ { "", 0, NULL }
};
static void check_decod(int l)
{
int i;
- for( i = 0; clear_tests[i]; i++ )
+ for( i = 0; decrypt_tests[i].len; i++ )
{
tcase_fn_start (decrypt_tests[i].decrypted, __FILE__, __LINE__);
char *decrypted;
diff --git a/tests/check_jabber_sasl.c b/tests/check_jabber_sasl.c
new file mode 100644
index 00000000..96c05837
--- /dev/null
+++ b/tests/check_jabber_sasl.c
@@ -0,0 +1,117 @@
+#include <stdlib.h>
+#include <glib.h>
+#include <gmodule.h>
+#include <check.h>
+#include <string.h>
+#include <stdio.h>
+#include "arc.h"
+
+char *sasl_get_part( char *data, char *field );
+
+#define challenge1 "nonce=\"1669585310\",qop=\"auth\",charset=utf-8,algorithm=md5-sess," \
+ "something=\"Not \\\"standardized\\\"\""
+#define challenge2 "realm=\"quadpoint.org\", nonce=\"NPotlQpQf9RNYodOwierkQ==\", " \
+ "qop=\"auth, auth-int\", charset=utf-8, algorithm=md5-sess"
+#define challenge3 ", realm=\"localhost\", nonce=\"LlBV2txnO8RbB5hgs3KgiQ==\", " \
+ "qop=\"auth, auth-int, \", ,\n, charset=utf-8, algorithm=md5-sess,"
+
+struct
+{
+ const char *challenge;
+ char *key;
+ char *value;
+} get_part_tests[] = {
+ {
+ challenge1,
+ "nonce",
+ "1669585310"
+ },
+ {
+ challenge1,
+ "charset",
+ "utf-8"
+ },
+ {
+ challenge1,
+ "harset",
+ NULL
+ },
+ {
+ challenge1,
+ "something",
+ "Not \"standardized\""
+ },
+ {
+ challenge1,
+ "something_else",
+ NULL
+ },
+ {
+ challenge2,
+ "realm",
+ "quadpoint.org",
+ },
+ {
+ challenge2,
+ "real",
+ NULL
+ },
+ {
+ challenge2,
+ "qop",
+ "auth, auth-int"
+ },
+ {
+ challenge3,
+ "realm",
+ "localhost"
+ },
+ {
+ challenge3,
+ "qop",
+ "auth, auth-int, "
+ },
+ {
+ challenge3,
+ "charset",
+ "utf-8"
+ },
+ { NULL, NULL, NULL }
+};
+
+static void check_get_part(int l)
+{
+ int i;
+
+ for( i = 0; get_part_tests[i].key; i++ )
+ {
+ tcase_fn_start( get_part_tests[i].key, __FILE__, i );
+ char *res;
+ int len;
+
+ res = sasl_get_part( get_part_tests[i].challenge,
+ get_part_tests[i].key );
+
+ if( get_part_tests[i].value == NULL )
+ fail_if( res != NULL, "Found key %s in %s while it shouldn't be there!",
+ get_part_tests[i].key, get_part_tests[i].challenge );
+ else if( res )
+ fail_unless( strcmp( res, get_part_tests[i].value ) == 0,
+ "Incorrect value for key %s in %s: %s",
+ get_part_tests[i].key, get_part_tests[i].challenge, res );
+ else
+ fail( "Could not find key %s in %s",
+ get_part_tests[i].key, get_part_tests[i].challenge );
+
+ g_free( res );
+ }
+}
+
+Suite *jabber_sasl_suite (void)
+{
+ Suite *s = suite_create("jabber/sasl");
+ TCase *tc_core = tcase_create("Core");
+ suite_add_tcase (s, tc_core);
+ tcase_add_test (tc_core, check_get_part);
+ return s;
+}
diff --git a/unix.c b/unix.c
index 63ef7fae..07cb709f 100644
--- a/unix.c
+++ b/unix.c
@@ -47,7 +47,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 );
@@ -125,11 +125,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();