aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJelmer Vernooij <jelmer@samba.org>2005-12-15 13:24:25 +0100
committerJelmer Vernooij <jelmer@samba.org>2005-12-15 13:24:25 +0100
commitbd69a219c0a618354fd80a98dd0d9a04fee755e0 (patch)
treeb4477537e48c6d7b2e5a261aa860a0688d69fb66
parent2983f5e8c2d3046bf01337e5caefa3af55ba6bff (diff)
parentbf02a679c61b0f030ee8f2f01698699a7775f7d5 (diff)
Merge Wilmer
-rw-r--r--.bzrignore2
-rw-r--r--Makefile2
-rw-r--r--account.c6
-rw-r--r--bitlbee.c256
-rw-r--r--bitlbee.h6
-rw-r--r--commands.c96
-rw-r--r--conf.c11
-rw-r--r--conf.h2
-rwxr-xr-xconfigure26
-rw-r--r--crypting.c101
-rw-r--r--crypting.h10
-rw-r--r--doc/AUTHORS2
-rw-r--r--doc/CHANGES22
-rw-r--r--doc/FAQ26
-rw-r--r--doc/README17
-rw-r--r--doc/TODO40
-rw-r--r--doc/user-guide/user-guide.xml19
-rw-r--r--irc.c25
-rw-r--r--irc.h1
-rw-r--r--nick.c21
-rw-r--r--nick.h12
-rw-r--r--protocols/jabber/jabber.c21
-rw-r--r--protocols/msn/sb.c2
-rw-r--r--protocols/nogaim.c89
-rw-r--r--protocols/nogaim.h8
-rw-r--r--protocols/oscar/aim.h6
-rw-r--r--protocols/oscar/chat.c25
-rw-r--r--protocols/oscar/im.c26
-rw-r--r--protocols/oscar/oscar.c185
-rw-r--r--protocols/oscar/tlv.c25
-rw-r--r--protocols/proxy.c16
-rw-r--r--protocols/proxy.h2
-rw-r--r--protocols/yahoo/crypt.c4
-rw-r--r--protocols/yahoo/libyahoo2.c4
-rw-r--r--protocols/yahoo/yahoo.c10
-rw-r--r--protocols/yahoo/yahoo_httplib.c4
-rw-r--r--protocols/yahoo/yahoo_util.c4
-rw-r--r--storage.c185
-rw-r--r--storage.h66
-rw-r--r--storage_text.c347
-rw-r--r--unix.c17
41 files changed, 1113 insertions, 636 deletions
diff --git a/.bzrignore b/.bzrignore
index ffd468a4..ad4f8534 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -16,3 +16,5 @@ help.txt
debian
build-arch-stamp
tags
+decode
+encode
diff --git a/Makefile b/Makefile
index 73a54ce0..ae86fcf1 100644
--- a/Makefile
+++ b/Makefile
@@ -9,7 +9,7 @@
-include Makefile.settings
# Program variables
-objects = account.o bitlbee.o commands.o crypting.o help.o ini.o irc.o nick.o query.o set.o url.o user.o log.o
+objects = account.o bitlbee.o commands.o crypting.o help.o ini.o irc.o log.o nick.o query.o set.o url.o user.o storage_text.o storage.o
subdirs = protocols
ifeq ($(ARCH),Windows)
diff --git a/account.c b/account.c
index c1e25a06..ed6b98c0 100644
--- a/account.c
+++ b/account.c
@@ -123,12 +123,6 @@ void account_on( irc_t *irc, account_t *a )
return;
}
- if (a->prpl == NULL )
- {
- irc_usermsg( irc, "Support for protocol %s is not included in this BitlBee", a->prpl->name );
- return;
- }
-
cancel_auto_reconnect( a );
u = g_new0 ( struct aim_user, 1 );
diff --git a/bitlbee.c b/bitlbee.c
index 8c51f92c..f55dbfcd 100644
--- a/bitlbee.c
+++ b/bitlbee.c
@@ -26,7 +26,6 @@
#define BITLBEE_CORE
#include "bitlbee.h"
#include "commands.h"
-#include "crypting.h"
#include "protocols/nogaim.h"
#include "help.h"
#include <signal.h>
@@ -158,7 +157,15 @@ gboolean bitlbee_io_current_client_read( GIOChannel *source, GIOCondition condit
irc_free( irc );
return FALSE;
}
-
+
+ /* Very naughty, go read the RFCs! >:) */
+ if( irc->readbuffer && ( strlen( irc->readbuffer ) > 1024 ) )
+ {
+ log_message( LOGLVL_ERROR, "Maximum line length exceeded." );
+ irc_free( irc );
+ return FALSE;
+ }
+
return TRUE;
}
@@ -229,251 +236,6 @@ gboolean bitlbee_io_current_client_write( GIOChannel *source, GIOCondition condi
}
}
-/* DO NOT USE THIS FUNCTION IN NEW CODE. This
- * function is here merely because the save/load code still uses
- * ids rather then names */
-struct prpl *find_protocol_by_id(int id)
-{
- switch (id) {
- case 1: return find_protocol("oscar");
- case 4: return find_protocol("msn");
- case 2: return find_protocol("yahoo");
- case 8: return find_protocol("jabber");
- default: break;
- }
- return NULL;
-}
-
-int bitlbee_load( irc_t *irc, char* password )
-{
- char s[512];
- char *line;
- char proto[20];
- char nick[MAX_NICK_LENGTH+1];
- FILE *fp;
- user_t *ru = user_find( irc, ROOT_NICK );
-
- if( irc->status == USTATUS_IDENTIFIED )
- return( 1 );
-
- g_snprintf( s, 511, "%s%s%s", global.conf->configdir, irc->nick, ".accounts" );
- fp = fopen( s, "r" );
- if( !fp ) return( 0 );
-
- fscanf( fp, "%32[^\n]s", s );
- if( setpass( irc, password, s ) < 0 )
- {
- fclose( fp );
- return( -1 );
- }
-
- /* Do this now. If the user runs with AuthMode = Registered, the
- account command will not work otherwise. */
- irc->status = USTATUS_IDENTIFIED;
-
- while( fscanf( fp, "%511[^\n]s", s ) > 0 )
- {
- fgetc( fp );
- line = deobfucrypt( irc, s );
- root_command_string( irc, ru, line, 0 );
- g_free( line );
- }
- fclose( fp );
-
- g_snprintf( s, 511, "%s%s%s", global.conf->configdir, irc->nick, ".nicks" );
- fp = fopen( s, "r" );
- if( !fp ) return( 0 );
- while( fscanf( fp, "%s %s %s", s, proto, nick ) > 0 )
- {
- struct prpl *prpl;
-
- prpl = find_protocol(proto);
-
- /* Older files saved the protocol number rather then the protocol name */
- if (!prpl && atoi(proto)) {
- prpl = find_protocol_by_id(atoi(proto));
- }
-
- if (!prpl)
- continue;
-
- http_decode( s );
- nick_set( irc, s, prpl, nick );
- }
- fclose( fp );
-
- if( set_getint( irc, "auto_connect" ) )
- {
- strcpy( s, "account on" ); /* Can't do this directly because r_c_s alters the string */
- root_command_string( irc, ru, s, 0 );
- }
-
- return( 1 );
-}
-
-int bitlbee_save( irc_t *irc )
-{
- char s[512];
- char path[512], new_path[512];
- char *line;
- nick_t *n;
- set_t *set;
- mode_t ou = umask( 0077 );
- account_t *a;
- FILE *fp;
- char *hash;
-
- /*\
- * [SH] Nothing should be saved if no password is set, because the
- * password is not set if it was wrong, or if one is not identified
- * yet. This means that a malicious user could easily overwrite
- * files owned by someone else:
- * a Bad Thing, methinks
- \*/
-
- /* [WVG] No? Really? */
-
- /*\
- * [SH] Okay, okay, it wasn't really Wilmer who said that, it was
- * me. I just thought it was funny.
- \*/
-
- hash = hashpass( irc );
- if( hash == NULL )
- {
- irc_usermsg( irc, "Please register yourself if you want to save your settings." );
- return( 0 );
- }
-
- g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".nicks~" );
- fp = fopen( path, "w" );
- if( !fp ) return( 0 );
- for( n = irc->nicks; n; n = n->next )
- {
- strcpy( s, n->handle );
- s[169] = 0; /* Prevent any overflow (169 ~ 512 / 3) */
- http_encode( s );
- g_snprintf( s + strlen( s ), 510 - strlen( s ), " %s %s", n->proto->name, n->nick );
- if( fprintf( fp, "%s\n", s ) != strlen( s ) + 1 )
- {
- irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
- fclose( fp );
- return( 0 );
- }
- }
- if( fclose( fp ) != 0 )
- {
- irc_usermsg( irc, "fclose() reported an error. Disk full?" );
- return( 0 );
- }
-
- g_snprintf( new_path, 512, "%s%s%s", global.conf->configdir, irc->nick, ".nicks" );
- if( unlink( new_path ) != 0 )
- {
- if( errno != ENOENT )
- {
- irc_usermsg( irc, "Error while removing old .nicks file" );
- return( 0 );
- }
- }
- if( rename( path, new_path ) != 0 )
- {
- irc_usermsg( irc, "Error while renaming new .nicks file" );
- return( 0 );
- }
-
- g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".accounts~" );
- fp = fopen( path, "w" );
- if( !fp ) return( 0 );
- if( fprintf( fp, "%s", hash ) != strlen( hash ) )
- {
- irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
- fclose( fp );
- return( 0 );
- }
- g_free( hash );
-
- for( a = irc->accounts; a; a = a->next )
- {
- if( !strcmp( a->prpl->name, "oscar" ) )
- g_snprintf( s, sizeof( s ), "account add oscar \"%s\" \"%s\" %s", a->user, a->pass, a->server );
- else
- g_snprintf( s, sizeof( s ), "account add %s \"%s\" \"%s\" \"%s\"",
- a->prpl->name, a->user, a->pass, a->server ? a->server : "" );
-
- line = obfucrypt( irc, s );
- if( *line )
- {
- if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 )
- {
- irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
- fclose( fp );
- return( 0 );
- }
- }
- g_free( line );
- }
-
- for( set = irc->set; set; set = set->next )
- {
- if( set->value && set->def )
- {
- g_snprintf( s, sizeof( s ), "set %s \"%s\"", set->key, set->value );
- line = obfucrypt( irc, s );
- if( *line )
- {
- if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 )
- {
- irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
- fclose( fp );
- return( 0 );
- }
- }
- g_free( line );
- }
- }
-
- if( strcmp( irc->mynick, ROOT_NICK ) != 0 )
- {
- g_snprintf( s, sizeof( s ), "rename %s %s", ROOT_NICK, irc->mynick );
- line = obfucrypt( irc, s );
- if( *line )
- {
- if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 )
- {
- irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
- fclose( fp );
- return( 0 );
- }
- }
- g_free( line );
- }
- if( fclose( fp ) != 0 )
- {
- irc_usermsg( irc, "fclose() reported an error. Disk full?" );
- return( 0 );
- }
-
- g_snprintf( new_path, 512, "%s%s%s", global.conf->configdir, irc->nick, ".accounts" );
- if( unlink( new_path ) != 0 )
- {
- if( errno != ENOENT )
- {
- irc_usermsg( irc, "Error while removing old .accounts file" );
- return( 0 );
- }
- }
- if( rename( path, new_path ) != 0 )
- {
- irc_usermsg( irc, "Error while renaming new .accounts file" );
- return( 0 );
- }
-
- umask( ou );
-
- return( 1 );
-}
-
void bitlbee_shutdown( gpointer data )
{
/* Try to save data for all active connections (if desired). */
diff --git a/bitlbee.h b/bitlbee.h
index e4cc2868..41247270 100644
--- a/bitlbee.h
+++ b/bitlbee.h
@@ -29,7 +29,7 @@
#define _GNU_SOURCE /* Stupid GNU :-P */
#define PACKAGE "BitlBee"
-#define BITLBEE_VERSION "1.0pre"
+#define BITLBEE_VERSION "BZR"
#define VERSION BITLBEE_VERSION
#define MAX_STRING 128
@@ -99,6 +99,7 @@
extern char *CONF_FILE;
#include "irc.h"
+#include "storage.h"
#include "set.h"
#include "protocols/nogaim.h"
#include "commands.h"
@@ -114,6 +115,7 @@ typedef struct global_t {
int listen_socket;
help_t *help;
conf_t *conf;
+ GList *storage; /* The first backend in the list will be used for saving */
char *helpfile;
GMainLoop *loop;
} global_t;
@@ -126,8 +128,6 @@ gboolean bitlbee_io_current_client_write( GIOChannel *source, GIOCondition condi
int root_command_string( irc_t *irc, user_t *u, char *command, int flags );
int root_command( irc_t *irc, char *command[] );
-int bitlbee_load( irc_t *irc, char *password );
-int bitlbee_save( irc_t *irc );
void bitlbee_shutdown( gpointer data );
double gettime( void );
G_MODULE_EXPORT void http_encode( char *s );
diff --git a/commands.c b/commands.c
index e099d635..fe1607c4 100644
--- a/commands.c
+++ b/commands.c
@@ -85,54 +85,47 @@ int cmd_help( irc_t *irc, char **cmd )
int cmd_identify( irc_t *irc, char **cmd )
{
- int checkie = bitlbee_load( irc, cmd[1] );
+ storage_status_t status = storage_load( irc->nick, cmd[1], irc );
- if( checkie == -1 )
- {
+ switch (status) {
+ case STORAGE_INVALID_PASSWORD:
irc_usermsg( irc, "Incorrect password" );
- }
- else if( checkie == 0 )
- {
+ break;
+ case STORAGE_NO_SUCH_USER:
irc_usermsg( irc, "The nick is (probably) not registered" );
- }
- else if( checkie == 1 )
- {
+ break;
+ case STORAGE_OK:
irc_usermsg( irc, "Password accepted" );
- }
- else
- {
+ break;
+ default:
irc_usermsg( irc, "Something very weird happened" );
+ break;
}
-
+
return( 0 );
}
int cmd_register( irc_t *irc, char **cmd )
{
- int checkie;
- char path[512];
-
if( global.conf->authmode == AUTHMODE_REGISTERED )
{
irc_usermsg( irc, "This server does not allow registering new accounts" );
return( 0 );
}
-
- g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".accounts" );
- checkie = access( path, F_OK );
-
- g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".nicks" );
- checkie += access( path, F_OK );
-
- if( checkie == -2 )
- {
- setpassnc( irc, cmd[1] );
- root_command_string( irc, user_find( irc, irc->mynick ), "save", 0 );
- irc->status = USTATUS_IDENTIFIED;
- }
- else
- {
- irc_usermsg( irc, "Nick is already registered" );
+
+ irc_setpass( irc, cmd[1] );
+ switch( storage_save( irc, FALSE )) {
+ case STORAGE_ALREADY_EXISTS:
+ irc_usermsg( irc, "Nick is already registered" );
+ break;
+
+ case STORAGE_OK:
+ irc->status = USTATUS_IDENTIFIED;
+ break;
+
+ default:
+ irc_usermsg( irc, "Error registering" );
+ break;
}
return( 0 );
@@ -140,35 +133,24 @@ int cmd_register( irc_t *irc, char **cmd )
int cmd_drop( irc_t *irc, char **cmd )
{
- char s[512];
- FILE *fp;
+ storage_status_t status;
- g_snprintf( s, 511, "%s%s%s", global.conf->configdir, irc->nick, ".accounts" );
- fp = fopen( s, "r" );
- if( !fp )
- {
+ status = storage_remove (irc->nick, cmd[1]);
+ switch (status) {
+ case STORAGE_NO_SUCH_USER:
irc_usermsg( irc, "That account does not exist" );
return( 0 );
- }
-
- fscanf( fp, "%32[^\n]s", s );
- fclose( fp );
- if( setpass( irc, cmd[1], s ) < 0 )
- {
- irc_usermsg( irc, "Incorrect password" );
+ case STORAGE_INVALID_PASSWORD:
+ irc_usermsg( irc, "Password invalid" );
+ return( 0 );
+ case STORAGE_OK:
+ irc_setpass( irc, NULL );
+ irc_usermsg( irc, "Account `%s' removed", irc->nick );
+ return( 0 );
+ default:
+ irc_usermsg( irc, "Error: '%d'", status );
return( 0 );
}
-
- g_snprintf( s, 511, "%s%s%s", global.conf->configdir, irc->nick, ".accounts" );
- unlink( s );
-
- g_snprintf( s, 511, "%s%s%s", global.conf->configdir, irc->nick, ".nicks" );
- unlink( s );
-
- setpassnc( irc, NULL );
- irc_usermsg( irc, "Files belonging to account `%s' removed", irc->nick );
-
- return( 0 );
}
int cmd_account( irc_t *irc, char **cmd )
@@ -622,7 +604,7 @@ int cmd_set( irc_t *irc, char **cmd )
int cmd_save( irc_t *irc, char **cmd )
{
- if( bitlbee_save( irc ) )
+ if( storage_save( irc, TRUE ) == STORAGE_OK )
irc_usermsg( irc, "Configuration saved" );
else
irc_usermsg( irc, "Configuration could not be saved!" );
diff --git a/conf.c b/conf.c
index 51b7fbcc..10c6911f 100644
--- a/conf.c
+++ b/conf.c
@@ -49,6 +49,7 @@ conf_t *conf_load( int argc, char *argv[] )
conf->port = 6667;
conf->nofork = 0;
conf->verbose = 0;
+ conf->primary_storage = "text";
conf->runmode = RUNMODE_INETD;
conf->authmode = AUTHMODE_OPEN;
conf->password = NULL;
@@ -197,6 +198,16 @@ static int conf_loadini( conf_t *conf, char *file )
g_free( conf->motdfile );
conf->motdfile = g_strdup( ini->value );
}
+ else if( g_strcasecmp( ini->key, "account_storage" ) == 0 )
+ {
+ g_free( conf->primary_storage );
+ conf->primary_storage = g_strdup( ini->value );
+ }
+ else if( g_strcasecmp( ini->key, "account_storage_migrate" ) == 0 )
+ {
+ g_strfreev( conf->migrate_storage );
+ conf->migrate_storage = g_strsplit( ini->value, " \t,;", -1 );
+ }
else if( g_strcasecmp( ini->key, "pinginterval" ) == 0 )
{
if( sscanf( ini->value, "%d", &i ) != 1 )
diff --git a/conf.h b/conf.h
index e31e0982..ea9de150 100644
--- a/conf.h
+++ b/conf.h
@@ -41,6 +41,8 @@ typedef struct conf
char *hostname;
char *configdir;
char *motdfile;
+ char *primary_storage;
+ char **migrate_storage;
int ping_interval;
int ping_timeout;
} conf_t;
diff --git a/configure b/configure
index 5d478010..e172d40d 100755
--- a/configure
+++ b/configure
@@ -56,7 +56,6 @@ Option Description Default
--debug=0/1 Disable/enable debugging $debug
--strip=0/1 Disable/enable binary stripping $strip
---flood=0/1 Flood protection $flood
--ipv6=0/1 IPv6 socket support $ipv6
--ssl=... SSL library to use (gnutls, nss, openssl, bogus, auto)
@@ -286,7 +285,11 @@ else
fi
if [ "$flood" = 1 ]; then
- echo '#define FLOOD_SEND' >> config.h
+ # echo '#define FLOOD_SEND' >> config.h
+ echo 'Flood protection is disabled in this release because of too many bugs.' 2> /dev/stderr
+ rm config.h
+ rm Makefile.settings
+ exit 1
fi
if [ -n "$BITLBEE_VERSION" ]; then
@@ -344,33 +347,28 @@ echo
echo Architecture: $arch
case "$arch" in
Linux )
- echo 'Linux.'
;;
GNU/* )
- echo 'Debian with non-Linux kernel?'
;;
*BSD )
- echo '*BSD.'
echo 'EFLAGS+=-liconv' >> Makefile.settings;
;;
SunOS )
- echo 'Solaris.'
echo 'EFLAGS+=-lresolv -lnsl -lsocket' >> Makefile.settings
echo 'STRIP=\# skip strip' >> Makefile.settings
echo 'EFLAGS+=-liconv' >> Makefile.settings;
;;
Darwin )
- echo 'Darwin/Mac OS X.'
echo 'EFLAGS+=-liconv' >> Makefile.settings;
;;
IRIX )
- echo 'IRIX.'
;;
CYGWIN* )
echo 'Cygwin is not officially supported.'
;;
* )
- echo 'We haven'\''t tested BitlBee on many platforms yet, yours is untested. YMMV. Please report any problems to <wilmer@gaast.net>.'
+ echo 'We haven'\''t tested BitlBee on many platforms yet, yours is untested. YMMV.'
+ echo 'Please report any problems at http://bugs.bitlbee.org/.'
;;
esac
@@ -393,11 +391,11 @@ if [ "$msn" = "1" ]; then
echo ' Using SSL library: '$ssl;
fi
-if [ "$flood" = "0" ]; then
- echo ' Flood protection disabled.';
-else
- echo ' Flood protection enabled.';
-fi
+#if [ "$flood" = "0" ]; then
+# echo ' Flood protection disabled.';
+#else
+# echo ' Flood protection enabled.';
+#fi
if [ -n "$protocols" ]; then
echo ' Building with these protocols:' $protocols;
diff --git a/crypting.c b/crypting.c
index 4091ed08..5ba47e5b 100644
--- a/crypting.c
+++ b/crypting.c
@@ -28,64 +28,20 @@
included if CRYPTING_MAIN is defined. Or just do "make decode" and
the programs will be built. */
-#ifndef CRYPTING_MAIN
-#define BITLBEE_CORE
-#include "bitlbee.h"
-#include "irc.h"
#include "md5.h"
#include "crypting.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
-#else
-
-typedef struct irc
-{
- char *password;
-} irc_t;
-
-#define set_add( a, b, c, d )
-#define set_find( a, b ) NULL
-
-#include "md5.h"
-#include "crypting.h"
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#define irc_usermsg
-
-#endif
-
/*\
* [SH] Do _not_ call this if it's not entirely sure that it will not cause
* harm to another users file, since this does not check the password for
* correctness.
\*/
-/* USE WITH CAUTION!
- Sets pass without checking */
-void setpassnc (irc_t *irc, char *pass) {
- if (!set_find (irc, "password"))
- set_add (irc, "password", NULL, passchange);
-
- if (irc->password) g_free (irc->password);
-
- if (pass) {
- irc->password = g_strdup (pass);
- irc_usermsg (irc, "Password successfully changed");
- } else {
- irc->password = NULL;
- }
-}
-
-char *passchange (irc_t *irc, void *set, char *value) {
- setpassnc (irc, value);
- return (NULL);
-}
-
-int setpass (irc_t *irc, char *pass, char* md5sum) {
+int checkpass (const char *pass, const char *md5sum)
+{
md5_state_t md5state;
md5_byte_t digest[16];
int i, j;
@@ -102,27 +58,25 @@ int setpass (irc_t *irc, char *pass, char* md5sum) {
if (digits[0] != md5sum[j]) return (-1);
if (digits[1] != md5sum[j + 1]) return (-1);
}
-
- /* If pass is correct, we end up here and we set the pass */
- setpassnc (irc, pass);
-
- return (0);
+
+ return( 0 );
}
-char *hashpass (irc_t *irc) {
+
+char *hashpass (const char *password)
+{
md5_state_t md5state;
md5_byte_t digest[16];
int i;
char digits[3];
char *rv;
- if (irc->password == NULL) return (NULL);
+ if (password == NULL) return (NULL);
- rv = (char *)g_malloc (33);
- memset (rv, 0, 33);
+ rv = g_new0 (char, 33);
md5_init (&md5state);
- md5_append (&md5state, (unsigned char *)irc->password, strlen (irc->password));
+ md5_append (&md5state, (const unsigned char *)password, strlen (password));
md5_finish (&md5state, digest);
for (i = 0; i < 16; i++) {
@@ -134,47 +88,46 @@ char *hashpass (irc_t *irc) {
return (rv);
}
-char *obfucrypt (irc_t *irc, char *line) {
+char *obfucrypt (char *line, const char *password)
+{
int i, j;
char *rv;
- if (irc->password == NULL) return (NULL);
+ if (password == NULL) return (NULL);
- rv = (char *)g_malloc (strlen (line) + 1);
- memset (rv, '\0', strlen (line) + 1);
+ rv = g_new0 (char, strlen (line) + 1);
i = j = 0;
while (*line) {
/* Encrypt/obfuscate the line, using the password */
if (*(signed char*)line < 0) *line = - (*line);
- if (((signed char*)irc->password)[i] < 0) irc->password[i] = - irc->password[i];
- rv[j] = *line + irc->password[i]; /* Overflow intended */
+ rv[j] = *line + password[i]; /* Overflow intended */
line++;
- if (!irc->password[++i]) i = 0;
+ if (!password[++i]) i = 0;
j++;
}
return (rv);
}
-char *deobfucrypt (irc_t *irc, char *line) {
+char *deobfucrypt (char *line, const char *password)
+{
int i, j;
char *rv;
- if (irc->password == NULL) return (NULL);
+ if (password == NULL) return (NULL);
- rv = (char *)g_malloc (strlen (line) + 1);
- memset (rv, '\0', strlen (line) + 1);
+ rv = g_new0 (char, strlen (line) + 1);
i = j = 0;
while (*line) {
/* Decrypt/deobfuscate the line, using the pass */
- rv[j] = *line - irc->password[i]; /* Overflow intended */
+ rv[j] = *line - password[i]; /* Overflow intended */
line++;
- if (!irc->password[++i]) i = 0;
+ if (!password[++i]) i = 0;
j++;
}
@@ -188,9 +141,8 @@ char *deobfucrypt (irc_t *irc, char *line) {
int main( int argc, char *argv[] )
{
- irc_t *irc = g_malloc( sizeof( irc_t ) );
char *hash, *action, line[256];
- char* (*func)( irc_t *, char * );
+ char* (*func)( char *, const char * );
if( argc < 2 )
{
@@ -200,10 +152,7 @@ int main( int argc, char *argv[] )
return( 1 );
}
- memset( irc, 0, sizeof( irc_t ) );
- irc->password = g_strdup( argv[1] );
-
- hash = hashpass( irc );
+ hash = hashpass( argv[1] );
action = argv[0] + strlen( argv[0] ) - strlen( "encode" );
if( strcmp( action, "encode" ) == 0 )
@@ -235,7 +184,7 @@ int main( int argc, char *argv[] )
/* Flush the newline */
fgetc( stdin );
- out = func( irc, line );
+ out = func( line, argv[1] );
printf( "%s\n", out );
g_free( out );
}
diff --git a/crypting.h b/crypting.h
index 0d4f0873..fbaa7dcc 100644
--- a/crypting.h
+++ b/crypting.h
@@ -23,9 +23,7 @@
Suite 330, Boston, MA 02111-1307 USA
*/
-void setpassnc (irc_t *irc, char *pass); /* USE WITH CAUTION! */
-char *passchange (irc_t *irc, void *set, char *value);
-int setpass (irc_t *irc, char *pass, char* md5sum);
-char *hashpass (irc_t *irc);
-char *obfucrypt (irc_t *irc, char *line);
-char *deobfucrypt (irc_t *irc, char *line);
+int checkpass (const char *password, const char *md5sum);
+char *hashpass (const char *password);
+char *obfucrypt (char *line, const char *password);
+char *deobfucrypt (char *line, const char *password);
diff --git a/doc/AUTHORS b/doc/AUTHORS
index 82d81862..6dab1040 100644
--- a/doc/AUTHORS
+++ b/doc/AUTHORS
@@ -3,7 +3,7 @@ Current developers:
Wilmer van der Gaast <wilmer@gaast.net>
Main developer
-Jelmer 'ctrlsoft' Vernooij <jelmer@nl.linux.org>
+Jelmer 'ctrlsoft' Vernooij <jelmer@samba.org>
Documentation, general hacking, Win32 port
Maurits Dijkstra <mauritsd@xs4all.nl>
diff --git a/doc/CHANGES b/doc/CHANGES
index 2981a378..7b95e8cb 100644
--- a/doc/CHANGES
+++ b/doc/CHANGES
@@ -10,8 +10,26 @@ Version 1.0:
- Cleaned up some unnecessary code in the Jabber module, and implemented
handlers for headline messages (which allows you to use RSS-to-Jabber
gateways).
-
-Finished ...
+- Lowered the line splitting limit a bit to fix data loss issues.
+- The $proto($handle) format used for messages specific to one IM-connection
+ now only include the ($handle) part when there's more than one $proto-
+ connection.
+- Fix for a crash-bug on broken Jabber/SSL connections.
+- Incoming typing notifications now also come in as CTCP TYPING messages, for
+ better consistency. Don't forget to update your scripts!
+- AIM typing notifications are supported now.
+- Jabber module only accepts ports 5220-5229 now, to prevent people from
+ abusing it as a port scanner. We aren't aware of any Jabber server that
+ runs on other ports than those. If you are, please warn us.
+- Send flood protection can't be enabled anymore. It was disabled by default
+ for a good reason for some time already, but some package maintainers
+ turned it back on while it's way too unreliable and trigger-happy to be
+ used.
+- Removed TODO file, the current to-do list is always in the on-line bug
+ tracking system.
+- Fixed a potential DoS bug in input handling.
+
+Finished 4 Dec 2005
Version 0.99:
- Fixed memory initialization bug in OSCAR module that caused crashes on
diff --git a/doc/FAQ b/doc/FAQ
index 2b0ed439..a47e066e 100644
--- a/doc/FAQ
+++ b/doc/FAQ
@@ -38,30 +38,18 @@ A: 'root' is just the name for the most powerful user in BitlBee. Just like
artistic creativity.
Q: When is $random_feature going to be implemented?
-A: Please do consult doc/TODO (preferably in a development snapshot, which
- is more up-to-date than a TODO in a release version) before asking.
- Please also check the documentation. You'd not be the first one to request
- a feature which already exists!
-
- If your fabulous feature seems not to be requested before, just join
- #bitlbee on irc.oftc.net and tell us the news.
-
- If your feature request is already in the TODO list, of course you can
- still request it again/make us know that you'd like to see the feature as
- well. But when the feature is in the "post-1.0" list, it's probably not
- going to help. Most of the features in this list are low-priority because
- we (the developers) don't need (or even want) them. (File transfers are a
- good example here.)
- Hence, they'll only be implemented when we really got too much spare
- time. Obviously, if you're willing to help (i.e. submit a patch), you're
- always welcome.
+A: It depends on the feature. We keep a list of all wishlist "bugs" in our
+ Bug Tracking system at http://bugs.bitlbee.org/
Q: The messages I send and/or receive look weird. I see weird characters and
annoying HTML codes. Or, BitlBee does evil things when I send messages with
non-ASCII characters!
A: You probably have to change some settings. To get rid of HTML in messages,
- see "help set html". If you seem to have problems with your charset, see
- "help set charset".
+ see "help set strip_html". If you seem to have problems with your charset,
+ see "help set charset".
+
+ Although actually most of these problems should be gone by now. So if you
+ can't get things to work well, you might have found a bug.
Q: Is BitlBee forked from Gaim?
A: BitlBee 0.7 was, sort-of. It contained a lot of code from Gaim 0.58
diff --git a/doc/README b/doc/README
index cb160b88..cd0085ff 100644
--- a/doc/README
+++ b/doc/README
@@ -107,11 +107,10 @@ not daemons).
See utils/bitlbeed.c for more information about the program.
-Just a little note: We run our public server im.bitlbee.org for a couple of
-months now, and so far we haven't experienced this problem yet. The only
-BitlBee processes killed because of CPU-time overuse were running for a long
-time already, they were usually killed during the MSN login process (which
-is quite CPU-time consuming).
+Just a little note: Now that we reach version 1.0, this shouldn't be that
+much of an issue anymore. However, on a public server, especially if you
+also use it for other things, it can't hurt to protect yourself against
+possible problems.
USAGE
@@ -145,6 +144,12 @@ WEBSITE
You can find new releases of BitlBee at:
http://www.bitlbee.org/
+The bug tracking system:
+http://bugs.bitlbee.org/
+
+Our version control system is Bazaar-NG. Our repository is at:
+http://code.bitlbee.org/
+
A NOTE ON ENCRYPTION
====================
@@ -186,5 +191,5 @@ also licensed under the GPL.
BitlBee - An IRC to other chat networks gateway
<http://www.bitlbee.org/>
- Copyright (C) 2002-2004 Wilmer van der Gaast <wilmer@gaast.net>
+ Copyright (C) 2002-2005 Wilmer van der Gaast <wilmer@gaast.net>
and others
diff --git a/doc/TODO b/doc/TODO
deleted file mode 100644
index 3bd241ef..00000000
--- a/doc/TODO
+++ /dev/null
@@ -1,40 +0,0 @@
-TODO for BitlBee:
-
-We're trying to keep a better TODO list now. The priorities here are somewhat
-random, maybe. Or at least they change from time to time. The "After 1.0"
-changes are very low-priority, the "Before 1.0" are "highest" priority, the
-others are changes we'll do when we feel like doing them. They're usually not
-as critical as the "Before 1.0" changes, but still a bit more important than
-"After 1.0".
-
-KNOWN BUGS TO FIX BEFORE 1.0:
-- 100% cpu usage bugs.
- -> They're still there... :-(
-- Check if the IRC send flood protection is reliable now.
- -> Probably not, at least it still causes troubles on logging in for some
- people. Maybe the thresholds aren't okay yet. Logins are just floody,
- nothing we can do about that.
-
-Some time: (mainly features)
-- Rewrite Jabber module - the current one sucks.
-- Test Yahoo! groupchats a bit better, because they still seem to be a bit
- flakey.
- -> There are bug reports from time to time, but we can't do much about
- them, possibly it's more a libyahoo2 problem.
-- Groupchats
- -> Make them work on other nets than MSN/Yahoo as well.
-- Make usernames case-insensitive. (On case-insensitive filesystems this
- change isn't necessary. This one is going to suck with backward-compati-
- bilty...)
- -> We'll probably combine this with the introduction of a better file
- format for userdata.
-- Remind the user of unanswered questions after some time.
-- Maybe a way to send global messages. (for server shutdowns, for example)
-- Away-auto-replies.
-- Allow nick changes.
-
-After 1.0: (mainly toys)
-- File transfers -> DCC
-- SSL support? Persistent connections? Things you can do with a bouncer/proxy.
-- Support for buddy groups.
-- What else?
diff --git a/doc/user-guide/user-guide.xml b/doc/user-guide/user-guide.xml
index eff5998e..5b881fb2 100644
--- a/doc/user-guide/user-guide.xml
+++ b/doc/user-guide/user-guide.xml
@@ -20,24 +20,13 @@
</author>
<legalnotice id="legalnotice">
- <para>
- Permission is granted to copy, distribute and/or modify this
- document under the terms of the <ulink type="help"
- url="gnome-help:fdl"><citetitle>GNU Free Documentation
- License</citetitle></ulink>, Version 1.1 or any later version
- published by the Free Software Foundation with no Invariant
- Sections, no Front-Cover Texts, and no Back-Cover Texts. You
- may obtain a copy of the <citetitle>GNU Free Documentation
- License</citetitle> from the Free Software Foundation by
- visiting <ulink type="http" url="http://www.fsf.org">their
- Web site</ulink> or by writing to: Free Software Foundation,
- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- USA.
- </para>
</legalnotice>
<releaseinfo>
- This is the initial release of the BitlBee User Guide.
+ This is the BitlBee User Guide. For now, the on-line help is
+ the most up-to-date documentation. Although this document shares
+ some parts with the on-line help system, other parts might be
+ very outdated.
</releaseinfo>
</bookinfo>
diff --git a/irc.c b/irc.c
index f5448495..29ac2a11 100644
--- a/irc.c
+++ b/irc.c
@@ -31,6 +31,12 @@ static gboolean irc_userping( gpointer _irc );
GSList *irc_connection_list = NULL;
+static char *passchange (irc_t *irc, void *set, char *value)
+{
+ irc_setpass (irc, value);
+ return (NULL);
+}
+
irc_t *irc_new( int fd )
{
irc_t *irc = g_new0( irc_t, 1 );
@@ -128,6 +134,7 @@ irc_t *irc_new( int fd )
set_add( irc, "strip_html", "true", NULL );
set_add( irc, "to_char", ": ", set_eval_to_char );
set_add( irc, "typing_notice", "false", set_eval_bool );
+ set_add( irc, "password", NULL, passchange);
conf_loaddefaults( irc );
@@ -153,7 +160,7 @@ void irc_free(irc_t * irc)
log_message( LOGLVL_INFO, "Destroying connection with fd %d", irc->fd );
if( irc->status >= USTATUS_IDENTIFIED && set_getint( irc, "save_on_quit" ) )
- if( !bitlbee_save( irc ) )
+ if( storage_save( irc, TRUE ) != STORAGE_OK )
irc_usermsg( irc, "Error while saving settings!" );
if( irc->ping_source_id > 0 )
@@ -260,6 +267,20 @@ void irc_free(irc_t * irc)
g_main_quit( global.loop );
}
+/* USE WITH CAUTION!
+ Sets pass without checking */
+void irc_setpass (irc_t *irc, const char *pass)
+{
+ if (irc->password) g_free (irc->password);
+
+ if (pass) {
+ irc->password = g_strdup (pass);
+ irc_usermsg (irc, "Password successfully changed");
+ } else {
+ irc->password = NULL;
+ }
+}
+
int irc_process( irc_t *irc )
{
char **lines, *temp;
@@ -1509,7 +1530,7 @@ int irc_privmsg( irc_t *irc, user_t *u, char *type, char *to, char *prefix, char
else
{
irc_write( irc, ":%s!%s@%s %s %s :%s%s", u->nick, u->user, u->host,
- type, to, prefix, line );
+ type, to, prefix ? prefix : "", line );
}
line = s + 1;
}
diff --git a/irc.h b/irc.h
index 86aaec5e..9e0500f9 100644
--- a/irc.h
+++ b/irc.h
@@ -136,6 +136,7 @@ void irc_kill( irc_t *irc, user_t *u );
void irc_invite( irc_t *irc, char *nick, char *channel );
void irc_whois( irc_t *irc, char *nick );
int irc_away( irc_t *irc, char *away );
+void irc_setpass( irc_t *irc, const char *pass ); /* USE WITH CAUTION! */
int irc_send( irc_t *irc, char *nick, char *s, int flags );
int irc_privmsg( irc_t *irc, user_t *u, char *type, char *to, char *prefix, char *msg );
diff --git a/nick.c b/nick.c
index 1376f365..771d2288 100644
--- a/nick.c
+++ b/nick.c
@@ -26,7 +26,7 @@
#define BITLBEE_CORE
#include "bitlbee.h"
-void nick_set( irc_t *irc, char *handle, struct prpl *proto, char *nick )
+void nick_set( irc_t *irc, const char *handle, struct prpl *proto, const char *nick )
{
nick_t *m = NULL, *n = irc->nicks;
@@ -55,7 +55,7 @@ void nick_set( irc_t *irc, char *handle, struct prpl *proto, char *nick )
nick_strip( n->nick );
}
-char *nick_get( irc_t *irc, char *handle, struct prpl *proto, const char *realname )
+char *nick_get( irc_t *irc, const char *handle, struct prpl *proto, const char *realname )
{
static char nick[MAX_NICK_LENGTH+1];
nick_t *n = irc->nicks;
@@ -128,7 +128,7 @@ char *nick_get( irc_t *irc, char *handle, struct prpl *proto, const char *realna
return( nick );
}
-void nick_del( irc_t *irc, char *nick )
+void nick_del( irc_t *irc, const char *nick )
{
nick_t *l = NULL, *n = irc->nicks;
@@ -175,9 +175,9 @@ void nick_strip( char * nick )
nick[j++] = '\0';
}
-int nick_ok( char *nick )
+int nick_ok( const char *nick )
{
- char *s;
+ const char *s;
/* Empty/long nicks are not allowed */
if( !*nick || strlen( nick ) > MAX_NICK_LENGTH )
@@ -236,7 +236,7 @@ int nick_uc( char *nick )
return( 1 );
}
-int nick_cmp( char *a, char *b )
+int nick_cmp( const char *a, const char *b )
{
char aa[1024] = "", bb[1024] = "";
@@ -252,12 +252,7 @@ int nick_cmp( char *a, char *b )
}
}
-char *nick_dup( char *nick )
+char *nick_dup( const char *nick )
{
- char *cp;
-
- cp = g_new0 ( char, MAX_NICK_LENGTH + 1 );
- strncpy( cp, nick, MAX_NICK_LENGTH );
-
- return( cp );
+ return g_strndup( nick, MAX_NICK_LENGTH );
}
diff --git a/nick.h b/nick.h
index d48369c6..9ab1ef1e 100644
--- a/nick.h
+++ b/nick.h
@@ -31,13 +31,13 @@ typedef struct __NICK
struct __NICK *next;
} nick_t;
-void nick_set( irc_t *irc, char *handle, struct prpl *proto, char *nick );
-char *nick_get( irc_t *irc, char *handle, struct prpl *proto, const char *realname );
-void nick_del( irc_t *irc, char *nick );
+void nick_set( irc_t *irc, const char *handle, struct prpl *proto, const char *nick );
+char *nick_get( irc_t *irc, const char *handle, struct prpl *proto, const char *realname );
+void nick_del( irc_t *irc, const char *nick );
void nick_strip( char *nick );
-int nick_ok( char *nick );
+int nick_ok( const char *nick );
int nick_lc( char *nick );
int nick_uc( char *nick );
-int nick_cmp( char *a, char *b );
-char *nick_dup( char *nick );
+int nick_cmp( const char *a, const char *b );
+char *nick_dup( const char *nick );
diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c
index 413f77ef..fc419124 100644
--- a/protocols/jabber/jabber.c
+++ b/protocols/jabber/jabber.c
@@ -21,10 +21,6 @@
*
*/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
#ifndef _WIN32
#include <sys/utsname.h>
#endif
@@ -58,6 +54,8 @@
#define DEFAULT_GROUPCHAT "conference.jabber.org"
#define DEFAULT_PORT 5222
#define DEFAULT_PORT_SSL 5223
+#define JABBER_PORT_MIN 5220
+#define JABBER_PORT_MAX 5229
#define JABBER_GROUP "Friends"
@@ -540,11 +538,6 @@ static void gjab_connected_ssl(gpointer data, void *source, GaimInputCondition c
struct jabber_data *jd;
gjconn gjc;
- if (!g_slist_find(get_connections(), gc)) {
- ssl_disconnect(source);
- return;
- }
-
jd = gc->proto_data;
gjc = jd->gjc;
@@ -553,6 +546,11 @@ static void gjab_connected_ssl(gpointer data, void *source, GaimInputCondition c
return;
}
+ if (!g_slist_find(get_connections(), gc)) {
+ ssl_disconnect(source);
+ return;
+ }
+
gjab_connected(data, gjc->fd, cond);
}
@@ -588,6 +586,11 @@ static void gjab_start(gjconn gjc)
port = DEFAULT_PORT;
else if (port == -1 && ssl)
port = DEFAULT_PORT_SSL;
+ else if (port < JABBER_PORT_MIN || port > JABBER_PORT_MAX) {
+ serv_got_crap(GJ_GC(gjc), "For security reasons, the Jabber port number must be in the %d-%d range.", JABBER_PORT_MIN, JABBER_PORT_MAX);
+ STATE_EVT(JCONN_STATE_OFF)
+ return;
+ }
if (server == NULL)
server = g_strdup(gjc->user->server);
diff --git a/protocols/msn/sb.c b/protocols/msn/sb.c
index 793a881e..2f4d05d5 100644
--- a/protocols/msn/sb.c
+++ b/protocols/msn/sb.c
@@ -643,7 +643,7 @@ static int msn_sb_message( gpointer data, char *msg, int msglen, char **cmd, int
if( who )
{
- serv_got_typing( gc, who, 5 );
+ serv_got_typing( gc, who, 5, 1 );
g_free( who );
}
diff --git a/protocols/nogaim.c b/protocols/nogaim.c
index 474b91b2..4966a76f 100644
--- a/protocols/nogaim.c
+++ b/protocols/nogaim.c
@@ -54,6 +54,7 @@ static int remove_chat_buddy_silent( struct conversation *b, char *handle );
GSList *connections;
+#ifdef WITH_PLUGINS
gboolean load_plugin(char *path)
{
void (*init_function) (void);
@@ -75,6 +76,34 @@ gboolean load_plugin(char *path)
return TRUE;
}
+void load_plugins(void)
+{
+ GDir *dir;
+ GError *error = NULL;
+
+ dir = g_dir_open(PLUGINDIR, 0, &error);
+
+ if (dir) {
+ const gchar *entry;
+ char *path;
+
+ while ((entry = g_dir_read_name(dir))) {
+ path = g_build_filename(PLUGINDIR, entry, NULL);
+ if(!path) {
+ log_message(LOGLVL_WARNING, "Can't build path for %s\n", entry);
+ continue;
+ }
+
+ load_plugin(path);
+
+ g_free(path);
+ }
+
+ g_dir_close(dir);
+ }
+}
+#endif
+
/* nogaim.c */
GList *protocols = NULL;
@@ -100,49 +129,30 @@ struct prpl *find_protocol(const char *name)
/* nogaim.c */
void nogaim_init()
{
- GDir *dir;
- GError *error = NULL;
+ extern void msn_init();
+ extern void oscar_init();
+ extern void byahoo_init();
+ extern void jabber_init();
#ifdef WITH_MSN
- extern void msn_init();
msn_init();
#endif
#ifdef WITH_OSCAR
- extern void oscar_init();
oscar_init();
#endif
#ifdef WITH_YAHOO
- extern void byahoo_init();
byahoo_init();
#endif
#ifdef WITH_JABBER
- extern void jabber_init();
jabber_init();
#endif
- dir = g_dir_open(PLUGINDIR, 0, &error);
-
- if (dir) {
- const gchar *entry;
- char *path;
-
- while ((entry = g_dir_read_name(dir))) {
- path = g_build_filename(PLUGINDIR, entry, NULL);
- if(!path) {
- log_message(LOGLVL_WARNING, "Can't build path for %s\n", entry);
- continue;
- }
-
- load_plugin(path);
-
- g_free(path);
- }
-
- g_dir_close(dir);
- }
+#ifdef WITH_PLUGINS
+ load_plugins();
+#endif
}
GSList *get_connections() { return connections; }
@@ -441,7 +451,14 @@ void signoff( struct gaim_connection *gc )
void do_error_dialog( struct gaim_connection *gc, char *msg, char *title )
{
- serv_got_crap( gc, "Error: %s", msg );
+ if( msg && title )
+ serv_got_crap( gc, "Error: %s: %s", title, msg );
+ else if( msg )
+ serv_got_crap( gc, "Error: %s", msg );
+ else if( title )
+ serv_got_crap( gc, "Error: %s", title );
+ else
+ serv_got_crap( gc, "Error" );
}
void do_ask_dialog( struct gaim_connection *gc, char *msg, void *data, void *doit, void *dont )
@@ -726,7 +743,7 @@ void serv_got_im( struct gaim_connection *gc, char *handle, char *msg, guint32 f
/* If there's a newline/space in this string, split up there,
looks a bit prettier. */
- if( ( nl = strrchr( msg, '\n' ) ) || ( nl = strchr( msg, ' ' ) ) )
+ if( ( nl = strrchr( msg, '\n' ) ) || ( nl = strrchr( msg, ' ' ) ) )
{
msg[425] = tmp;
tmp = *nl;
@@ -750,15 +767,25 @@ void serv_got_im( struct gaim_connection *gc, char *handle, char *msg, guint32 f
irc_msgfrom( irc, u->nick, msg );
}
-void serv_got_typing( struct gaim_connection *gc, char *handle, int timeout )
+void serv_got_typing( struct gaim_connection *gc, char *handle, int timeout, int type )
{
user_t *u;
if( !set_getint( gc->irc, "typing_notice" ) )
return;
- if( ( u = user_findhandle( gc, handle ) ) )
- irc_msgfrom( gc->irc, u->nick, "\1TYPING 1\1" );
+ if( ( u = user_findhandle( gc, handle ) ) ) {
+ /* If type is:
+ * 0: user has stopped typing
+ * 1: user is actively typing
+ * 2: user has entered text, but is not actively typing
+ */
+ if (type == 0 || type == 1 || type == 2) {
+ char buf[256];
+ g_snprintf(buf, 256, "\1TYPING %d\1", type);
+ irc_privmsg( gc->irc, u, "PRIVMSG", gc->irc->nick, NULL, buf );
+ }
+ }
}
void serv_got_chat_left( struct gaim_connection *gc, int id )
diff --git a/protocols/nogaim.h b/protocols/nogaim.h
index 3d5006d9..8ec65347 100644
--- a/protocols/nogaim.h
+++ b/protocols/nogaim.h
@@ -306,7 +306,7 @@ G_MODULE_EXPORT void show_got_added( struct gaim_connection *gc, char *id, char
/* server.c */
G_MODULE_EXPORT void serv_got_update( struct gaim_connection *gc, char *handle, int loggedin, int evil, time_t signon, time_t idle, int type, guint caps );
G_MODULE_EXPORT void serv_got_im( struct gaim_connection *gc, char *handle, char *msg, guint32 flags, time_t mtime, gint len );
-G_MODULE_EXPORT void serv_got_typing( struct gaim_connection *gc, char *handle, int timeout );
+G_MODULE_EXPORT void serv_got_typing( struct gaim_connection *gc, char *handle, int timeout, int type );
G_MODULE_EXPORT void serv_got_chat_invite( struct gaim_connection *gc, char *handle, char *who, char *msg, GList *data );
G_MODULE_EXPORT struct conversation *serv_got_joined_chat( struct gaim_connection *gc, int id, char *handle );
G_MODULE_EXPORT void serv_got_chat_in( struct gaim_connection *gc, int id, char *who, int whisper, char *msg, time_t mtime );
@@ -325,12 +325,6 @@ G_MODULE_EXPORT void strip_html( char *msg );
G_MODULE_EXPORT char * escape_html(const char *html);
G_MODULE_EXPORT void info_string_append(GString *str, char *newline, char *name, char *value);
-/* file transfers */
-G_MODULE_EXPORT void ft_progress( struct ft *, int);
-G_MODULE_EXPORT void ft_incoming( struct ft_request * );
-G_MODULE_EXPORT void ft_accepted( struct ft_request *, struct ft *);
-G_MODULE_EXPORT void ft_denied( struct ft_request *, const char *reason);
-
/* prefs.c */
G_MODULE_EXPORT void build_block_list();
G_MODULE_EXPORT void build_allow_list();
diff --git a/protocols/oscar/aim.h b/protocols/oscar/aim.h
index f7bf1a8e..24cd7730 100644
--- a/protocols/oscar/aim.h
+++ b/protocols/oscar/aim.h
@@ -465,6 +465,7 @@ int aim_addtlvtochain_availmsg(aim_tlvlist_t **list, const guint16 type, const c
int aim_addtlvtochain_raw(aim_tlvlist_t **list, const guint16 t, const guint16 l, const guint8 *v);
int aim_addtlvtochain_caps(aim_tlvlist_t **list, const guint16 t, const guint32 caps);
int aim_addtlvtochain_noval(aim_tlvlist_t **list, const guint16 type);
+int aim_addtlvtochain_chatroom(aim_tlvlist_t **list, guint16 type, guint16 exchange, const char *roomname, guint16 instance);
int aim_addtlvtochain_userinfo(aim_tlvlist_t **list, guint16 type, aim_userinfo_t *ui);
int aim_addtlvtochain_frozentlvlist(aim_tlvlist_t **list, guint16 type, aim_tlvlist_t **tl);
int aim_counttlvchain(aim_tlvlist_t **list);
@@ -571,6 +572,11 @@ struct aim_chat_roominfo {
unsigned short instance;
};
+struct aim_chat_invitation {
+ struct gaim_connection * gc;
+ char * name;
+ guint8 exchange;
+};
#define AIM_VISIBILITYCHANGE_PERMITADD 0x05
#define AIM_VISIBILITYCHANGE_PERMITREMOVE 0x06
diff --git a/protocols/oscar/chat.c b/protocols/oscar/chat.c
index 60aabc79..033c2577 100644
--- a/protocols/oscar/chat.c
+++ b/protocols/oscar/chat.c
@@ -183,31 +183,6 @@ int aim_chat_send_im(aim_session_t *sess, aim_conn_t *conn, guint16 flags, const
return 0;
}
-static int aim_addtlvtochain_chatroom(aim_tlvlist_t **list, guint16 type, guint16 exchange, const char *roomname, guint16 instance)
-{
- guint8 *buf;
- int buflen;
- aim_bstream_t bs;
-
- buflen = 2 + 1 + strlen(roomname) + 2;
-
- if (!(buf = g_malloc(buflen)))
- return 0;
-
- aim_bstream_init(&bs, buf, buflen);
-
- aimbs_put16(&bs, exchange);
- aimbs_put8(&bs, strlen(roomname));
- aimbs_putraw(&bs, (guint8 *)roomname, strlen(roomname));
- aimbs_put16(&bs, instance);
-
- aim_addtlvtochain_raw(list, type, aim_bstream_curpos(&bs), buf);
-
- g_free(buf);
-
- return 0;
-}
-
/*
* Join a room of name roomname. This is the first step to joining an
* already created room. It's basically a Service Request for
diff --git a/protocols/oscar/im.c b/protocols/oscar/im.c
index 085687e0..c829d409 100644
--- a/protocols/oscar/im.c
+++ b/protocols/oscar/im.c
@@ -1368,6 +1368,30 @@ static int incomingim_ch1(aim_session_t *sess, aim_module_t *mod, aim_frame_t *r
return ret;
}
+
+static void incomingim_ch2_chat_free(aim_session_t *sess, struct aim_incomingim_ch2_args *args)
+{
+
+ /* XXX aim_chat_roominfo_free() */
+ g_free(args->info.chat.roominfo.name);
+
+ return;
+}
+
+static void incomingim_ch2_chat(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args, aim_bstream_t *servdata)
+{
+
+ /*
+ * Chat room info.
+ */
+ if (servdata)
+ aim_chat_readroominfo(servdata, &args->info.chat.roominfo);
+
+ args->destructor = (void *)incomingim_ch2_chat_free;
+
+ return;
+}
+
static void incomingim_ch2_icqserverrelay_free(aim_session_t *sess, struct aim_incomingim_ch2_args *args)
{
@@ -1616,6 +1640,8 @@ static int incomingim_ch2(aim_session_t *sess, aim_module_t *mod, aim_frame_t *r
if (args.reqclass & AIM_CAPS_ICQSERVERRELAY)
incomingim_ch2_icqserverrelay(sess, mod, rx, snac, userinfo, &args, sdbsptr);
+ else if (args.reqclass & AIM_CAPS_CHAT)
+ incomingim_ch2_chat(sess, mod, rx, snac, userinfo, &args, sdbsptr);
if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c
index 538f47ae..5f19f12b 100644
--- a/protocols/oscar/oscar.c
+++ b/protocols/oscar/oscar.c
@@ -61,7 +61,7 @@
/* Don't know if support for UTF8 is really working. For now it's UTF16 here.
static int gaim_caps = AIM_CAPS_UTF8; */
-static int gaim_caps = AIM_CAPS_INTEROP | AIM_CAPS_ICHAT | AIM_CAPS_ICQSERVERRELAY;
+static int gaim_caps = AIM_CAPS_INTEROP | AIM_CAPS_ICHAT | AIM_CAPS_ICQSERVERRELAY | AIM_CAPS_CHAT;
static guint8 gaim_features[] = {0x01, 0x01, 0x01, 0x02};
struct oscar_data {
@@ -155,7 +155,6 @@ static char *extract_name(const char *name) {
return tmp;
}
-#if 0
static struct chat_connection *find_oscar_chat(struct gaim_connection *gc, int id) {
GSList *g = ((struct oscar_data *)gc->proto_data)->oscar_chats;
struct chat_connection *c = NULL;
@@ -170,7 +169,7 @@ static struct chat_connection *find_oscar_chat(struct gaim_connection *gc, int i
return c;
}
-#endif
+
static struct chat_connection *find_oscar_chat_by_conn(struct gaim_connection *gc,
aim_conn_t *conn) {
@@ -1073,30 +1072,38 @@ static int incomingim_chan1(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_
return 1;
}
+void oscar_accept_chat(gpointer w, struct aim_chat_invitation * inv);
+void oscar_reject_chat(gpointer w, struct aim_chat_invitation * inv);
+
static int incomingim_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args) {
-#if 0
struct gaim_connection *gc = sess->aux_data;
-#endif
if (args->status != AIM_RENDEZVOUS_PROPOSE)
return 1;
-#if 0
+
if (args->reqclass & AIM_CAPS_CHAT) {
char *name = extract_name(args->info.chat.roominfo.name);
int *exch = g_new0(int, 1);
GList *m = NULL;
+ char txt[1024];
+ struct aim_chat_invitation * inv = g_new0(struct aim_chat_invitation, 1);
+
m = g_list_append(m, g_strdup(name ? name : args->info.chat.roominfo.name));
*exch = args->info.chat.roominfo.exchange;
m = g_list_append(m, exch);
- serv_got_chat_invite(gc,
- name ? name : args->info.chat.roominfo.name,
- userinfo->sn,
- (char *)args->msg,
- m);
+
+ g_snprintf( txt, 1024, "Got an invitation to chatroom %s from %s: %s", name, userinfo->sn, args->msg );
+
+ inv->gc = gc;
+ inv->exchange = *exch;
+ inv->name = g_strdup(name);
+
+ do_ask_dialog( gc, txt, inv, oscar_accept_chat, oscar_reject_chat);
+
if (name)
g_free(name);
}
-#endif
+
return 1;
}
@@ -2440,10 +2447,20 @@ int gaim_parsemtn(aim_session_t *sess, aim_frame_t *fr, ...)
sn = va_arg(ap, char*);
type2 = va_arg(ap, int);
va_end(ap);
-
- if(type2 == 0x0001 || type2 == 0x0002)
- serv_got_typing(gc, sn, 0);
-
+
+ if(type2 == 0x0002) {
+ /* User is typing */
+ serv_got_typing(gc, sn, 0, 1);
+ }
+ else if (type2 == 0x0001) {
+ /* User has typed something, but is not actively typing (stale) */
+ serv_got_typing(gc, sn, 0, 2);
+ }
+ else {
+ /* User has stopped typing */
+ serv_got_typing(gc, sn, 0, 0);
+ }
+
return 1;
}
@@ -2481,6 +2498,138 @@ int oscar_send_typing(struct gaim_connection *gc, char * who, int typing)
return( aim_im_sendmtn(od->sess, 1, who, typing ? 0x0002 : 0x0000) );
}
+int oscar_chat_send(struct gaim_connection * gc, int id, char *message)
+{
+ struct oscar_data * od = (struct oscar_data*)gc->proto_data;
+ struct chat_connection * ccon;
+ int ret;
+ guint8 len = strlen(message);
+ char *s;
+
+ if(!(ccon = find_oscar_chat(gc, id)))
+ return -1;
+
+ for (s = message; *s; s++)
+ if (*s & 128)
+ break;
+
+ /* Message contains high ASCII chars, time for some translation! */
+ if (*s) {
+ s = g_malloc(BUF_LONG);
+ /* Try if we can put it in an ISO8859-1 string first.
+ If we can't, fall back to UTF16. */
+ if ((ret = do_iconv("UTF-8", "ISO8859-1", message, s, len, BUF_LONG)) >= 0) {
+ len = ret;
+ } else if ((ret = do_iconv("UTF-8", "UNICODEBIG", message, s, len, BUF_LONG)) >= 0) {
+ len = ret;
+ } else {
+ /* OOF, translation failed... Oh well.. */
+ g_free( s );
+ s = message;
+ }
+ } else {
+ s = message;
+ }
+
+ ret = aim_chat_send_im(od->sess, ccon->conn, AIM_CHATFLAGS_NOREFLECT, s, len);
+
+ if (s != message) {
+ g_free(s);
+ }
+
+ return (ret >= 0);
+}
+
+void oscar_chat_invite(struct gaim_connection * gc, int id, char *message, char *who)
+{
+ struct oscar_data * od = (struct oscar_data *)gc->proto_data;
+ struct chat_connection *ccon = find_oscar_chat(gc, id);
+
+ if (ccon == NULL)
+ return;
+
+ aim_chat_invite(od->sess, od->conn, who, message ? message : "",
+ ccon->exchange, ccon->name, 0x0);
+}
+
+void oscar_chat_kill(struct gaim_connection *gc, struct chat_connection *cc)
+{
+ struct oscar_data *od = (struct oscar_data *)gc->proto_data;
+
+ /* Notify the conversation window that we've left the chat */
+ serv_got_chat_left(gc, cc->id);
+
+ /* Destroy the chat_connection */
+ od->oscar_chats = g_slist_remove(od->oscar_chats, cc);
+ if (cc->inpa > 0)
+ gaim_input_remove(cc->inpa);
+ aim_conn_kill(od->sess, &cc->conn);
+ g_free(cc->name);
+ g_free(cc->show);
+ g_free(cc);
+}
+
+void oscar_chat_leave(struct gaim_connection * gc, int id)
+{
+ struct chat_connection * ccon = find_oscar_chat(gc, id);
+
+ if(ccon == NULL)
+ return;
+
+ oscar_chat_kill(gc, ccon);
+}
+
+int oscar_chat_join(struct gaim_connection * gc, char * name)
+{
+ struct oscar_data * od = (struct oscar_data *)gc->proto_data;
+
+ aim_conn_t * cur;
+
+ if((cur = aim_getconn_type(od->sess, AIM_CONN_TYPE_CHATNAV))) {
+
+ return (aim_chatnav_createroom(od->sess, cur, name, 4) == 0);
+
+ } else {
+ struct create_room * cr = g_new0(struct create_room, 1);
+ cr->exchange = 4;
+ cr->name = g_strdup(name);
+ od->create_rooms = g_slist_append(od->create_rooms, cr);
+ aim_reqservice(od->sess, od->conn, AIM_CONN_TYPE_CHATNAV);
+ return 1;
+ }
+}
+
+int oscar_chat_open(struct gaim_connection * gc, char *who)
+{
+ struct oscar_data * od = (struct oscar_data *)gc->proto_data;
+ int ret;
+ static int chat_id = 0;
+ char * chatname = g_new0(char, strlen(gc->username)+4);
+
+ g_snprintf(chatname, strlen(gc->username) + 4, "%s%d", gc->username, chat_id++);
+
+ ret = oscar_chat_join(gc, chatname);
+
+ aim_chat_invite(od->sess, od->conn, who, "", 4, chatname, 0x0);
+
+ g_free(chatname);
+
+ return ret;
+}
+
+void oscar_accept_chat(gpointer w, struct aim_chat_invitation * inv)
+{
+ oscar_chat_join(inv->gc, inv->name);
+ g_free(inv->name);
+ g_free(inv);
+}
+
+void oscar_reject_chat(gpointer w, struct aim_chat_invitation * inv)
+{
+ g_free(inv->name);
+ g_free(inv);
+}
+
void oscar_init()
{
struct prpl *ret = g_new0(struct prpl, 1);
@@ -2494,6 +2643,10 @@ void oscar_init()
ret->get_away = oscar_get_away;
ret->add_buddy = oscar_add_buddy;
ret->remove_buddy = oscar_remove_buddy;
+ ret->chat_send = oscar_chat_send;
+ ret->chat_invite = oscar_chat_invite;
+ ret->chat_leave = oscar_chat_leave;
+ ret->chat_open = oscar_chat_open;
ret->add_permit = oscar_add_permit;
ret->add_deny = oscar_add_deny;
ret->rem_permit = oscar_rem_permit;
diff --git a/protocols/oscar/tlv.c b/protocols/oscar/tlv.c
index 11b89758..9d827caf 100644
--- a/protocols/oscar/tlv.c
+++ b/protocols/oscar/tlv.c
@@ -339,6 +339,31 @@ int aim_addtlvtochain_frozentlvlist(aim_tlvlist_t **list, guint16 type, aim_tlvl
return buflen;
}
+int aim_addtlvtochain_chatroom(aim_tlvlist_t **list, guint16 type, guint16 exchange, const char *roomname, guint16 instance)
+{
+ guint8 *buf;
+ int buflen;
+ aim_bstream_t bs;
+
+ buflen = 2 + 1 + strlen(roomname) + 2;
+
+ if (!(buf = g_malloc(buflen)))
+ return 0;
+
+ aim_bstream_init(&bs, buf, buflen);
+
+ aimbs_put16(&bs, exchange);
+ aimbs_put8(&bs, strlen(roomname));
+ aimbs_putraw(&bs, (guint8 *)roomname, strlen(roomname));
+ aimbs_put16(&bs, instance);
+
+ aim_addtlvtochain_raw(list, type, aim_bstream_curpos(&bs), buf);
+
+ g_free(buf);
+
+ return 0;
+}
+
/**
* aim_writetlvchain - Write a TLV chain into a data buffer.
* @buf: Destination buffer
diff --git a/protocols/proxy.c b/protocols/proxy.c
index 6d450c92..0546f2d7 100644
--- a/protocols/proxy.c
+++ b/protocols/proxy.c
@@ -72,7 +72,7 @@ typedef struct _GaimIOClosure {
-static struct sockaddr_in *gaim_gethostbyname(char *host, int port)
+static struct sockaddr_in *gaim_gethostbyname(const char *host, int port)
{
static struct sockaddr_in sin;
@@ -113,7 +113,7 @@ static gboolean gaim_io_invoke(GIOChannel *source, GIOCondition condition, gpoin
return TRUE;
}
-static void no_one_calls(gpointer data, gint source, GaimInputCondition cond)
+static void gaim_io_connected(gpointer data, gint source, GaimInputCondition cond)
{
struct PHB *phb = data;
unsigned int len;
@@ -143,7 +143,7 @@ static void no_one_calls(gpointer data, gint source, GaimInputCondition cond)
}
}
-static int proxy_connect_none(char *host, unsigned short port, struct PHB *phb)
+static int proxy_connect_none(const char *host, unsigned short port, struct PHB *phb)
{
struct sockaddr_in *sin;
int fd = -1;
@@ -162,7 +162,7 @@ static int proxy_connect_none(char *host, unsigned short port, struct PHB *phb)
if (connect(fd, (struct sockaddr *)sin, sizeof(*sin)) < 0) {
if (sockerr_again()) {
- phb->inpa = gaim_input_add(fd, GAIM_INPUT_WRITE, no_one_calls, phb);
+ phb->inpa = gaim_input_add(fd, GAIM_INPUT_WRITE, gaim_io_connected, phb);
phb->fd = fd;
} else {
closesocket(fd);
@@ -270,7 +270,7 @@ static void http_canwrite(gpointer data, gint source, GaimInputCondition cond)
phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, http_canread, phb);
}
-static int proxy_connect_http(char *host, unsigned short port, struct PHB *phb)
+static int proxy_connect_http(const char *host, unsigned short port, struct PHB *phb)
{
phb->host = g_strdup(host);
phb->port = port;
@@ -354,7 +354,7 @@ static void s4_canwrite(gpointer data, gint source, GaimInputCondition cond)
phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s4_canread, phb);
}
-static int proxy_connect_socks4(char *host, unsigned short port, struct PHB *phb)
+static int proxy_connect_socks4(const char *host, unsigned short port, struct PHB *phb)
{
phb->host = g_strdup(host);
phb->port = port;
@@ -536,7 +536,7 @@ static void s5_canwrite(gpointer data, gint source, GaimInputCondition cond)
phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s5_canread, phb);
}
-static int proxy_connect_socks5(char *host, unsigned short port, struct PHB *phb)
+static int proxy_connect_socks5(const char *host, unsigned short port, struct PHB *phb)
{
phb->host = g_strdup(host);
phb->port = port;
@@ -577,7 +577,7 @@ void gaim_input_remove(gint tag)
g_source_remove(tag);
}
-int proxy_connect(char *host, int port, GaimInputFunction func, gpointer data)
+int proxy_connect(const char *host, int port, GaimInputFunction func, gpointer data)
{
struct PHB *phb;
diff --git a/protocols/proxy.h b/protocols/proxy.h
index 7c34fc40..47c966d2 100644
--- a/protocols/proxy.h
+++ b/protocols/proxy.h
@@ -55,6 +55,6 @@ typedef void (*GaimInputFunction)(gpointer, gint, GaimInputCondition);
G_MODULE_EXPORT gint gaim_input_add(int, GaimInputCondition, GaimInputFunction, gpointer);
G_MODULE_EXPORT void gaim_input_remove(gint);
-G_MODULE_EXPORT int proxy_connect(char *host, int port, GaimInputFunction func, gpointer data);
+G_MODULE_EXPORT int proxy_connect(const char *host, int port, GaimInputFunction func, gpointer data);
#endif /* _PROXY_H_ */
diff --git a/protocols/yahoo/crypt.c b/protocols/yahoo/crypt.c
index 00eed70b..5122e3af 100644
--- a/protocols/yahoo/crypt.c
+++ b/protocols/yahoo/crypt.c
@@ -22,10 +22,6 @@
* already had. isn't that lovely. people should just use linux or
* freebsd, crypt works properly on those systems. i hate solaris */
-#if HAVE_CONFIG_H
-# include <config.h>
-#endif
-
#if HAVE_STRING_H
# include <string.h>
#elif HAVE_STRINGS_H
diff --git a/protocols/yahoo/libyahoo2.c b/protocols/yahoo/libyahoo2.c
index 62ceb0af..c691f18b 100644
--- a/protocols/yahoo/libyahoo2.c
+++ b/protocols/yahoo/libyahoo2.c
@@ -43,10 +43,6 @@
*
*/
-#if HAVE_CONFIG_H
-# include <config.h>
-#endif
-
#ifndef _WIN32
#include <unistd.h>
#endif
diff --git a/protocols/yahoo/yahoo.c b/protocols/yahoo/yahoo.c
index e55b30af..832d1ab4 100644
--- a/protocols/yahoo/yahoo.c
+++ b/protocols/yahoo/yahoo.c
@@ -634,8 +634,14 @@ void ext_yahoo_got_file( int id, char *who, char *url, long expires, char *msg,
void ext_yahoo_typing_notify( int id, char *who, int stat )
{
struct gaim_connection *gc = byahoo_get_gc_by_id( id );
-
- serv_got_typing( gc, who, 1 );
+ if (stat == 1) {
+ /* User is typing */
+ serv_got_typing( gc, who, 1, 1 );
+ }
+ else {
+ /* User stopped typing */
+ serv_got_typing( gc, who, 1, 0 );
+ }
}
void ext_yahoo_system_message( int id, char *msg )
diff --git a/protocols/yahoo/yahoo_httplib.c b/protocols/yahoo/yahoo_httplib.c
index 41e31a23..dbbe2a84 100644
--- a/protocols/yahoo/yahoo_httplib.c
+++ b/protocols/yahoo/yahoo_httplib.c
@@ -19,10 +19,6 @@
*
*/
-#if HAVE_CONFIG_H
-# include <config.h>
-#endif
-
#include <stdio.h>
#include <stdlib.h>
diff --git a/protocols/yahoo/yahoo_util.c b/protocols/yahoo/yahoo_util.c
index cb155e3c..3c99cf44 100644
--- a/protocols/yahoo/yahoo_util.c
+++ b/protocols/yahoo/yahoo_util.c
@@ -19,10 +19,6 @@
*
*/
-#if HAVE_CONFIG_H
-# include <config.h>
-#endif
-
#if STDC_HEADERS
# include <string.h>
#else
diff --git a/storage.c b/storage.c
new file mode 100644
index 00000000..b766c9e3
--- /dev/null
+++ b/storage.c
@@ -0,0 +1,185 @@
+ /********************************************************************\
+ * BitlBee -- An IRC to other IM-networks gateway *
+ * *
+ * Copyright 2002-2004 Wilmer van der Gaast and others *
+ \********************************************************************/
+
+/* Support for multiple storage backends */
+
+/*
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License with
+ the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+ Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#define BITLBEE_CORE
+#include "bitlbee.h"
+#include "crypting.h"
+
+extern storage_t storage_text;
+
+static GList text_entry = { &storage_text, NULL, NULL };
+static GList *storage_backends = &text_entry;
+
+void register_storage_backend(storage_t *backend)
+{
+ storage_backends = g_list_append(storage_backends, backend);
+}
+
+static storage_t *storage_init_single(const char *name)
+{
+ GList *gl;
+ storage_t *st;
+
+ for (gl = storage_backends; gl; gl = gl->next) {
+ st = gl->data;
+ if (strcmp(st->name, name) == 0)
+ break;
+ }
+
+ if (gl == NULL)
+ return NULL;
+
+ if (st->init)
+ st->init();
+
+ return st;
+}
+
+GList *storage_init(const char *primary, char **migrate)
+{
+ GList *ret = NULL;
+ int i;
+ storage_t *storage;
+
+ storage = storage_init_single(primary);
+ if (storage == NULL)
+ return NULL;
+
+ ret = g_list_append(ret, storage);
+
+ for (i = 0; migrate && migrate[i]; i++) {
+ storage = storage_init_single(migrate[i]);
+
+ if (storage)
+ ret = g_list_append(ret, storage);
+ }
+
+ return ret;
+}
+
+storage_status_t storage_check_pass (const char *nick, const char *password)
+{
+ GList *gl;
+
+ /* Loop until we don't get NO_SUCH_USER */
+
+ for (gl = global.storage; gl; gl = gl->next) {
+ storage_t *st = gl->data;
+ storage_status_t status;
+
+ status = st->check_pass(nick, password);
+ if (status != STORAGE_NO_SUCH_USER)
+ return status;
+ }
+
+ return STORAGE_NO_SUCH_USER;
+}
+
+storage_status_t storage_load (const char *nick, const char *password, irc_t * irc)
+{
+ GList *gl;
+
+ /* Loop until we don't get NO_SUCH_USER */
+ for (gl = global.storage; gl; gl = gl->next) {
+ storage_t *st = gl->data;
+ storage_status_t status;
+
+ status = st->load(nick, password, irc);
+ if (status == STORAGE_OK) {
+ irc_setpass(irc, password);
+ return status;
+ }
+
+ if (status != STORAGE_NO_SUCH_USER)
+ return status;
+ }
+
+ return STORAGE_NO_SUCH_USER;
+}
+
+storage_status_t storage_save (irc_t *irc, int overwrite)
+{
+ return ((storage_t *)global.storage->data)->save(irc, overwrite);
+}
+
+storage_status_t storage_remove (const char *nick, const char *password)
+{
+ GList *gl;
+ storage_status_t ret = STORAGE_OK;
+
+ /* Remove this account from all storage backends. If this isn't
+ * done, the account will still be usable, it'd just be
+ * loaded from a different backend. */
+ for (gl = global.storage; gl; gl = gl->next) {
+ storage_t *st = gl->data;
+ storage_status_t status;
+
+ status = st->remove(nick, password);
+ if (status != STORAGE_NO_SUCH_USER &&
+ status != STORAGE_OK)
+ ret = status;
+ }
+
+ return ret;
+}
+
+storage_status_t storage_rename (const char *onick, const char *nnick, const char *password)
+{
+ storage_status_t status;
+ GList *gl = global.storage;
+ storage_t *primary_storage = gl->data;
+ irc_t *irc;
+
+ /* First, try to rename in the current write backend, assuming onick
+ * is stored there */
+ status = primary_storage->rename(onick, nnick, password);
+ if (status != STORAGE_NO_SUCH_USER)
+ return status;
+
+ /* Try to load from a migration backend and save to the current backend.
+ * Explicitly remove the account from the migration backend as otherwise
+ * it'd still be usable under the old name */
+
+ irc = g_new0(irc_t, 1);
+ status = storage_load(onick, password, irc);
+ if (status != STORAGE_OK) {
+ irc_free(irc);
+ return status;
+ }
+
+ g_free(irc->nick);
+ irc->nick = g_strdup(nnick);
+
+ status = storage_save(irc, FALSE);
+ if (status != STORAGE_OK) {
+ irc_free(irc);
+ return status;
+ }
+ irc_free(irc);
+
+ storage_remove(onick, password);
+
+ return STORAGE_OK;
+}
diff --git a/storage.h b/storage.h
new file mode 100644
index 00000000..301b424c
--- /dev/null
+++ b/storage.h
@@ -0,0 +1,66 @@
+ /********************************************************************\
+ * BitlBee -- An IRC to other IM-networks gateway *
+ * *
+ * Copyright 2002-2004 Wilmer van der Gaast and others *
+ \********************************************************************/
+
+/* Layer for retrieving and storing buddy information */
+
+/*
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License with
+ the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+ Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef __STORAGE_H__
+#define __STORAGE_H__
+
+typedef enum {
+ STORAGE_OK = 0,
+ STORAGE_NO_SUCH_USER,
+ STORAGE_INVALID_PASSWORD,
+ STORAGE_ALREADY_EXISTS,
+ STORAGE_OTHER_ERROR /* Error that isn't caused by user input, such as
+ a database that is unreachable. log() will be
+ used for the exact error message */
+} storage_status_t;
+
+typedef struct {
+ const char *name;
+
+ /* May be set to NULL if not required */
+ void (*init) (void);
+
+ storage_status_t (*check_pass) (const char *nick, const char *password);
+
+ storage_status_t (*load) (const char *nick, const char *password, irc_t * irc);
+ storage_status_t (*save) (irc_t *irc, int overwrite);
+ storage_status_t (*remove) (const char *nick, const char *password);
+
+ /* May be NULL if not supported by backend */
+ storage_status_t (*rename) (const char *onick, const char *nnick, const char *password);
+} storage_t;
+
+storage_status_t storage_check_pass (const char *nick, const char *password);
+
+storage_status_t storage_load (const char *nick, const char *password, irc_t * irc);
+storage_status_t storage_save (irc_t *irc, int overwrite);
+storage_status_t storage_remove (const char *nick, const char *password);
+
+storage_status_t storage_rename (const char *onick, const char *nnick, const char *password);
+
+void register_storage_backend(storage_t *);
+GList *storage_init(const char *primary, char **migrate);
+
+#endif /* __STORAGE_H__ */
diff --git a/storage_text.c b/storage_text.c
new file mode 100644
index 00000000..ed32b73f
--- /dev/null
+++ b/storage_text.c
@@ -0,0 +1,347 @@
+ /********************************************************************\
+ * BitlBee -- An IRC to other IM-networks gateway *
+ * *
+ * Copyright 2002-2004 Wilmer van der Gaast and others *
+ \********************************************************************/
+
+/* Storage backend that uses the same file format as <=1.0 */
+
+/*
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License with
+ the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+ Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#define BITLBEE_CORE
+#include "bitlbee.h"
+#include "crypting.h"
+
+/* DO NOT USE THIS FUNCTION IN NEW CODE. This
+ * function is here merely because the save/load code still uses
+ * ids rather than names */
+static struct prpl *find_protocol_by_id(int id)
+{
+ switch (id) {
+ case 1: return find_protocol("oscar");
+ case 4: return find_protocol("msn");
+ case 2: return find_protocol("yahoo");
+ case 8: return find_protocol("jabber");
+ default: break;
+ }
+ return NULL;
+}
+
+static int find_protocol_id(const char *name)
+{
+ if (!strcmp(name, "oscar")) return 1;
+ if (!strcmp(name, "msn")) return 4;
+ if (!strcmp(name, "yahoo")) return 2;
+ if (!strcmp(name, "jabber")) return 8;
+
+ return -1;
+}
+
+
+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.", CONFIG );
+ 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 );
+}
+
+static storage_status_t text_load ( const char *my_nick, const char* password, irc_t *irc )
+{
+ char s[512];
+ char *line;
+ int proto;
+ char nick[MAX_NICK_LENGTH+1];
+ FILE *fp;
+ user_t *ru = user_find( irc, ROOT_NICK );
+
+ if( irc->status == USTATUS_IDENTIFIED )
+ return( 1 );
+
+ g_snprintf( s, 511, "%s%s%s", global.conf->configdir, my_nick, ".accounts" );
+ fp = fopen( s, "r" );
+ if( !fp ) return STORAGE_NO_SUCH_USER;
+
+ fscanf( fp, "%32[^\n]s", s );
+
+ if (checkpass (password, s) != 0)
+ {
+ fclose( fp );
+ return STORAGE_INVALID_PASSWORD;
+ }
+
+ /* Do this now. If the user runs with AuthMode = Registered, the
+ account command will not work otherwise. */
+ irc->status = USTATUS_IDENTIFIED;
+
+ while( fscanf( fp, "%511[^\n]s", s ) > 0 )
+ {
+ fgetc( fp );
+ line = deobfucrypt( s, password );
+ if (line == NULL) return STORAGE_OTHER_ERROR;
+ root_command_string( irc, ru, line, 0 );
+ g_free( line );
+ }
+ fclose( fp );
+
+ g_snprintf( s, 511, "%s%s%s", global.conf->configdir, my_nick, ".nicks" );
+ fp = fopen( s, "r" );
+ if( !fp ) return STORAGE_NO_SUCH_USER;
+ while( fscanf( fp, "%s %d %s", s, &proto, nick ) > 0 )
+ {
+ struct prpl *prpl;
+
+ prpl = find_protocol_by_id(proto);
+
+ if (!prpl)
+ continue;
+
+ http_decode( s );
+ nick_set( irc, s, prpl, nick );
+ }
+ fclose( fp );
+
+ if( set_getint( irc, "auto_connect" ) )
+ {
+ strcpy( s, "account on" ); /* Can't do this directly because r_c_s alters the string */
+ root_command_string( irc, ru, s, 0 );
+ }
+
+ return STORAGE_OK;
+}
+
+static storage_status_t text_save( irc_t *irc, int overwrite )
+{
+ char s[512];
+ char path[512], new_path[512];
+ char *line;
+ nick_t *n;
+ set_t *set;
+ mode_t ou = umask( 0077 );
+ account_t *a;
+ FILE *fp;
+ char *hash;
+
+ if (!overwrite) {
+ g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".accounts" );
+ if (access( path, F_OK ) != -1)
+ return STORAGE_ALREADY_EXISTS;
+
+ g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".nicks" );
+ if (access( path, F_OK ) != -1)
+ return STORAGE_ALREADY_EXISTS;
+ }
+
+ /*\
+ * [SH] Nothing should be saved if no password is set, because the
+ * password is not set if it was wrong, or if one is not identified
+ * yet. This means that a malicious user could easily overwrite
+ * files owned by someone else:
+ * a Bad Thing, methinks
+ \*/
+
+ /* [WVG] No? Really? */
+
+ /*\
+ * [SH] Okay, okay, it wasn't really Wilmer who said that, it was
+ * me. I just thought it was funny.
+ \*/
+
+ hash = hashpass( irc->password );
+ if( hash == NULL )
+ {
+ irc_usermsg( irc, "Please register yourself if you want to save your settings." );
+ return STORAGE_OTHER_ERROR;
+ }
+
+ g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".nicks~" );
+ fp = fopen( path, "w" );
+ if( !fp ) return STORAGE_OTHER_ERROR;
+ for( n = irc->nicks; n; n = n->next )
+ {
+ strcpy( s, n->handle );
+ s[169] = 0; /* Prevent any overflow (169 ~ 512 / 3) */
+ http_encode( s );
+ g_snprintf( s + strlen( s ), 510 - strlen( s ), " %d %s", find_protocol_id(n->proto->name), n->nick );
+ if( fprintf( fp, "%s\n", s ) != strlen( s ) + 1 )
+ {
+ irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
+ fclose( fp );
+ return STORAGE_OTHER_ERROR;
+ }
+ }
+ if( fclose( fp ) != 0 )
+ {
+ irc_usermsg( irc, "fclose() reported an error. Disk full?" );
+ return STORAGE_OTHER_ERROR;
+ }
+
+ g_snprintf( new_path, 512, "%s%s%s", global.conf->configdir, irc->nick, ".nicks" );
+ if( unlink( new_path ) != 0 )
+ {
+ if( errno != ENOENT )
+ {
+ irc_usermsg( irc, "Error while removing old .nicks file" );
+ return STORAGE_OTHER_ERROR;
+ }
+ }
+ if( rename( path, new_path ) != 0 )
+ {
+ irc_usermsg( irc, "Error while renaming new .nicks file" );
+ return STORAGE_OTHER_ERROR;
+ }
+
+ g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".accounts~" );
+ fp = fopen( path, "w" );
+ if( !fp ) return STORAGE_OTHER_ERROR;
+ if( fprintf( fp, "%s", hash ) != strlen( hash ) )
+ {
+ irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
+ fclose( fp );
+ return STORAGE_OTHER_ERROR;
+ }
+ g_free( hash );
+
+ for( a = irc->accounts; a; a = a->next )
+ {
+ if( !strcmp(a->prpl->name, "oscar") )
+ g_snprintf( s, sizeof( s ), "account add oscar \"%s\" \"%s\" %s", a->user, a->pass, a->server );
+ else
+ g_snprintf( s, sizeof( s ), "account add %s \"%s\" \"%s\" \"%s\"",
+ a->prpl->name, a->user, a->pass, a->server ? a->server : "" );
+
+ line = obfucrypt( s, irc->password );
+ if( *line )
+ {
+ if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 )
+ {
+ irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
+ fclose( fp );
+ return STORAGE_OTHER_ERROR;
+ }
+ }
+ g_free( line );
+ }
+
+ for( set = irc->set; set; set = set->next )
+ {
+ if( set->value && set->def )
+ {
+ g_snprintf( s, sizeof( s ), "set %s \"%s\"", set->key, set->value );
+ line = obfucrypt( s, irc->password );
+ if( *line )
+ {
+ if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 )
+ {
+ irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
+ fclose( fp );
+ return STORAGE_OTHER_ERROR;
+ }
+ }
+ g_free( line );
+ }
+ }
+
+ if( strcmp( irc->mynick, ROOT_NICK ) != 0 )
+ {
+ g_snprintf( s, sizeof( s ), "rename %s %s", ROOT_NICK, irc->mynick );
+ line = obfucrypt( s, irc->password );
+ if( *line )
+ {
+ if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 )
+ {
+ irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
+ fclose( fp );
+ return STORAGE_OTHER_ERROR;
+ }
+ }
+ g_free( line );
+ }
+ if( fclose( fp ) != 0 )
+ {
+ irc_usermsg( irc, "fclose() reported an error. Disk full?" );
+ return STORAGE_OTHER_ERROR;
+ }
+
+ g_snprintf( new_path, 512, "%s%s%s", global.conf->configdir, irc->nick, ".accounts" );
+ if( unlink( new_path ) != 0 )
+ {
+ if( errno != ENOENT )
+ {
+ irc_usermsg( irc, "Error while removing old .accounts file" );
+ return STORAGE_OTHER_ERROR;
+ }
+ }
+ if( rename( path, new_path ) != 0 )
+ {
+ irc_usermsg( irc, "Error while renaming new .accounts file" );
+ return STORAGE_OTHER_ERROR;
+ }
+
+ umask( ou );
+
+ return STORAGE_OK;
+}
+
+static storage_status_t text_check_pass( const char *nick, const char *password )
+{
+ char s[512];
+ FILE *fp;
+
+ g_snprintf( s, 511, "%s%s%s", global.conf->configdir, nick, ".accounts" );
+ fp = fopen( s, "r" );
+ if (!fp)
+ return STORAGE_NO_SUCH_USER;
+
+ fscanf( fp, "%32[^\n]s", s );
+ fclose( fp );
+
+ if (checkpass( password, s) == -1)
+ return STORAGE_INVALID_PASSWORD;
+
+ return STORAGE_OK;
+}
+
+static storage_status_t text_remove( const char *nick, const char *password )
+{
+ char s[512];
+ storage_status_t status;
+
+ status = text_check_pass( nick, password );
+ if (status != STORAGE_OK)
+ return status;
+
+ g_snprintf( s, 511, "%s%s%s", global.conf->configdir, nick, ".accounts" );
+ if (unlink( s ) == -1)
+ return STORAGE_OTHER_ERROR;
+
+ g_snprintf( s, 511, "%s%s%s", global.conf->configdir, nick, ".nicks" );
+ if (unlink( s ) == -1)
+ return STORAGE_OTHER_ERROR;
+
+ return STORAGE_OK;
+}
+
+storage_t storage_text = {
+ .name = "text",
+ .init = text_init,
+ .check_pass = text_check_pass,
+ .remove = text_remove,
+ .load = text_load,
+ .save = text_save
+};
diff --git a/unix.c b/unix.c
index c108528a..3474ca75 100644
--- a/unix.c
+++ b/unix.c
@@ -52,11 +52,12 @@ int main( int argc, char *argv[] )
CONF_FILE = g_strdup( CONF_FILE_DEF );
global.helpfile = g_strdup( HELP_FILE );
-
+
global.conf = conf_load( argc, argv );
if( global.conf == NULL )
return( 1 );
-
+
+
if( global.conf->runmode == RUNMODE_INETD )
{
log_link( LOGLVL_ERROR, LOGOUTPUT_IRC );
@@ -76,6 +77,14 @@ int main( int argc, char *argv[] )
}
if( i != 0 )
return( i );
+
+ global.storage = storage_init( global.conf->primary_storage,
+ global.conf->migrate_storage );
+ if ( global.storage == NULL) {
+ log_message( LOGLVL_ERROR, "Unable to load storage backend '%s'", global.conf->primary_storage );
+ return( 1 );
+ }
+
/* Catch some signals to tell the user what's happening before quitting */
memset( &sig, 0, sizeof( sig ) );
@@ -93,10 +102,6 @@ int main( int argc, char *argv[] )
if( !getuid() || !geteuid() )
log_message( LOGLVL_WARNING, "BitlBee is running with root privileges. Why?" );
- if( access( global.conf->configdir, F_OK ) != 0 )
- log_message( LOGLVL_WARNING, "The configuration directory %s does not exist. Configuration won't be saved.", CONFIG );
- 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 );
if( help_init( &(global.help) ) == NULL )
log_message( LOGLVL_WARNING, "Error opening helpfile %s.", HELP_FILE );