diff options
40 files changed, 1538 insertions, 405 deletions
@@ -9,10 +9,12 @@ -include Makefile.settings # Program variables -objects = account.o bitlbee.o conf.o crypting.o help.o ini.o ipc.o irc.o irc_commands.o log.o nick.o query.o root_commands.o set.o storage.o storage_text.o unix.o url.o user.o util.o +objects = account.o bitlbee.o conf.o crypting.o help.o ini.o ipc.o irc.o irc_commands.o log.o nick.o query.o root_commands.o set.o storage.o storage_text.o storage_xml.o unix.o url.o user.o util.o headers = account.h bitlbee.h commands.h conf.h config.h crypting.h help.h ini.h ipc.h irc.h log.h nick.h query.h set.h sock.h storage.h url.h user.h protocols/http_client.h protocols/md5.h protocols/nogaim.h protocols/proxy.h protocols/sha.h protocols/ssl_client.h subdirs = protocols +objects += $(LDAP_OBJ) + # Expansion of variables subdirobjs = $(foreach dir,$(subdirs),$(dir)/$(dir).o) CFLAGS += -Wall @@ -34,7 +34,7 @@ account_t *account_add( irc_t *irc, struct prpl *prpl, char *user, char *pass ) if( irc->accounts ) { for( a = irc->accounts; a->next; a = a->next ); - a = a->next = g_new0 ( account_t, 1 ); + a = a->next = g_new0( account_t, 1 ); } else { @@ -33,7 +33,7 @@ #include <stdio.h> #include <errno.h> -gboolean bitlbee_io_new_client( GIOChannel *source, GIOCondition condition, gpointer data ); +static gboolean bitlbee_io_new_client( gpointer data, gint fd, b_input_condition condition ); int bitlbee_daemon_init() { @@ -43,7 +43,6 @@ int bitlbee_daemon_init() struct sockaddr_in listen_addr; #endif int i; - GIOChannel *ch; FILE *fp; log_link( LOGLVL_ERROR, LOGOUTPUT_SYSLOG ); @@ -90,8 +89,7 @@ int bitlbee_daemon_init() return( -1 ); } - ch = g_io_channel_unix_new( global.listen_socket ); - global.listen_watch_source_id = g_io_add_watch( ch, G_IO_IN, bitlbee_io_new_client, NULL ); + global.listen_watch_source_id = b_input_add( global.listen_socket, GAIM_INPUT_READ, bitlbee_io_new_client, NULL ); #ifndef _WIN32 if( !global.conf->nofork ) @@ -146,18 +144,12 @@ int bitlbee_inetd_init() return( 0 ); } -gboolean bitlbee_io_current_client_read( GIOChannel *source, GIOCondition condition, gpointer data ) +gboolean bitlbee_io_current_client_read( gpointer data, gint fd, b_input_condition cond ) { irc_t *irc = data; char line[513]; int st; - if( condition & G_IO_ERR || condition & G_IO_HUP ) - { - irc_abort( irc, 1, "Read error" ); - return FALSE; - } - st = read( irc->fd, line, sizeof( line ) - 1 ); if( st == 0 ) { @@ -193,7 +185,7 @@ gboolean bitlbee_io_current_client_read( GIOChannel *source, GIOCondition condit /* Normally, irc_process() shouldn't call irc_free() but irc_abort(). Just in case: */ if( !g_slist_find( irc_connection_list, irc ) ) { - log_message( LOGLVL_WARNING, "Abnormal termination of connection with fd %d.", irc->fd ); + log_message( LOGLVL_WARNING, "Abnormal termination of connection with fd %d.", fd ); return FALSE; } @@ -207,14 +199,14 @@ gboolean bitlbee_io_current_client_read( GIOChannel *source, GIOCondition condit return TRUE; } -gboolean bitlbee_io_current_client_write( GIOChannel *source, GIOCondition condition, gpointer data ) +gboolean bitlbee_io_current_client_write( gpointer data, gint fd, b_input_condition cond ) { irc_t *irc = data; int st, size; char *temp; if( irc->sendbuffer == NULL ) - return( FALSE ); + return FALSE; size = strlen( irc->sendbuffer ); st = write( irc->fd, irc->sendbuffer, size ); @@ -238,7 +230,7 @@ gboolean bitlbee_io_current_client_write( GIOChannel *source, GIOCondition condi if( irc->status & USTATUS_SHUTDOWN ) irc_free( irc ); - return( FALSE ); + return FALSE; } else { @@ -246,13 +238,13 @@ gboolean bitlbee_io_current_client_write( GIOChannel *source, GIOCondition condi g_free( irc->sendbuffer ); irc->sendbuffer = temp; - return( TRUE ); + return TRUE; } } -gboolean bitlbee_io_new_client( GIOChannel *source, GIOCondition condition, gpointer data ) +static gboolean bitlbee_io_new_client( gpointer data, gint fd, b_input_condition condition ) { - size_t size = sizeof( struct sockaddr_in ); + socklen_t size = sizeof( struct sockaddr_in ); struct sockaddr_in conn_info; int new_socket = accept( global.listen_socket, (struct sockaddr *) &conn_info, &size ); pid_t client_pid = 0; @@ -285,7 +277,7 @@ gboolean bitlbee_io_new_client( GIOChannel *source, GIOCondition condition, gpoi child = g_new0( struct bitlbee_child, 1 ); child->pid = client_pid; child->ipc_fd = fds[0]; - child->ipc_inpa = gaim_input_add( child->ipc_fd, GAIM_INPUT_READ, ipc_master_read, child ); + child->ipc_inpa = b_input_add( child->ipc_fd, GAIM_INPUT_READ, ipc_master_read, child ); child_list = g_slist_append( child_list, child ); log_message( LOGLVL_INFO, "Creating new subprocess with pid %d.", client_pid ); @@ -300,14 +292,14 @@ gboolean bitlbee_io_new_client( GIOChannel *source, GIOCondition condition, gpoi /* Close the listening socket, we're a client. */ close( global.listen_socket ); - g_source_remove( global.listen_watch_source_id ); + b_event_remove( global.listen_watch_source_id ); /* Make the connection. */ irc = irc_new( new_socket ); /* We can store the IPC fd there now. */ global.listen_socket = fds[1]; - global.listen_watch_source_id = gaim_input_add( fds[1], GAIM_INPUT_READ, ipc_child_read, irc ); + global.listen_watch_source_id = b_input_add( fds[1], GAIM_INPUT_READ, ipc_child_read, irc ); close( fds[0] ); @@ -323,12 +315,14 @@ gboolean bitlbee_io_new_client( GIOChannel *source, GIOCondition condition, gpoi return TRUE; } -void bitlbee_shutdown( gpointer data ) +gboolean bitlbee_shutdown( gpointer data, gint fd, b_input_condition cond ) { /* Try to save data for all active connections (if desired). */ while( irc_connection_list != NULL ) irc_free( irc_connection_list->data ); /* We'll only reach this point when not running in inetd mode: */ - g_main_quit( global.loop ); + b_main_quit(); + + return FALSE; } @@ -57,23 +57,42 @@ /* The following functions should not be used if we want to maintain Windows compatibility... */ #undef free -#define free __PLEASE_USE_THE_GLIB_MEMORY_ALLOCATION_SYSTEM_INSTEAD__ +#define free __PLEASE_USE_THE_GLIB_MEMORY_ALLOCATION_SYSTEM__ #undef malloc -#define malloc __PLEASE_USE_THE_GLIB_MEMORY_ALLOCATION_SYSTEM_INSTEAD__ +#define malloc __PLEASE_USE_THE_GLIB_MEMORY_ALLOCATION_SYSTEM__ #undef calloc -#define calloc __PLEASE_USE_THE_GLIB_MEMORY_ALLOCATION_SYSTEM_INSTEAD__ +#define calloc __PLEASE_USE_THE_GLIB_MEMORY_ALLOCATION_SYSTEM__ #undef realloc -#define realloc __PLEASE_USE_THE_GLIB_MEMORY_ALLOCATION_SYSTEM_INSTEAD__ +#define realloc __PLEASE_USE_THE_GLIB_MEMORY_ALLOCATION_SYSTEM__ #undef strdup -#define strdup __PLEASE_USE_THE_GLIB_STRDUP_FUNCTIONS_SYSTEM_INSTEAD__ +#define strdup __PLEASE_USE_THE_GLIB_STRDUP_FUNCTIONS_SYSTEM__ #undef strndup -#define strndup __PLEASE_USE_THE_GLIB_STRDUP_FUNCTIONS_SYSTEM_INSTEAD__ +#define strndup __PLEASE_USE_THE_GLIB_STRDUP_FUNCTIONS_SYSTEM__ #undef snprintf -#define snprintf __PLEASE_USE_G_SNPRINTF_INSTEAD__ +#define snprintf __PLEASE_USE_G_SNPRINTF__ #undef strcasecmp -#define strcasecmp __PLEASE_USE_G_STRCASECMP_INSTEAD__ +#define strcasecmp __PLEASE_USE_G_STRCASECMP__ #undef strncasecmp -#define strncasecmp __PLEASE_USE_G_STRNCASECMP_INSTEAD__ +#define strncasecmp __PLEASE_USE_G_STRNCASECMP__ + +/* And the following functions shouldn't be used anymore to keep compatibility + with other event handling libs than GLib. */ +#undef g_timeout_add +#define g_timeout_add __PLEASE_USE_B_TIMEOUT_ADD__ +#undef g_timeout_add_full +#define g_timeout_add_full __PLEASE_USE_B_TIMEOUT_ADD__ +#undef g_io_add_watch +#define g_io_add_watch __PLEASE_USE_B_INPUT_ADD__ +#undef g_io_add_watch_full +#define g_io_add_watch_full __PLEASE_USE_B_INPUT_ADD__ +#undef g_source_remove +#define g_source_remove __PLEASE_USE_B_EVENT_REMOVE__ +#undef g_source_remove_by_user_data +#define g_source_remove_by_user_data __PLEASE_USE_B_SOURCE_REMOVE_BY_USER_DATA__ +#undef g_main_run +#define g_main_run __PLEASE_USE_B_MAIN_RUN__ +#undef g_main_quit +#define g_main_quit __PLEASE_USE_B_MAIN_QUIT__ #ifndef F_OK #define F_OK 0 @@ -111,6 +130,7 @@ extern char *CONF_FILE; #include "query.h" #include "sock.h" #include "util.h" +#include "proxy.h" typedef struct global { /* In forked mode, child processes store the fd of the IPC socket here. */ @@ -120,19 +140,18 @@ typedef struct global { conf_t *conf; GList *storage; /* The first backend in the list will be used for saving */ char *helpfile; - GMainLoop *loop; int restart; } global_t; int bitlbee_daemon_init( void ); int bitlbee_inetd_init( void ); -gboolean bitlbee_io_current_client_read( GIOChannel *source, GIOCondition condition, gpointer data ); -gboolean bitlbee_io_current_client_write( GIOChannel *source, GIOCondition condition, gpointer data ); +gboolean bitlbee_io_current_client_read( gpointer data, gint source, b_input_condition cond ); +gboolean bitlbee_io_current_client_write( gpointer data, gint source, b_input_condition cond ); void root_command_string( irc_t *irc, user_t *u, char *command, int flags ); void root_command( irc_t *irc, char *command[] ); -void bitlbee_shutdown( gpointer data ); +gboolean bitlbee_shutdown( gpointer data, gint fd, b_input_condition cond ); extern global_t global; @@ -54,7 +54,7 @@ conf_t *conf_load( int argc, char *argv[] ) conf->port = 6667; conf->nofork = 0; conf->verbose = 0; - conf->primary_storage = "text"; + conf->primary_storage = "xml"; conf->runmode = RUNMODE_INETD; conf->authmode = AUTHMODE_OPEN; conf->auth_pass = NULL; @@ -13,11 +13,12 @@ etcdir='$prefix/etc/bitlbee/' mandir='$prefix/share/man/' datadir='$prefix/share/bitlbee/' config='/var/lib/bitlbee/' +plugindir='$prefix/lib/bitlbee/' +includedir='$prefix/include/bitlbee/' +libevent='/usr/' pidfile='/var/run/bitlbee.pid' ipcsocket='/var/run/bitlbee' -plugindir='$prefix/lib/bitlbee' pcdir='$prefix/lib/pkgconfig' -includedir='$prefix/include/bitlbee' msn=1 jabber=1 @@ -27,6 +28,9 @@ yahoo=1 debug=0 strip=1 ipv6=1 + +events=glib +ldap=auto ssl=auto arch=`uname -s` @@ -63,6 +67,9 @@ Option Description Default --ipv6=0/1 IPv6 socket support $ipv6 +--ldap=0/1/auto LDAP support $ldap + +--events=... Event handler (glib, libevent) $events --ssl=... SSL library to use (gnutls, nss, openssl, bogus, auto) $ssl EOF @@ -79,9 +86,11 @@ mandir=`eval echo "$mandir/" | sed 's/\/\{1,\}/\//g'` datadir=`eval echo "$datadir/" | sed 's/\/\{1,\}/\//g'` config=`eval echo "$config/" | sed 's/\/\{1,\}/\//g'` plugindir=`eval echo "$plugindir/" | sed 's/\/\{1,\}/\//g'` +includedir=`eval echo "$includedir"/ | sed 's/\/\{1,\}/\//g'` +libevent=`eval echo "$libevent"/ | sed 's/\/\{1,\}/\//g'` + pidfile=`eval echo "$pidfile" | sed 's/\/\{1,\}/\//g'` ipcsocket=`eval echo "$ipcsocket" | sed 's/\/\{1,\}/\//g'` -includedir=`eval echo "$includedir" | sed 's/\/\{1,\}/\//g'` pcdir=`eval echo "$pcdir" | sed 's/\/\{1,\}/\//g'` cat<<EOF>Makefile.settings @@ -139,16 +148,18 @@ echo CFLAGS+=-I`pwd` -I`pwd`/protocols -I. >> Makefile.settings echo CFLAGS+=-DHAVE_CONFIG_H >> Makefile.settings if [ -n "$CC" ]; then - echo "CC=$CC" >> Makefile.settings; + CC=$CC elif type gcc > /dev/null 2> /dev/null; then - echo "CC=gcc" >> Makefile.settings; + CC=gcc elif type cc > /dev/null 2> /dev/null; then - echo "CC=cc" >> Makefile.settings; + CC=cc else echo 'Cannot find a C compiler, aborting.' exit 1; fi +echo "CC=$CC" >> Makefile.settings; + if [ -n "$LD" ]; then echo "LD=$LD" >> Makefile.settings; elif type ld > /dev/null 2> /dev/null; then @@ -172,6 +183,29 @@ else exit 1; fi +if [ "$events" = "libevent" ]; then + if ! [ -e "${libevent}include/event.h" ]; then + echo + echo 'Warning: Could not find event.h, you might have to install it and/or specify' + echo 'its location using the --libevent= argument. (Example: If event.h is in' + echo '/usr/local/include and binaries are in /usr/local/lib: --libevent=/usr/local)' + fi + + echo '#define EVENTS_LIBEVENT' >> config.h + cat <<EOF>>Makefile.settings +EFLAGS+=-levent -L${libevent}lib +CFLAGS+=-I${libevent}include +EOF +elif [ "$events" = "glib" ]; then + ## We already use glib anyway, so this is all we need (and in fact not even this, but just to be sure...): + echo '#define EVENTS_GLIB' >> config.h +else + echo + echo 'ERROR: Unknown event handler specified.' + exit 1 +fi +echo 'EVENT_HANDLER=events_'$events'.o' >> Makefile.settings + detect_gnutls() { if libgnutls-config --version > /dev/null 2> /dev/null; then @@ -202,6 +236,23 @@ EOF fi; } +detect_ldap() +{ + TMPFILE=`mktemp` + if $CC -o $TMPFILE -shared -lldap 2>/dev/null >/dev/null; then + cat<<EOF>>Makefile.settings +EFLAGS+=-lldap +CFLAGS+= +EOF + ldap=1 + rm -f $TMPFILE + ret=1 + else + ldap=0 + ret=0 + fi +} + if [ "$msn" = 1 -o "$jabber" = 1 ]; then if [ "$ssl" = "auto" ]; then detect_gnutls @@ -262,6 +313,18 @@ if [ "$msn" = 1 -o "$jabber" = 1 ]; then echo 'SSL_CLIENT=ssl_'$ssl'.o' >> Makefile.settings fi +if [ "$ldap" = "auto" ]; then + detect_ldap +fi + +if [ "$ldap" = 0 ]; then + echo "LDAP_OBJ=\# no ldap" >> Makefile.settings + echo "#undef WITH_LDAP" >> config.h +elif [ "$ldap" = 1 ]; then + echo "#define WITH_LDAP 1" >> config.h + echo "LDAP_OBJ=storage_ldap.o" >> Makefile.settings +fi + if [ "$strip" = 0 ]; then echo "STRIP=\# skip strip" >> Makefile.settings; else @@ -400,9 +463,8 @@ else echo ' Binary stripping disabled.'; fi -if [ "$msn" = "1" ]; then - echo ' Using SSL library: '$ssl; -fi +echo ' Using event handler: '$events; +echo ' Using SSL library: '$ssl; #if [ "$flood" = "0" ]; then # echo ' Flood protection disabled.'; @@ -415,3 +477,9 @@ if [ -n "$protocols" ]; then else echo ' Building without IM-protocol support. We wish you a lot of fun...'; fi + +if [ "$ldap" = "0" ]; then + echo " LDAP storage backend disabled." +else + echo " LDAP storage backend enabled." +fi diff --git a/doc/bitlbee.schema b/doc/bitlbee.schema new file mode 100644 index 00000000..3322e057 --- /dev/null +++ b/doc/bitlbee.schema @@ -0,0 +1,62 @@ +## LDAP Schema file for BitlBee +## Copyright (C) 2006 Jelmer Vernooij <jelmer@samba.org> +## +## We need the following object classes and related attributes: +## +## bitlBeeBuddy: +## - nick +## - handle + +## each bitlBeeNick has zero or more bitlBeeAccount subentries +## and bitlBeeAccount entries contain zero or more bitlBeeBuddy entries + +## The admin needs to setup the LDAP server to: +## - allow anonymous users to auth against bitlBeeNick objects on the +## password field +## - allow anonymous users to create new objects that start with nick= +## - allow read/write for a user that is authenticated only to his/her own +## object and subentries + +## - userid +## - userPassword +## - setting (multiple values) +## depends: top, account + +attributetype ( 1.3.6.1.4.1.25873.2.1.1 NAME 'bitlBeeAutoConnect' + DESC 'Autoconnect setting' + EQUALITY booleanMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.25873.2.1.2 NAME 'bitlBeeAccountNo' + DESC 'Account number' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +objectclass ( 1.3.6.1.4.1.25873.2.2.3 NAME 'bitlBeeAccount' SUP account STRUCTURAL + DESC 'BitlBee User Account ' + MUST ( userid, userPassword ) + MAY ( ) ) + +## bitlBeeAccount: +## - accountNo 1.3.6.1.4.1.1466.115.121.1.27 +## - protocol (msn, oscar, jabber, yahoo, ...) +## - username +## - password +## - server name +## - autoconnect (true/false) 1.3.6.1.4.1.1466.115.121.1.7 +## depends: top + +objectclass ( 1.3.6.1.4.1.25873.2.2.1 NAME 'bitlBeeIMAccount' SUP account STRUCTURAL + DESC 'BitlBee IM Account ' + MUST ( bitlBeeAccountNo, userid, userPassword ) + MAY ( host, bitlBeeAutoconnect ) ) + +objectclass ( 1.3.6.1.4.1.25873.2.2.2 NAME 'bitlBeeSetting' SUP top STRUCTURAL + DESC 'BitlBee Configuration Setting' + MUST ( bitlBeeSettingName ) + MAY ( bitlBeeSettingValue ) ) + +objectclass ( 1.3.6.1.4.1.25873.2.2.3 NAME 'bitlBeeBuddy' SUP top STRUCTURAL + DESC 'BitlBee Nick Mapping' + MUST ( bitlBeeBuddyHandle ) + MAY ( ircNick ) ) @@ -59,7 +59,7 @@ static void ipc_master_cmd_die( irc_t *data, char **cmd ) if( global.conf->runmode == RUNMODE_FORKDAEMON ) ipc_to_children_str( "DIE\r\n" ); - bitlbee_shutdown( NULL ); + bitlbee_shutdown( NULL, -1, 0 ); } void ipc_master_cmd_rehash( irc_t *data, char **cmd ) @@ -90,7 +90,7 @@ void ipc_master_cmd_restart( irc_t *data, char **cmd ) } global.restart = -1; - bitlbee_shutdown( NULL ); + bitlbee_shutdown( NULL, -1, 0 ); } static const command_t ipc_master_commands[] = { @@ -114,7 +114,7 @@ static void ipc_child_cmd_die( irc_t *irc, char **cmd ) static void ipc_child_cmd_wallops( irc_t *irc, char **cmd ) { - if( ! irc->status & USTATUS_LOGGED_IN ) + if( !( irc->status & USTATUS_LOGGED_IN ) ) return; if( strchr( irc->umode, 'w' ) ) @@ -123,7 +123,7 @@ static void ipc_child_cmd_wallops( irc_t *irc, char **cmd ) static void ipc_child_cmd_lilo( irc_t *irc, char **cmd ) { - if( ! irc->status & USTATUS_LOGGED_IN ) + if( !( irc->status & USTATUS_LOGGED_IN ) ) return; if( strchr( irc->umode, 's' ) ) @@ -132,7 +132,7 @@ static void ipc_child_cmd_lilo( irc_t *irc, char **cmd ) static void ipc_child_cmd_opermsg( irc_t *irc, char **cmd ) { - if( ! irc->status & USTATUS_LOGGED_IN ) + if( !( irc->status & USTATUS_LOGGED_IN ) ) return; if( strchr( irc->umode, 'o' ) ) @@ -153,7 +153,7 @@ static void ipc_child_cmd_rehash( irc_t *irc, char **cmd ) static void ipc_child_cmd_kill( irc_t *irc, char **cmd ) { - if( ! irc->status & USTATUS_LOGGED_IN ) + if( !( irc->status & USTATUS_LOGGED_IN ) ) return; if( nick_cmp( cmd[1], irc->nick ) != 0 ) @@ -165,7 +165,7 @@ static void ipc_child_cmd_kill( irc_t *irc, char **cmd ) static void ipc_child_cmd_hello( irc_t *irc, char **cmd ) { - if( ! irc->status & USTATUS_LOGGED_IN ) + if( !( irc->status & USTATUS_LOGGED_IN ) ) ipc_to_master_str( "HELLO\r\n" ); else ipc_to_master_str( "HELLO %s %s :%s\r\n", irc->host, irc->nick, irc->realname ); @@ -245,7 +245,7 @@ static char *ipc_readline( int fd ) return buf; } -void ipc_master_read( gpointer data, gint source, GaimInputCondition cond ) +gboolean ipc_master_read( gpointer data, gint source, b_input_condition cond ) { char *buf, **cmd; @@ -271,9 +271,11 @@ void ipc_master_read( gpointer data, gint source, GaimInputCondition cond ) } } } + + return TRUE; } -void ipc_child_read( gpointer data, gint source, GaimInputCondition cond ) +gboolean ipc_child_read( gpointer data, gint source, b_input_condition cond ) { char *buf, **cmd; @@ -285,11 +287,13 @@ void ipc_child_read( gpointer data, gint source, GaimInputCondition cond ) } else { - gaim_input_remove( global.listen_watch_source_id ); + b_event_remove( global.listen_watch_source_id ); close( global.listen_socket ); global.listen_socket = -1; } + + return TRUE; } void ipc_to_master( char **cmd ) @@ -396,7 +400,7 @@ void ipc_to_children_str( char *format, ... ) void ipc_master_free_one( struct bitlbee_child *c ) { - gaim_input_remove( c->ipc_inpa ); + b_event_remove( c->ipc_inpa ); closesocket( c->ipc_fd ); g_free( c->host ); @@ -462,24 +466,22 @@ void ipc_master_set_statefile( char *fn ) } -static gboolean new_ipc_client (GIOChannel *gio, GIOCondition cond, gpointer data) +static gboolean new_ipc_client( gpointer data, gint serversock, b_input_condition cond ) { struct bitlbee_child *child = g_new0( struct bitlbee_child, 1 ); - int serversock; - - serversock = g_io_channel_unix_get_fd(gio); - - child->ipc_fd = accept(serversock, NULL, 0); - - if (child->ipc_fd == -1) { + + child->ipc_fd = accept( serversock, NULL, 0 ); + + if( child->ipc_fd == -1 ) + { log_message( LOGLVL_WARNING, "Unable to accept connection on UNIX domain socket: %s", strerror(errno) ); return TRUE; } - child->ipc_inpa = gaim_input_add( child->ipc_fd, GAIM_INPUT_READ, ipc_master_read, child ); - + child->ipc_inpa = b_input_add( child->ipc_fd, GAIM_INPUT_READ, ipc_master_read, child ); + child_list = g_slist_append( child_list, child ); - + return TRUE; } @@ -488,7 +490,6 @@ int ipc_master_listen_socket() { struct sockaddr_un un_addr; int serversock; - GIOChannel *gio; /* Clean up old socket files that were hanging around.. */ if (unlink(IPCSOCKET) == -1 && errno != ENOENT) { @@ -516,14 +517,8 @@ int ipc_master_listen_socket() return 0; } - gio = g_io_channel_unix_new(serversock); + b_input_add( serversock, GAIM_INPUT_READ, new_ipc_client, NULL ); - if (gio == NULL) { - log_message( LOGLVL_WARNING, "Unable to create IO channel for unix socket" ); - return 0; - } - - g_io_add_watch(gio, G_IO_IN, new_ipc_client, NULL); return 1; } #else @@ -562,7 +557,7 @@ int ipc_master_load_state() fclose( fp ); return 0; } - child->ipc_inpa = gaim_input_add( child->ipc_fd, GAIM_INPUT_READ, ipc_master_read, child ); + child->ipc_inpa = b_input_add( child->ipc_fd, GAIM_INPUT_READ, ipc_master_read, child ); child_list = g_slist_append( child_list, child ); } @@ -39,8 +39,8 @@ struct bitlbee_child }; -void ipc_master_read( gpointer data, gint source, GaimInputCondition cond ); -void ipc_child_read( gpointer data, gint source, GaimInputCondition cond ); +gboolean ipc_master_read( gpointer data, gint source, b_input_condition cond ); +gboolean ipc_child_read( gpointer data, gint source, b_input_condition cond ); void ipc_master_free_one( struct bitlbee_child *child ); void ipc_master_free_all(); @@ -28,7 +28,7 @@ #include "crypting.h" #include "ipc.h" -static gboolean irc_userping( gpointer _irc ); +static gboolean irc_userping( gpointer _irc, int fd, b_input_condition cond ); GSList *irc_connection_list = NULL; @@ -53,11 +53,9 @@ irc_t *irc_new( int fd ) irc = g_new0( irc_t, 1 ); irc->fd = fd; - irc->io_channel = g_io_channel_unix_new( fd ); - g_io_channel_set_encoding (irc->io_channel, NULL, NULL); - g_io_channel_set_buffered (irc->io_channel, FALSE); - g_io_channel_set_flags( irc->io_channel, G_IO_FLAG_NONBLOCK, NULL ); - irc->r_watch_source_id = g_io_add_watch( irc->io_channel, G_IO_IN | G_IO_ERR | G_IO_HUP, bitlbee_io_current_client_read, irc ); + sock_make_nonblocking( irc->fd ); + + irc->r_watch_source_id = b_input_add( irc->fd, GAIM_INPUT_READ, bitlbee_io_current_client_read, irc ); irc->status = USTATUS_OFFLINE; irc->last_pong = gettime(); @@ -115,7 +113,7 @@ irc_t *irc_new( int fd ) if( !irc->myhost ) irc->myhost = g_strdup( "localhost." ); if( global.conf->ping_interval > 0 && global.conf->ping_timeout > 0 ) - irc->ping_source_id = g_timeout_add( global.conf->ping_interval * 1000, irc_userping, irc ); + irc->ping_source_id = b_timeout_add( global.conf->ping_interval * 1000, irc_userping, irc ); irc_write( irc, ":%s NOTICE AUTH :%s", irc->myhost, "BitlBee-IRCd initialized, please go on" ); @@ -185,8 +183,8 @@ void irc_abort( irc_t *irc, int immed, char *format, ... ) to it that should shut down the connection in a second, just in case bitlbee_.._write doesn't do it first. */ - g_source_remove( irc->r_watch_source_id ); - irc->r_watch_source_id = g_timeout_add_full( G_PRIORITY_HIGH, 1000, (GSourceFunc) irc_free, irc, NULL ); + b_event_remove( irc->r_watch_source_id ); + irc->r_watch_source_id = b_timeout_add( 1000, (b_event_handler) irc_free, irc ); } else { @@ -219,12 +217,11 @@ void irc_free(irc_t * irc) closesocket( irc->fd ); if( irc->ping_source_id > 0 ) - g_source_remove( irc->ping_source_id ); - g_source_remove( irc->r_watch_source_id ); + b_event_remove( irc->ping_source_id ); + b_event_remove( irc->r_watch_source_id ); if( irc->w_watch_source_id > 0 ) - g_source_remove( irc->w_watch_source_id ); + b_event_remove( irc->w_watch_source_id ); - g_io_channel_unref( irc->io_channel ); irc_connection_list = g_slist_remove( irc_connection_list, irc ); for (account = irc->accounts; account; account = account->next) { @@ -274,7 +271,7 @@ void irc_free(irc_t * irc) if(user->user!=user->nick) g_free(user->user); if(user->host!=user->nick) g_free(user->host); if(user->realname!=user->nick) g_free(user->realname); - gaim_input_remove(user->sendbuf_timer); + b_event_remove(user->sendbuf_timer); usertmp = user; user = user->next; @@ -324,7 +321,7 @@ void irc_free(irc_t * irc) g_free(irc); if( global.conf->runmode == RUNMODE_INETD || global.conf->runmode == RUNMODE_FORKDAEMON ) - g_main_quit( global.loop ); + b_main_quit(); } /* USE WITH CAUTION! @@ -578,7 +575,8 @@ void irc_vawrite( irc_t *irc, char *format, va_list params ) int size; char line[IRC_MAX_LINE+1], *cs; - if( irc->quit ) + /* Don't try to write anything new anymore when shutting down. */ + if( irc->status & USTATUS_SHUTDOWN ) return; line[IRC_MAX_LINE] = 0; @@ -595,17 +593,25 @@ void irc_vawrite( irc_t *irc, char *format, va_list params ) } strcat( line, "\r\n" ); - if( irc->sendbuffer != NULL ) { + if( irc->sendbuffer != NULL ) + { size = strlen( irc->sendbuffer ) + strlen( line ); irc->sendbuffer = g_renew ( char, irc->sendbuffer, size + 1 ); strcpy( ( irc->sendbuffer + strlen( irc->sendbuffer ) ), line ); } - else - irc->sendbuffer = g_strdup(line); + else + { + irc->sendbuffer = g_strdup(line); + } if( irc->w_watch_source_id == 0 ) { - irc->w_watch_source_id = g_io_add_watch( irc->io_channel, G_IO_OUT, bitlbee_io_current_client_write, irc ); + /* If the buffer is empty we can probably write, so call the write event handler + immediately. If it returns TRUE, it should be called again, so add the event to + the queue. If it's FALSE, we emptied the buffer and saved ourselves some work + in the event queue. */ + if( bitlbee_io_current_client_write( irc, irc->fd, GAIM_INPUT_WRITE ) ) + irc->w_watch_source_id = b_input_add( irc->fd, GAIM_INPUT_WRITE, bitlbee_io_current_client_write, irc ); } return; @@ -631,7 +637,7 @@ void irc_write_all( int now, char *format, ... ) irc_vawrite( temp->data, format, params ); if( now ) { - bitlbee_io_current_client_write( irc->io_channel, G_IO_OUT, irc ); + bitlbee_io_current_client_write( irc, irc->fd, GAIM_INPUT_WRITE ); } temp = temp->next; } @@ -700,7 +706,7 @@ int irc_check_login( irc_t *irc ) { if( irc->user && irc->nick ) { - if( global.conf->authmode == AUTHMODE_CLOSED && ! irc->status & USTATUS_AUTHORIZED ) + if( global.conf->authmode == AUTHMODE_CLOSED && !( irc->status & USTATUS_AUTHORIZED ) ) { irc_reply( irc, 464, ":This server is password-protected." ); return 0; @@ -1034,7 +1040,7 @@ int irc_send( irc_t *irc, char *nick, char *s, int flags ) return( 0 ); } -gboolean buddy_send_handler_delayed( gpointer data ) +static gboolean buddy_send_handler_delayed( gpointer data, gint fd, b_input_condition cond ) { user_t *u = data; @@ -1065,8 +1071,8 @@ void buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags ) if( u->sendbuf_len > 0 && u->sendbuf_flags != flags) { /* Flush the buffer */ - g_source_remove( u->sendbuf_timer ); - buddy_send_handler_delayed( u ); + b_event_remove( u->sendbuf_timer ); + buddy_send_handler_delayed( u, -1, 0 ); } if( u->sendbuf_len == 0 ) @@ -1090,8 +1096,8 @@ void buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags ) delay *= 1000; if( u->sendbuf_timer > 0 ) - g_source_remove( u->sendbuf_timer ); - u->sendbuf_timer = g_timeout_add( delay, buddy_send_handler_delayed, u ); + b_event_remove( u->sendbuf_timer ); + u->sendbuf_timer = b_timeout_add( delay, buddy_send_handler_delayed, u ); } else { @@ -1175,12 +1181,12 @@ int irc_noticefrom( irc_t *irc, char *nick, char *msg ) timeout. The number returned is the number of seconds we received no pongs from the user. When not connected yet, we don't ping but drop the connection when the user fails to connect in IRC_LOGIN_TIMEOUT secs. */ -static gboolean irc_userping( gpointer _irc ) +static gboolean irc_userping( gpointer _irc, gint fd, b_input_condition cond ) { irc_t *irc = _irc; int rv = 0; - if( ! irc->status & USTATUS_LOGGED_IN ) + if( !( irc->status & USTATUS_LOGGED_IN ) ) { if( gettime() > ( irc->last_pong + IRC_LOGIN_TIMEOUT ) ) rv = gettime() - irc->last_pong; @@ -60,7 +60,6 @@ typedef struct irc int pinging; char *sendbuffer; char *readbuffer; - int quit; int sentbytes; time_t oldtime; @@ -92,7 +91,6 @@ typedef struct irc struct help *help; struct set *set; - GIOChannel *io_channel; gint r_watch_source_id; gint w_watch_source_id; gint ping_source_id; diff --git a/irc_commands.c b/irc_commands.c index 519070db..f410bb52 100644 --- a/irc_commands.c +++ b/irc_commands.c @@ -613,7 +613,7 @@ void irc_exec( irc_t *irc, char *cmd[] ) { irc_reply( irc, 462, ":Only allowed before logging in" ); } - else if( irc_commands[i].flags & IRC_CMD_LOGGED_IN && ! irc->status & USTATUS_LOGGED_IN ) + else if( irc_commands[i].flags & IRC_CMD_LOGGED_IN && !( irc->status & USTATUS_LOGGED_IN ) ) { irc_reply( irc, 451, ":Register first" ); } diff --git a/protocols/Makefile b/protocols/Makefile index 4016e7fd..b74212f4 100644 --- a/protocols/Makefile +++ b/protocols/Makefile @@ -9,7 +9,7 @@ -include ../Makefile.settings # [SH] Program variables -objects = http_client.o md5.o nogaim.o proxy.o sha.o $(SSL_CLIENT) +objects = $(EVENT_HANDLER) http_client.o md5.o nogaim.o proxy.o sha.o $(SSL_CLIENT) # [SH] The next two lines should contain the directory name (in $(subdirs)) # and the name of the object file, which should be linked into diff --git a/protocols/events.h b/protocols/events.h new file mode 100644 index 00000000..781fca6a --- /dev/null +++ b/protocols/events.h @@ -0,0 +1,66 @@ +/* + * nogaim + * + * Copyright (C) 2006 Wilmer van der Gaast and others + * + * 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 + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* + * Split off the event handling things from proxy.[ch] (and adding timer + * stuff. This to allow BitlBee to use other libs than GLib for event + * handling. + */ + + +#ifndef _EVENTS_H_ +#define _EVENTS_H_ + +#include <sys/types.h> +#ifndef _WIN32 +#include <sys/socket.h> +#include <netdb.h> +#include <netinet/in.h> +#endif +#include <glib.h> +#include <gmodule.h> + +typedef enum { + GAIM_INPUT_READ = 1 << 1, + GAIM_INPUT_WRITE = 1 << 2 +} b_input_condition; +typedef gboolean (*b_event_handler)(gpointer data, gint fd, b_input_condition cond); + +#define GAIM_READ_COND (G_IO_IN | G_IO_HUP | G_IO_ERR) +#define GAIM_WRITE_COND (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL) +#define GAIM_ERR_COND (G_IO_HUP | G_IO_ERR | G_IO_NVAL) + +// #define event_debug( x... ) printf( x ) +#define event_debug( x... ) + +G_MODULE_EXPORT void b_main_init(); +G_MODULE_EXPORT void b_main_run(); +G_MODULE_EXPORT void b_main_quit(); + +G_MODULE_EXPORT gint b_input_add(int fd, b_input_condition cond, b_event_handler func, gpointer data); +G_MODULE_EXPORT gint b_timeout_add(gint timeout, b_event_handler func, gpointer data); +G_MODULE_EXPORT void b_event_remove(gint id); + +#ifdef EVENTS_LIBEVENT +G_MODULE_EXPORT void closesocket(int fd); +#endif + +#endif /* _EVENTS_H_ */ diff --git a/protocols/events_glib.c b/protocols/events_glib.c new file mode 100644 index 00000000..620720cd --- /dev/null +++ b/protocols/events_glib.c @@ -0,0 +1,137 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2006 Wilmer van der Gaast and others * + \********************************************************************/ + +/* + * Event handling (using GLib) + */ + +/* + 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#ifndef _WIN32 +#include <sys/socket.h> +#include <netdb.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <unistd.h> +#else +#include "sock.h" +#define ETIMEDOUT WSAETIMEDOUT +#define EINPROGRESS WSAEINPROGRESS +#endif +#include <fcntl.h> +#include <errno.h> +#include "proxy.h" + +typedef struct _GaimIOClosure { + b_event_handler function; + guint result; + gpointer data; +} GaimIOClosure; + +static GMainLoop *loop; + +void b_main_init() +{ + loop = g_main_new( FALSE ); +} + +void b_main_run() +{ + g_main_run( loop ); +} + +void b_main_quit() +{ + g_main_quit( loop ); +} + +static gboolean gaim_io_invoke(GIOChannel *source, GIOCondition condition, gpointer data) +{ + GaimIOClosure *closure = data; + b_input_condition gaim_cond = 0; + gboolean st; + + if (condition & GAIM_READ_COND) + gaim_cond |= GAIM_INPUT_READ; + if (condition & GAIM_WRITE_COND) + gaim_cond |= GAIM_INPUT_WRITE; + + event_debug( "gaim_io_invoke( %d, %d, 0x%x )\n", g_io_channel_unix_get_fd(source), condition, data ); + + st = closure->function(closure->data, g_io_channel_unix_get_fd(source), gaim_cond); + + if( !st ) + event_debug( "Returned FALSE, cancelling.\n" ); + + return st; +} + +static void gaim_io_destroy(gpointer data) +{ + event_debug( "gaim_io_destroy( 0x%x )\n", data ); + g_free(data); +} + +gint b_input_add(gint source, b_input_condition condition, b_event_handler function, gpointer data) +{ + GaimIOClosure *closure = g_new0(GaimIOClosure, 1); + GIOChannel *channel; + GIOCondition cond = 0; + + closure->function = function; + closure->data = data; + + if (condition & GAIM_INPUT_READ) + cond |= GAIM_READ_COND; + if (condition & GAIM_INPUT_WRITE) + cond |= GAIM_WRITE_COND; + + channel = g_io_channel_unix_new(source); + closure->result = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond, + gaim_io_invoke, closure, gaim_io_destroy); + + event_debug( "b_input_add( %d, %d, 0x%x, 0x%x ) = %d (0x%x)\n", source, condition, function, data, closure->result, closure ); + + g_io_channel_unref(channel); + return closure->result; +} + +gint b_timeout_add(gint timeout, b_event_handler func, gpointer data) +{ + gint st = g_timeout_add(timeout, func, data); + + event_debug( "b_timeout_add( %d, %d, %d ) = %d\n", timeout, func, data, st ); + + return st; +} + +void b_event_remove(gint tag) +{ + event_debug( "b_event_remove( %d )\n", tag ); + + if (tag > 0) + g_source_remove(tag); +} diff --git a/protocols/events_libevent.c b/protocols/events_libevent.c new file mode 100644 index 00000000..1119c2ab --- /dev/null +++ b/protocols/events_libevent.c @@ -0,0 +1,247 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2006 Wilmer van der Gaast and others * + \********************************************************************/ + +/* + * Event handling (using libevent) + */ + +/* + 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include "proxy.h" + +#include <sys/time.h> +#include <event.h> + +static guint id_next; +static GHashTable *id_hash; +static int quitting = 0; + +/* Since libevent doesn't handle two event handlers for one fd-condition + very well (which happens sometimes when BitlBee changes event handlers + for a combination), let's buid some indexes so we can delete them here + already, just in time. */ +static GHashTable *read_hash; +static GHashTable *write_hash; + +struct b_event_data +{ + guint id; + struct event evinfo; + gint timeout; + b_event_handler function; + void *data; +}; + +void b_main_init() +{ + event_init(); + + id_next = 1; + id_hash = g_hash_table_new( g_int_hash, g_int_equal ); + read_hash = g_hash_table_new( g_int_hash, g_int_equal ); + write_hash = g_hash_table_new( g_int_hash, g_int_equal ); +} + +void b_main_run() +{ + event_dispatch(); +} + +void b_main_quit() +{ + struct timeval tv; + + /* libevent sometimes generates events before really quitting, + we want to stop them. */ + quitting = 1; + + memset( &tv, 0, sizeof( struct timeval ) ); + event_loopexit( &tv ); +} + +static void b_event_passthrough( int fd, short event, void *data ) +{ + struct b_event_data *b_ev = data; + b_input_condition cond = 0; + int id; + + if( fd >= 0 ) + { + if( event & EV_READ ) + cond |= GAIM_INPUT_READ; + if( event & EV_WRITE ) + cond |= GAIM_INPUT_WRITE; + } + + event_debug( "b_event_passthrough( %d, %d, 0x%x ) (%d)\n", fd, event, (int) data, b_ev->id ); + + /* Since the called function might cancel this handler already + (which free()s b_ev, we have to remember the ID here. */ + id = b_ev->id; + + if( quitting ) + { + b_event_remove( id ); + return; + } + + if( !b_ev->function( b_ev->data, fd, cond ) ) + { + event_debug( "Handler returned FALSE: " ); + b_event_remove( id ); + } + else if( fd == -1 ) + { + struct timeval tv; + + tv.tv_sec = b_ev->timeout / 1000; + tv.tv_usec = ( b_ev->timeout % 1000 ) * 1000; + + evtimer_add( &b_ev->evinfo, &tv ); + } +} + +gint b_input_add( gint fd, b_input_condition condition, b_event_handler function, gpointer data ) +{ + struct b_event_data *b_ev; + + event_debug( "b_input_add( %d, %d, 0x%x, 0x%x ) ", fd, condition, function, data ); + + if( ( condition & GAIM_INPUT_READ && ( b_ev = g_hash_table_lookup( read_hash, &fd ) ) ) || + ( condition & GAIM_INPUT_WRITE && ( b_ev = g_hash_table_lookup( write_hash, &fd ) ) ) ) + { + /* We'll stick with this libevent entry, but give it a new BitlBee id. */ + g_hash_table_remove( id_hash, &b_ev->id ); + + event_debug( "(replacing old handler (id = %d)) = %d\n", b_ev->id, id_next ); + + b_ev->id = id_next++; + b_ev->function = function; + b_ev->data = data; + } + else + { + GIOCondition out_cond; + + event_debug( "(new) = %d\n", id_next ); + + b_ev = g_new0( struct b_event_data, 1 ); + b_ev->id = id_next++; + b_ev->function = function; + b_ev->data = data; + + out_cond = EV_PERSIST; + if( condition & GAIM_INPUT_READ ) + out_cond |= EV_READ; + if( condition & GAIM_INPUT_WRITE ) + out_cond |= EV_WRITE; + + event_set( &b_ev->evinfo, fd, out_cond, b_event_passthrough, b_ev ); + event_add( &b_ev->evinfo, NULL ); + + if( out_cond & EV_READ ) + g_hash_table_insert( read_hash, &b_ev->evinfo.ev_fd, b_ev ); + if( out_cond & EV_WRITE ) + g_hash_table_insert( write_hash, &b_ev->evinfo.ev_fd, b_ev ); + } + + g_hash_table_insert( id_hash, &b_ev->id, b_ev ); + return b_ev->id; +} + +/* TODO: Persistence for timers! */ +gint b_timeout_add( gint timeout, b_event_handler function, gpointer data ) +{ + struct b_event_data *b_ev = g_new0( struct b_event_data, 1 ); + struct timeval tv; + + b_ev->id = id_next++; + b_ev->timeout = timeout; + b_ev->function = function; + b_ev->data = data; + + tv.tv_sec = timeout / 1000; + tv.tv_usec = ( timeout % 1000 ) * 1000; + + evtimer_set( &b_ev->evinfo, b_event_passthrough, b_ev ); + evtimer_add( &b_ev->evinfo, &tv ); + + event_debug( "b_timeout_add( %d, 0x%x, 0x%x ) = %d\n", timeout, function, data, b_ev->id ); + + g_hash_table_insert( id_hash, &b_ev->id, b_ev ); + + return b_ev->id; +} + +void b_event_remove( gint id ) +{ + struct b_event_data *b_ev = g_hash_table_lookup( id_hash, &id ); + + event_debug( "b_event_remove( %d )\n", id ); + if( b_ev ) + { + g_hash_table_remove( id_hash, &b_ev->id ); + if( b_ev->evinfo.ev_fd >= 0 ) + { + if( b_ev->evinfo.ev_events & EV_READ ) + g_hash_table_remove( read_hash, &b_ev->evinfo.ev_fd ); + if( b_ev->evinfo.ev_events & EV_WRITE ) + g_hash_table_remove( write_hash, &b_ev->evinfo.ev_fd ); + } + + event_del( &b_ev->evinfo ); + g_free( b_ev ); + } + else + { + event_debug( "Already removed?\n" ); + } +} + +void closesocket( int fd ) +{ + struct b_event_data *b_ev; + + /* Since epoll() (the main reason we use libevent) automatically removes sockets from + the epoll() list when a socket gets closed and some modules have a habit of + closing sockets before removing event handlers, our and libevent's administration + get a little bit messed up. So this little function will remove the handlers + properly before closing a socket. */ + + if( ( b_ev = g_hash_table_lookup( read_hash, &fd ) ) ) + { + event_debug( "Warning: fd %d still had a read event handler when shutting down.\n", fd ); + b_event_remove( b_ev->id ); + } + if( ( b_ev = g_hash_table_lookup( write_hash, &fd ) ) ) + { + event_debug( "Warning: fd %d still had a write event handler when shutting down.\n", fd ); + b_event_remove( b_ev->id ); + } + + close( fd ); +} diff --git a/protocols/http_client.c b/protocols/http_client.c index c793d9d4..b00fcf98 100644 --- a/protocols/http_client.c +++ b/protocols/http_client.c @@ -31,9 +31,9 @@ #include "sock.h" -static void http_connected( gpointer data, int source, GaimInputCondition cond ); -static void http_ssl_connected( gpointer data, void *source, GaimInputCondition cond ); -static void http_incoming_data( gpointer data, int source, GaimInputCondition cond ); +static gboolean http_connected( gpointer data, int source, b_input_condition cond ); +static gboolean http_ssl_connected( gpointer data, void *source, b_input_condition cond ); +static gboolean http_incoming_data( gpointer data, int source, b_input_condition cond ); void *http_dorequest( char *host, int port, int ssl, char *request, http_input_function func, gpointer data ) @@ -103,7 +103,7 @@ void *http_dorequest_url( char *url_string, http_input_function func, gpointer d /* This one is actually pretty simple... Might get more calls if we can't write the whole request at once. */ -static void http_connected( gpointer data, int source, GaimInputCondition cond ) +static gboolean http_connected( gpointer data, int source, b_input_condition cond ) { struct http_request *req = data; int st; @@ -112,7 +112,7 @@ static void http_connected( gpointer data, int source, GaimInputCondition cond ) goto error; if( req->inpa > 0 ) - gaim_input_remove( req->inpa ); + b_event_remove( req->inpa ); sock_make_nonblocking( req->fd ); @@ -147,13 +147,13 @@ static void http_connected( gpointer data, int source, GaimInputCondition cond ) req->bytes_written += st; if( req->bytes_written < req->request_length ) - req->inpa = gaim_input_add( source, - req->ssl ? ssl_getdirection( req->ssl ) : GAIM_INPUT_WRITE, - http_connected, req ); + req->inpa = b_input_add( source, + req->ssl ? ssl_getdirection( req->ssl ) : GAIM_INPUT_WRITE, + http_connected, req ); else - req->inpa = gaim_input_add( source, GAIM_INPUT_READ, http_incoming_data, req ); + req->inpa = b_input_add( source, GAIM_INPUT_READ, http_incoming_data, req ); - return; + return FALSE; error: req->status_string = g_strdup( "Error while writing HTTP request" ); @@ -163,10 +163,10 @@ error: g_free( req->request ); g_free( req ); - return; + return FALSE; } -static void http_ssl_connected( gpointer data, void *source, GaimInputCondition cond ) +static gboolean http_ssl_connected( gpointer data, void *source, b_input_condition cond ) { struct http_request *req = data; @@ -178,7 +178,7 @@ static void http_ssl_connected( gpointer data, void *source, GaimInputCondition return http_connected( data, req->fd, cond ); } -static void http_incoming_data( gpointer data, int source, GaimInputCondition cond ) +static gboolean http_incoming_data( gpointer data, int source, b_input_condition cond ) { struct http_request *req = data; int evil_server = 0; @@ -187,7 +187,7 @@ static void http_incoming_data( gpointer data, int source, GaimInputCondition co int st; if( req->inpa > 0 ) - gaim_input_remove( req->inpa ); + b_event_remove( req->inpa ); if( req->ssl ) { @@ -235,11 +235,11 @@ static void http_incoming_data( gpointer data, int source, GaimInputCondition co } /* There will be more! */ - req->inpa = gaim_input_add( req->fd, - req->ssl ? ssl_getdirection( req->ssl ) : GAIM_INPUT_READ, - http_incoming_data, req ); + req->inpa = b_input_add( req->fd, + req->ssl ? ssl_getdirection( req->ssl ) : GAIM_INPUT_READ, + http_incoming_data, req ); - return; + return FALSE; got_reply: /* Maybe if the webserver is overloaded, or when there's bad SSL @@ -429,7 +429,7 @@ got_reply: req->bytes_read = req->bytes_written = req->inpa = 0; req->reply_headers = req->reply_body = NULL; - return; + return FALSE; } /* Assume that a closed connection means we're finished, this indeed @@ -448,4 +448,6 @@ cleanup: g_free( req->reply_headers ); g_free( req->status_string ); g_free( req ); + + return FALSE; } diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index ac6481a1..029473fd 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -470,12 +470,14 @@ static void endElement(void *userdata, const char *name) gjc->current = x; } -static void jabber_callback(gpointer data, gint source, GaimInputCondition condition) +static gboolean jabber_callback(gpointer data, gint source, b_input_condition condition) { struct gaim_connection *gc = (struct gaim_connection *)data; struct jabber_data *jd = (struct jabber_data *)gc->proto_data; gjab_recv(jd->gjc); + + return TRUE; } static void charData(void *userdata, const char *s, int slen) @@ -486,7 +488,7 @@ static void charData(void *userdata, const char *s, int slen) xmlnode_insert_cdata(gjc->current, s, slen); } -static void gjab_connected(gpointer data, gint source, GaimInputCondition cond) +static gboolean gjab_connected(gpointer data, gint source, b_input_condition cond) { xmlnode x; char *t, *t2; @@ -496,7 +498,7 @@ static void gjab_connected(gpointer data, gint source, GaimInputCondition cond) if (!g_slist_find(get_connections(), gc)) { closesocket(source); - return; + return FALSE; } jd = gc->proto_data; @@ -507,7 +509,7 @@ static void gjab_connected(gpointer data, gint source, GaimInputCondition cond) if (source == -1) { STATE_EVT(JCONN_STATE_OFF) - return; + return FALSE; } gjc->state = JCONN_STATE_CONNECTED; @@ -529,10 +531,12 @@ static void gjab_connected(gpointer data, gint source, GaimInputCondition cond) STATE_EVT(JCONN_STATE_ON); gc = GJ_GC(gjc); - gc->inpa = gaim_input_add(gjc->fd, GAIM_INPUT_READ, jabber_callback, gc); + gc->inpa = b_input_add(gjc->fd, GAIM_INPUT_READ, jabber_callback, gc); + + return FALSE; } -static void gjab_connected_ssl(gpointer data, void *source, GaimInputCondition cond) +static gboolean gjab_connected_ssl(gpointer data, void *source, b_input_condition cond) { struct gaim_connection *gc = data; struct jabber_data *jd; @@ -543,15 +547,15 @@ static void gjab_connected_ssl(gpointer data, void *source, GaimInputCondition c if (source == NULL) { STATE_EVT(JCONN_STATE_OFF) - return; + return FALSE; } if (!g_slist_find(get_connections(), gc)) { ssl_disconnect(source); - return; + return FALSE; } - gjab_connected(data, gjc->fd, cond); + return gjab_connected(data, gjc->fd, cond); } static void gjab_start(gjconn gjc) @@ -1542,7 +1546,7 @@ static gboolean jabber_destroy_hash(gpointer key, gpointer val, gpointer data) { return TRUE; } -static gboolean jabber_free(gpointer data) +static gboolean jabber_free(gpointer data, gint fd, b_input_condition cond) { struct jabber_data *jd = data; @@ -1587,10 +1591,10 @@ static void jabber_close(struct gaim_connection *gc) } } if (gc->inpa) - gaim_input_remove(gc->inpa); + b_event_remove(gc->inpa); if(jd) { - g_timeout_add(50, jabber_free, jd); + b_timeout_add(50, jabber_free, jd); if(jd->gjc != NULL) xmlnode_free(jd->gjc->current); } diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h index 0cd174f2..dbbb6aa0 100644 --- a/protocols/msn/msn.h +++ b/protocols/msn/msn.h @@ -145,7 +145,7 @@ GSList *msn_connections; GSList *msn_switchboards; /* ns.c */ -void msn_ns_connected( gpointer data, gint source, GaimInputCondition cond ); +gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ); /* msn_util.c */ int msn_write( struct gaim_connection *gc, char *s, int len ); @@ -172,4 +172,4 @@ struct msn_switchboard *msn_sb_spare( struct gaim_connection *gc ); int msn_sb_sendmessage( struct msn_switchboard *sb, char *text ); void msn_sb_to_chat( struct msn_switchboard *sb ); void msn_sb_destroy( struct msn_switchboard *sb ); -void msn_sb_connected( gpointer data, gint source, GaimInputCondition cond ); +gboolean msn_sb_connected( gpointer data, gint source, b_input_condition cond ); diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index 523de0ae..e4c2b68c 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -29,26 +29,26 @@ #include "passport.h" #include "md5.h" -static void msn_ns_callback( gpointer data, gint source, GaimInputCondition cond ); +static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition cond ); static int msn_ns_command( gpointer data, char **cmd, int num_parts ); static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts ); static void msn_auth_got_passport_id( struct passport_reply *rep ); -void msn_ns_connected( gpointer data, gint source, GaimInputCondition cond ) +gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ) { struct gaim_connection *gc = data; struct msn_data *md; char s[1024]; if( !g_slist_find( msn_connections, gc ) ) - return; + return FALSE; if( source == -1 ) { hide_login_progress( gc, "Could not connect to server" ); signoff( gc ); - return; + return FALSE; } md = gc->proto_data; @@ -74,12 +74,14 @@ void msn_ns_connected( gpointer data, gint source, GaimInputCondition cond ) g_snprintf( s, sizeof( s ), "VER %d MSNP8 CVR0\r\n", ++md->trId ); if( msn_write( gc, s, strlen( s ) ) ) { - gc->inpa = gaim_input_add( md->fd, GAIM_INPUT_READ, msn_ns_callback, gc ); + gc->inpa = b_input_add( md->fd, GAIM_INPUT_READ, msn_ns_callback, gc ); set_login_progress( gc, 1, "Connected to server, waiting for reply" ); } + + return FALSE; } -void msn_ns_callback( gpointer data, gint source, GaimInputCondition cond ) +static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition cond ) { struct gaim_connection *gc = data; struct msn_data *md = gc->proto_data; @@ -88,7 +90,11 @@ void msn_ns_callback( gpointer data, gint source, GaimInputCondition cond ) { hide_login_progress( gc, "Error while reading from server" ); signoff( gc ); + + return FALSE; } + else + return TRUE; } static int msn_ns_command( gpointer data, char **cmd, int num_parts ) @@ -129,7 +135,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( num_parts == 6 && strcmp( cmd[2], "NS" ) == 0 ) { - gaim_input_remove( gc->inpa ); + b_event_remove( gc->inpa ); gc->inpa = 0; closesocket( md->fd ); diff --git a/protocols/msn/sb.c b/protocols/msn/sb.c index 34b0a30a..63744cd0 100644 --- a/protocols/msn/sb.c +++ b/protocols/msn/sb.c @@ -29,7 +29,7 @@ #include "passport.h" #include "md5.h" -static void msn_sb_callback( gpointer data, gint source, GaimInputCondition cond ); +static gboolean msn_sb_callback( gpointer data, gint source, b_input_condition cond ); static int msn_sb_command( gpointer data, char **cmd, int num_parts ); static int msn_sb_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts ); @@ -236,7 +236,7 @@ void msn_sb_destroy( struct msn_switchboard *sb ) g_free( sb->handler ); } - if( sb->inp ) gaim_input_remove( sb->inp ); + if( sb->inp ) b_event_remove( sb->inp ); closesocket( sb->fd ); msn_switchboards = g_slist_remove( msn_switchboards, sb ); @@ -244,7 +244,7 @@ void msn_sb_destroy( struct msn_switchboard *sb ) g_free( sb ); } -void msn_sb_connected( gpointer data, gint source, GaimInputCondition cond ) +gboolean msn_sb_connected( gpointer data, gint source, b_input_condition cond ) { struct msn_switchboard *sb = data; struct gaim_connection *gc; @@ -253,7 +253,7 @@ void msn_sb_connected( gpointer data, gint source, GaimInputCondition cond ) /* Are we still alive? */ if( !g_slist_find( msn_switchboards, sb ) ) - return; + return FALSE; gc = sb->gc; md = gc->proto_data; @@ -262,7 +262,7 @@ void msn_sb_connected( gpointer data, gint source, GaimInputCondition cond ) { debug( "ERROR %d while connecting to switchboard server", 1 ); msn_sb_destroy( sb ); - return; + return FALSE; } /* Prepare the callback */ @@ -279,12 +279,14 @@ void msn_sb_connected( gpointer data, gint source, GaimInputCondition cond ) g_snprintf( buf, sizeof( buf ), "ANS %d %s %s %d\r\n", ++sb->trId, gc->username, sb->key, sb->session ); if( msn_sb_write( sb, buf, strlen( buf ) ) ) - sb->inp = gaim_input_add( sb->fd, GAIM_INPUT_READ, msn_sb_callback, sb ); + sb->inp = b_input_add( sb->fd, GAIM_INPUT_READ, msn_sb_callback, sb ); else debug( "ERROR %d while connecting to switchboard server", 2 ); + + return FALSE; } -static void msn_sb_callback( gpointer data, gint source, GaimInputCondition cond ) +static gboolean msn_sb_callback( gpointer data, gint source, b_input_condition cond ) { struct msn_switchboard *sb = data; @@ -292,7 +294,11 @@ static void msn_sb_callback( gpointer data, gint source, GaimInputCondition cond { debug( "ERROR: Switchboard died" ); msn_sb_destroy( sb ); + + return FALSE; } + else + return TRUE; } static int msn_sb_command( gpointer data, char **cmd, int num_parts ) diff --git a/protocols/nogaim.c b/protocols/nogaim.c index f95ddd8a..d4ccc3f1 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -1,7 +1,7 @@ /********************************************************************\ * BitlBee -- An IRC to other IM-networks gateway * * * - * Copyright 2002-2004 Wilmer van der Gaast and others * + * Copyright 2002-2006 Wilmer van der Gaast and others * \********************************************************************/ /* @@ -12,8 +12,6 @@ * This file contains functions called by the Gaim IM-modules. It's written * from scratch for BitlBee and doesn't contain any code from Gaim anymore * (except for the function names). - * - * Copyright 2002-2006 Wilmer van der Gaast <wilmer@gaast.net> and others */ /* @@ -159,7 +157,7 @@ struct gaim_connection *new_gaim_conn( struct aim_user *user ) /* [MD] BUGFIX: don't set gc->irc to the global IRC, but use the one from the struct aim_user. * This fixes daemon mode breakage where IRC doesn't point to the currently active connection. */ - gc->irc=user->irc; + gc->irc = user->irc; connections = g_slist_append( connections, gc ); @@ -239,7 +237,7 @@ void serv_got_crap( struct gaim_connection *gc, char *format, ... ) g_free( text ); } -static gboolean send_keepalive( gpointer d ) +static gboolean send_keepalive( gpointer d, gint fd, b_input_condition cond ) { struct gaim_connection *gc = d; @@ -263,7 +261,7 @@ void account_online( struct gaim_connection *gc ) serv_got_crap( gc, "Logged in" ); - gc->keepalive = g_timeout_add( 60000, send_keepalive, gc ); + gc->keepalive = b_timeout_add( 60000, send_keepalive, gc ); gc->flags |= OPT_LOGGED_IN; /* Also necessary when we're not away, at least for some of the @@ -271,7 +269,7 @@ void account_online( struct gaim_connection *gc ) bim_set_away( gc, u->away ); } -gboolean auto_reconnect( gpointer data ) +gboolean auto_reconnect( gpointer data, gint fd, b_input_condition cond ) { account_t *a = data; @@ -283,7 +281,8 @@ gboolean auto_reconnect( gpointer data ) void cancel_auto_reconnect( account_t *a ) { - while( g_source_remove_by_user_data( (gpointer) a ) ); + /* while( b_event_remove_by_data( (gpointer) a ) ); */ + b_event_remove( a->reconnect ); a->reconnect = 0; } @@ -296,10 +295,10 @@ void signoff( struct gaim_connection *gc ) serv_got_crap( gc, "Signing off.." ); gc->flags |= OPT_LOGGING_OUT; - gaim_input_remove( gc->keepalive ); + b_event_remove( gc->keepalive ); gc->keepalive = 0; gc->prpl->close( gc ); - gaim_input_remove( gc->inpa ); + b_event_remove( gc->inpa ); while( u ) { @@ -326,10 +325,9 @@ void signoff( struct gaim_connection *gc ) else if( !gc->wants_to_die && set_getint( irc, "auto_reconnect" ) ) { int delay = set_getint( irc, "auto_reconnect_delay" ); - serv_got_crap( gc, "Reconnecting in %d seconds..", delay ); - a->reconnect = 1; - g_timeout_add( delay * 1000, auto_reconnect, a ); + serv_got_crap( gc, "Reconnecting in %d seconds..", delay ); + a->reconnect = b_timeout_add( delay * 1000, auto_reconnect, a ); } destroy_gaim_conn( gc ); diff --git a/protocols/nogaim.h b/protocols/nogaim.h index b143440a..2080465c 100644 --- a/protocols/nogaim.h +++ b/protocols/nogaim.h @@ -207,7 +207,7 @@ void bim_rem_block( struct gaim_connection *gc, char *handle ); void nogaim_init(); char *set_eval_away_devoice( irc_t *irc, set_t *set, char *value ); -gboolean auto_reconnect( gpointer data ); +gboolean auto_reconnect( gpointer data, gint fd, b_input_condition cond ); void cancel_auto_reconnect( struct account *a ); /* multi.c */ diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c index c2716c6b..7c76533a 100644 --- a/protocols/oscar/oscar.c +++ b/protocols/oscar/oscar.c @@ -254,8 +254,8 @@ static char *msgerrreason[] = { }; static int msgerrreasonlen = 25; -static void oscar_callback(gpointer data, gint source, - GaimInputCondition condition) { +static gboolean oscar_callback(gpointer data, gint source, + b_input_condition condition) { aim_conn_t *conn = (aim_conn_t *)data; aim_session_t *sess = aim_conn_getsess(conn); struct gaim_connection *gc = sess ? sess->aux_data : NULL; @@ -263,13 +263,13 @@ static void oscar_callback(gpointer data, gint source, if (!gc) { /* gc is null. we return, else we seg SIGSEG on next line. */ - return; + return FALSE; } if (!g_slist_find(get_connections(), gc)) { /* oh boy. this is probably bad. i guess the only thing we * can really do is return? */ - return; + return FALSE; } odata = (struct oscar_data *)gc->proto_data; @@ -289,7 +289,7 @@ static void oscar_callback(gpointer data, gint source, char buf[BUF_LONG]; c->conn = NULL; if (c->inpa > 0) - gaim_input_remove(c->inpa); + b_event_remove(c->inpa); c->inpa = 0; c->fd = -1; aim_conn_kill(odata->sess, &conn); @@ -297,7 +297,7 @@ static void oscar_callback(gpointer data, gint source, do_error_dialog(sess->aux_data, buf, _("Chat Error!")); } else if (conn->type == AIM_CONN_TYPE_CHATNAV) { if (odata->cnpa > 0) - gaim_input_remove(odata->cnpa); + b_event_remove(odata->cnpa); odata->cnpa = 0; while (odata->create_rooms) { struct create_room *cr = odata->create_rooms->data; @@ -311,17 +311,22 @@ static void oscar_callback(gpointer data, gint source, aim_conn_kill(odata->sess, &conn); } else if (conn->type == AIM_CONN_TYPE_AUTH) { if (odata->paspa > 0) - gaim_input_remove(odata->paspa); + b_event_remove(odata->paspa); odata->paspa = 0; aim_conn_kill(odata->sess, &conn); } else { aim_conn_kill(odata->sess, &conn); } } + } else { + /* WTF??? */ + return FALSE; } + + return TRUE; } -static void oscar_login_connect(gpointer data, gint source, GaimInputCondition cond) +static gboolean oscar_login_connect(gpointer data, gint source, b_input_condition cond) { struct gaim_connection *gc = data; struct oscar_data *odata; @@ -330,7 +335,7 @@ static void oscar_login_connect(gpointer data, gint source, GaimInputCondition c if (!g_slist_find(get_connections(), gc)) { closesocket(source); - return; + return FALSE; } odata = gc->proto_data; @@ -340,12 +345,14 @@ static void oscar_login_connect(gpointer data, gint source, GaimInputCondition c if (source < 0) { hide_login_progress(gc, _("Couldn't connect to host")); signoff(gc); - return; + return FALSE; } aim_conn_completeconnect(sess, conn); - gc->inpa = gaim_input_add(conn->fd, GAIM_INPUT_READ, + gc->inpa = b_input_add(conn->fd, GAIM_INPUT_READ, oscar_callback, conn); + + return FALSE; } static void oscar_login(struct aim_user *user) { @@ -413,7 +420,7 @@ static void oscar_close(struct gaim_connection *gc) { while (odata->oscar_chats) { struct chat_connection *n = odata->oscar_chats->data; if (n->inpa > 0) - gaim_input_remove(n->inpa); + b_event_remove(n->inpa); g_free(n->name); g_free(n->show); odata->oscar_chats = g_slist_remove(odata->oscar_chats, n); @@ -432,11 +439,11 @@ static void oscar_close(struct gaim_connection *gc) { if (odata->oldp) g_free(odata->oldp); if (gc->inpa > 0) - gaim_input_remove(gc->inpa); + b_event_remove(gc->inpa); if (odata->cnpa > 0) - gaim_input_remove(odata->cnpa); + b_event_remove(odata->cnpa); if (odata->paspa > 0) - gaim_input_remove(odata->paspa); + b_event_remove(odata->paspa); aim_session_kill(odata->sess); g_free(odata->sess); odata->sess = NULL; @@ -444,7 +451,7 @@ static void oscar_close(struct gaim_connection *gc) { gc->proto_data = NULL; } -static void oscar_bos_connect(gpointer data, gint source, GaimInputCondition cond) { +static gboolean oscar_bos_connect(gpointer data, gint source, b_input_condition cond) { struct gaim_connection *gc = data; struct oscar_data *odata; aim_session_t *sess; @@ -452,7 +459,7 @@ static void oscar_bos_connect(gpointer data, gint source, GaimInputCondition con if (!g_slist_find(get_connections(), gc)) { closesocket(source); - return; + return FALSE; } odata = gc->proto_data; @@ -462,13 +469,15 @@ static void oscar_bos_connect(gpointer data, gint source, GaimInputCondition con if (source < 0) { hide_login_progress(gc, _("Could Not Connect")); signoff(gc); - return; + return FALSE; } aim_conn_completeconnect(sess, bosconn); - gc->inpa = gaim_input_add(bosconn->fd, GAIM_INPUT_READ, + gc->inpa = b_input_add(bosconn->fd, GAIM_INPUT_READ, oscar_callback, bosconn); set_login_progress(gc, 4, _("Connection established, cookie sent")); + + return FALSE; } static int gaim_parse_auth_resp(aim_session_t *sess, aim_frame_t *fr, ...) { @@ -571,7 +580,7 @@ static int gaim_parse_auth_resp(aim_session_t *sess, aim_frame_t *fr, ...) { return 0; } aim_sendcookie(sess, bosconn, info->cookie); - gaim_input_remove(gc->inpa); + b_event_remove(gc->inpa); return 1; } @@ -586,7 +595,7 @@ struct pieceofcrap { unsigned int inpa; }; -static void damn_you(gpointer data, gint source, GaimInputCondition c) +static gboolean damn_you(gpointer data, gint source, b_input_condition c) { struct pieceofcrap *pos = data; struct oscar_data *od = pos->gc->proto_data; @@ -606,21 +615,23 @@ static void damn_you(gpointer data, gint source, GaimInputCondition c) if (in != '\n') { do_error_dialog(pos->gc, "Gaim was unable to get a valid hash for logging into AIM." " You may be disconnected shortly.", "Login Error"); - gaim_input_remove(pos->inpa); + b_event_remove(pos->inpa); closesocket(pos->fd); g_free(pos); - return; + return FALSE; } /* [WvG] Wheeeee! Who needs error checking anyway? ;-) */ read(pos->fd, m, 16); m[16] = '\0'; - gaim_input_remove(pos->inpa); + b_event_remove(pos->inpa); closesocket(pos->fd); aim_sendmemblock(od->sess, pos->conn, 0, 16, m, AIM_SENDMEMBLOCK_FLAG_ISHASH); g_free(pos); + + return FALSE; } -static void straight_to_hell(gpointer data, gint source, GaimInputCondition cond) { +static gboolean straight_to_hell(gpointer data, gint source, b_input_condition cond) { struct pieceofcrap *pos = data; char buf[BUF_LONG]; @@ -630,7 +641,7 @@ static void straight_to_hell(gpointer data, gint source, GaimInputCondition cond if (pos->modname) g_free(pos->modname); g_free(pos); - return; + return FALSE; } g_snprintf(buf, sizeof(buf), "GET " AIMHASHDATA @@ -639,8 +650,8 @@ static void straight_to_hell(gpointer data, gint source, GaimInputCondition cond write(pos->fd, buf, strlen(buf)); if (pos->modname) g_free(pos->modname); - pos->inpa = gaim_input_add(pos->fd, GAIM_INPUT_READ, damn_you, pos); - return; + pos->inpa = b_input_add(pos->fd, GAIM_INPUT_READ, damn_you, pos); + return FALSE; } /* size of icbmui.ocm, the largest module in AIM 3.5 */ @@ -762,7 +773,7 @@ static int conninitdone_chatnav(aim_session_t *sess, aim_frame_t *fr, ...) { return 1; } -static void oscar_chatnav_connect(gpointer data, gint source, GaimInputCondition cond) { +static gboolean oscar_chatnav_connect(gpointer data, gint source, b_input_condition cond) { struct gaim_connection *gc = data; struct oscar_data *odata; aim_session_t *sess; @@ -770,7 +781,7 @@ static void oscar_chatnav_connect(gpointer data, gint source, GaimInputCondition if (!g_slist_find(get_connections(), gc)) { closesocket(source); - return; + return FALSE; } odata = gc->proto_data; @@ -779,15 +790,17 @@ static void oscar_chatnav_connect(gpointer data, gint source, GaimInputCondition if (source < 0) { aim_conn_kill(sess, &tstconn); - return; + return FALSE; } aim_conn_completeconnect(sess, tstconn); - odata->cnpa = gaim_input_add(tstconn->fd, GAIM_INPUT_READ, + odata->cnpa = b_input_add(tstconn->fd, GAIM_INPUT_READ, oscar_callback, tstconn); + + return FALSE; } -static void oscar_auth_connect(gpointer data, gint source, GaimInputCondition cond) +static gboolean oscar_auth_connect(gpointer data, gint source, b_input_condition cond) { struct gaim_connection *gc = data; struct oscar_data *odata; @@ -796,7 +809,7 @@ static void oscar_auth_connect(gpointer data, gint source, GaimInputCondition co if (!g_slist_find(get_connections(), gc)) { closesocket(source); - return; + return FALSE; } odata = gc->proto_data; @@ -805,15 +818,17 @@ static void oscar_auth_connect(gpointer data, gint source, GaimInputCondition co if (source < 0) { aim_conn_kill(sess, &tstconn); - return; + return FALSE; } aim_conn_completeconnect(sess, tstconn); - odata->paspa = gaim_input_add(tstconn->fd, GAIM_INPUT_READ, + odata->paspa = b_input_add(tstconn->fd, GAIM_INPUT_READ, oscar_callback, tstconn); + + return FALSE; } -static void oscar_chat_connect(gpointer data, gint source, GaimInputCondition cond) +static gboolean oscar_chat_connect(gpointer data, gint source, b_input_condition cond) { struct chat_connection *ccon = data; struct gaim_connection *gc = ccon->gc; @@ -826,7 +841,7 @@ static void oscar_chat_connect(gpointer data, gint source, GaimInputCondition co g_free(ccon->show); g_free(ccon->name); g_free(ccon); - return; + return FALSE; } odata = gc->proto_data; @@ -838,14 +853,16 @@ static void oscar_chat_connect(gpointer data, gint source, GaimInputCondition co g_free(ccon->show); g_free(ccon->name); g_free(ccon); - return; + return FALSE; } aim_conn_completeconnect(sess, ccon->conn); - ccon->inpa = gaim_input_add(tstconn->fd, + ccon->inpa = b_input_add(tstconn->fd, GAIM_INPUT_READ, oscar_callback, tstconn); odata->oscar_chats = g_slist_append(odata->oscar_chats, ccon); + + return FALSE; } /* Hrmph. I don't know how to make this look better. --mid */ @@ -2564,7 +2581,7 @@ void oscar_chat_kill(struct gaim_connection *gc, struct chat_connection *cc) /* Destroy the chat_connection */ od->oscar_chats = g_slist_remove(od->oscar_chats, cc); if (cc->inpa > 0) - gaim_input_remove(cc->inpa); + b_event_remove(cc->inpa); aim_conn_kill(od->sess, &cc->conn); g_free(cc->name); g_free(cc->show); diff --git a/protocols/proxy.c b/protocols/proxy.c index 1ca35dfe..b8aa304d 100644 --- a/protocols/proxy.c +++ b/protocols/proxy.c @@ -20,10 +20,6 @@ * */ -/* this is a little piece of code to handle proxy connection */ -/* it is intended to : 1st handle http proxy, using the CONNECT command - , 2nd provide an easy way to add socks support */ - #define BITLBEE_CORE #include <stdio.h> #include <stdlib.h> @@ -45,10 +41,6 @@ #include "nogaim.h" #include "proxy.h" -#define GAIM_READ_COND (G_IO_IN | G_IO_HUP | G_IO_ERR) -#define GAIM_WRITE_COND (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL) -#define GAIM_ERR_COND (G_IO_HUP | G_IO_ERR | G_IO_NVAL) - char proxyhost[128] = ""; int proxyport = 0; int proxytype = PROXY_NONE; @@ -56,7 +48,7 @@ char proxyuser[128] = ""; char proxypass[128] = ""; struct PHB { - GaimInputFunction func, proxy_func; + b_event_handler func, proxy_func; gpointer data, proxy_data; char *host; int port; @@ -64,12 +56,6 @@ struct PHB { gint inpa; }; -typedef struct _GaimIOClosure { - GaimInputFunction function; - guint result; - gpointer data; -} GaimIOClosure; - static struct sockaddr_in *gaim_gethostbyname(const char *host, int port) @@ -91,27 +77,7 @@ static struct sockaddr_in *gaim_gethostbyname(const char *host, int port) return &sin; } -static void gaim_io_destroy(gpointer data) -{ - g_free(data); -} - -static gboolean gaim_io_invoke(GIOChannel *source, GIOCondition condition, gpointer data) -{ - GaimIOClosure *closure = data; - GaimInputCondition gaim_cond = 0; - - if (condition & GAIM_READ_COND) - gaim_cond |= GAIM_INPUT_READ; - if (condition & GAIM_WRITE_COND) - gaim_cond |= GAIM_INPUT_WRITE; - - closure->function(closure->data, g_io_channel_unix_get_fd(source), gaim_cond); - - return TRUE; -} - -static void gaim_io_connected(gpointer data, gint source, GaimInputCondition cond) +static gboolean gaim_io_connected(gpointer data, gint source, b_input_condition cond) { struct PHB *phb = data; unsigned int len; @@ -121,24 +87,26 @@ static void gaim_io_connected(gpointer data, gint source, GaimInputCondition con #ifndef _WIN32 if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { closesocket(source); - gaim_input_remove(phb->inpa); + b_event_remove(phb->inpa); if( phb->proxy_func ) phb->proxy_func(phb->proxy_data, -1, GAIM_INPUT_READ); else { phb->func(phb->data, -1, GAIM_INPUT_READ); g_free(phb); } - return; + return FALSE; } #endif sock_make_blocking(source); - gaim_input_remove(phb->inpa); + b_event_remove(phb->inpa); if( phb->proxy_func ) phb->proxy_func(phb->proxy_data, source, GAIM_INPUT_READ); else { phb->func(phb->data, source, GAIM_INPUT_READ); g_free(phb); } + + return FALSE; } static int proxy_connect_none(const char *host, unsigned short port, struct PHB *phb) @@ -157,10 +125,12 @@ static int proxy_connect_none(const char *host, unsigned short port, struct PHB } sock_make_nonblocking(fd); - + + event_debug("proxy_connect_none( \"%s\", %d ) = %d\n", host, port, fd); + if (connect(fd, (struct sockaddr *)sin, sizeof(*sin)) < 0) { if (sockerr_again()) { - phb->inpa = gaim_input_add(fd, GAIM_INPUT_WRITE, gaim_io_connected, phb); + phb->inpa = b_input_add(fd, GAIM_INPUT_WRITE, gaim_io_connected, phb); phb->fd = fd; } else { closesocket(fd); @@ -178,14 +148,14 @@ static int proxy_connect_none(const char *host, unsigned short port, struct PHB #define HTTP_GOODSTRING "HTTP/1.0 200 Connection established" #define HTTP_GOODSTRING2 "HTTP/1.1 200 Connection established" -static void http_canread(gpointer data, gint source, GaimInputCondition cond) +static gboolean http_canread(gpointer data, gint source, b_input_condition cond) { int nlc = 0; int pos = 0; struct PHB *phb = data; char inputline[8192]; - gaim_input_remove(phb->inpa); + b_event_remove(phb->inpa); while ((pos < sizeof(inputline)-1) && (nlc != 2) && (read(source, &inputline[pos++], 1) == 1)) { if (inputline[pos - 1] == '\n') @@ -200,31 +170,32 @@ static void http_canread(gpointer data, gint source, GaimInputCondition cond) phb->func(phb->data, source, GAIM_INPUT_READ); g_free(phb->host); g_free(phb); - return; + return FALSE; } close(source); phb->func(phb->data, -1, GAIM_INPUT_READ); g_free(phb->host); g_free(phb); - return; + + return FALSE; } -static void http_canwrite(gpointer data, gint source, GaimInputCondition cond) +static gboolean http_canwrite(gpointer data, gint source, b_input_condition cond) { char cmd[384]; struct PHB *phb = data; unsigned int len; int error = ETIMEDOUT; if (phb->inpa > 0) - gaim_input_remove(phb->inpa); + b_event_remove(phb->inpa); len = sizeof(error); if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { close(source); phb->func(phb->data, -1, GAIM_INPUT_READ); g_free(phb->host); g_free(phb); - return; + return FALSE; } sock_make_blocking(source); @@ -235,7 +206,7 @@ static void http_canwrite(gpointer data, gint source, GaimInputCondition cond) phb->func(phb->data, -1, GAIM_INPUT_READ); g_free(phb->host); g_free(phb); - return; + return FALSE; } if (proxyuser && *proxyuser) { @@ -250,7 +221,7 @@ static void http_canwrite(gpointer data, gint source, GaimInputCondition cond) phb->func(phb->data, -1, GAIM_INPUT_READ); g_free(phb->host); g_free(phb); - return; + return FALSE; } } @@ -260,10 +231,12 @@ static void http_canwrite(gpointer data, gint source, GaimInputCondition cond) phb->func(phb->data, -1, GAIM_INPUT_READ); g_free(phb->host); g_free(phb); - return; + return FALSE; } - phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, http_canread, phb); + phb->inpa = b_input_add(source, GAIM_INPUT_READ, http_canread, phb); + + return FALSE; } static int proxy_connect_http(const char *host, unsigned short port, struct PHB *phb) @@ -279,28 +252,30 @@ static int proxy_connect_http(const char *host, unsigned short port, struct PHB /* Connecting to SOCKS4 proxies */ -static void s4_canread(gpointer data, gint source, GaimInputCondition cond) +static gboolean s4_canread(gpointer data, gint source, b_input_condition cond) { unsigned char packet[12]; struct PHB *phb = data; - gaim_input_remove(phb->inpa); + b_event_remove(phb->inpa); memset(packet, 0, sizeof(packet)); if (read(source, packet, 9) >= 4 && packet[1] == 90) { phb->func(phb->data, source, GAIM_INPUT_READ); g_free(phb->host); g_free(phb); - return; + return FALSE; } close(source); phb->func(phb->data, -1, GAIM_INPUT_READ); g_free(phb->host); g_free(phb); + + return FALSE; } -static void s4_canwrite(gpointer data, gint source, GaimInputCondition cond) +static gboolean s4_canwrite(gpointer data, gint source, b_input_condition cond) { unsigned char packet[12]; struct hostent *hp; @@ -308,14 +283,14 @@ static void s4_canwrite(gpointer data, gint source, GaimInputCondition cond) unsigned int len; int error = ETIMEDOUT; if (phb->inpa > 0) - gaim_input_remove(phb->inpa); + b_event_remove(phb->inpa); len = sizeof(error); if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { close(source); phb->func(phb->data, -1, GAIM_INPUT_READ); g_free(phb->host); g_free(phb); - return; + return FALSE; } sock_make_blocking(source); @@ -325,7 +300,7 @@ static void s4_canwrite(gpointer data, gint source, GaimInputCondition cond) phb->func(phb->data, -1, GAIM_INPUT_READ); g_free(phb->host); g_free(phb); - return; + return FALSE; } packet[0] = 4; @@ -342,10 +317,12 @@ static void s4_canwrite(gpointer data, gint source, GaimInputCondition cond) phb->func(phb->data, -1, GAIM_INPUT_READ); g_free(phb->host); g_free(phb); - return; + return FALSE; } - phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s4_canread, phb); + phb->inpa = b_input_add(source, GAIM_INPUT_READ, s4_canread, phb); + + return FALSE; } static int proxy_connect_socks4(const char *host, unsigned short port, struct PHB *phb) @@ -361,32 +338,33 @@ static int proxy_connect_socks4(const char *host, unsigned short port, struct PH /* Connecting to SOCKS5 proxies */ -static void s5_canread_again(gpointer data, gint source, GaimInputCondition cond) +static gboolean s5_canread_again(gpointer data, gint source, b_input_condition cond) { unsigned char buf[512]; struct PHB *phb = data; - gaim_input_remove(phb->inpa); + b_event_remove(phb->inpa); if (read(source, buf, 10) < 10) { close(source); phb->func(phb->data, -1, GAIM_INPUT_READ); g_free(phb->host); g_free(phb); - return; + return FALSE; } if ((buf[0] != 0x05) || (buf[1] != 0x00)) { close(source); phb->func(phb->data, -1, GAIM_INPUT_READ); g_free(phb->host); g_free(phb); - return; + return FALSE; } phb->func(phb->data, source, GAIM_INPUT_READ); g_free(phb->host); g_free(phb); - return; + + return FALSE; } static void s5_sendconnect(gpointer data, gint source) @@ -394,7 +372,7 @@ static void s5_sendconnect(gpointer data, gint source) unsigned char buf[512]; struct PHB *phb = data; int hlen = strlen(phb->host); - + buf[0] = 0x05; buf[1] = 0x01; /* CONNECT */ buf[2] = 0x00; /* reserved */ @@ -412,22 +390,22 @@ static void s5_sendconnect(gpointer data, gint source) return; } - phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s5_canread_again, phb); + phb->inpa = b_input_add(source, GAIM_INPUT_READ, s5_canread_again, phb); } -static void s5_readauth(gpointer data, gint source, GaimInputCondition cond) +static gboolean s5_readauth(gpointer data, gint source, b_input_condition cond) { unsigned char buf[512]; struct PHB *phb = data; - gaim_input_remove(phb->inpa); + b_event_remove(phb->inpa); if (read(source, buf, 2) < 2) { close(source); phb->func(phb->data, -1, GAIM_INPUT_READ); g_free(phb->host); g_free(phb); - return; + return FALSE; } if ((buf[0] != 0x01) || (buf[1] != 0x00)) { @@ -435,25 +413,27 @@ static void s5_readauth(gpointer data, gint source, GaimInputCondition cond) phb->func(phb->data, -1, GAIM_INPUT_READ); g_free(phb->host); g_free(phb); - return; + return FALSE; } s5_sendconnect(phb, source); + + return FALSE; } -static void s5_canread(gpointer data, gint source, GaimInputCondition cond) +static gboolean s5_canread(gpointer data, gint source, b_input_condition cond) { unsigned char buf[512]; struct PHB *phb = data; - gaim_input_remove(phb->inpa); + b_event_remove(phb->inpa); if (read(source, buf, 2) < 2) { close(source); phb->func(phb->data, -1, GAIM_INPUT_READ); g_free(phb->host); g_free(phb); - return; + return FALSE; } if ((buf[0] != 0x05) || (buf[1] == 0xff)) { @@ -461,7 +441,7 @@ static void s5_canread(gpointer data, gint source, GaimInputCondition cond) phb->func(phb->data, -1, GAIM_INPUT_READ); g_free(phb->host); g_free(phb); - return; + return FALSE; } if (buf[1] == 0x02) { @@ -476,16 +456,18 @@ static void s5_canread(gpointer data, gint source, GaimInputCondition cond) phb->func(phb->data, -1, GAIM_INPUT_READ); g_free(phb->host); g_free(phb); - return; + return FALSE; } - phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s5_readauth, phb); + phb->inpa = b_input_add(source, GAIM_INPUT_READ, s5_readauth, phb); } else { s5_sendconnect(phb, source); } + + return FALSE; } -static void s5_canwrite(gpointer data, gint source, GaimInputCondition cond) +static gboolean s5_canwrite(gpointer data, gint source, b_input_condition cond) { unsigned char buf[512]; int i; @@ -493,14 +475,14 @@ static void s5_canwrite(gpointer data, gint source, GaimInputCondition cond) unsigned int len; int error = ETIMEDOUT; if (phb->inpa > 0) - gaim_input_remove(phb->inpa); + b_event_remove(phb->inpa); len = sizeof(error); if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { close(source); phb->func(phb->data, -1, GAIM_INPUT_READ); g_free(phb->host); g_free(phb); - return; + return FALSE; } sock_make_blocking(source); @@ -522,10 +504,12 @@ static void s5_canwrite(gpointer data, gint source, GaimInputCondition cond) phb->func(phb->data, -1, GAIM_INPUT_READ); g_free(phb->host); g_free(phb); - return; + return FALSE; } - phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s5_canread, phb); + phb->inpa = b_input_add(source, GAIM_INPUT_READ, s5_canread, phb); + + return FALSE; } static int proxy_connect_socks5(const char *host, unsigned short port, struct PHB *phb) @@ -541,35 +525,7 @@ static int proxy_connect_socks5(const char *host, unsigned short port, struct PH /* Export functions */ -gint gaim_input_add(gint source, GaimInputCondition condition, GaimInputFunction function, gpointer data) -{ - GaimIOClosure *closure = g_new0(GaimIOClosure, 1); - GIOChannel *channel; - GIOCondition cond = 0; - - closure->function = function; - closure->data = data; - - if (condition & GAIM_INPUT_READ) - cond |= GAIM_READ_COND; - if (condition & GAIM_INPUT_WRITE) - cond |= GAIM_WRITE_COND; - - channel = g_io_channel_unix_new(source); - closure->result = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond, - gaim_io_invoke, closure, gaim_io_destroy); - - g_io_channel_unref(channel); - return closure->result; -} - -void gaim_input_remove(gint tag) -{ - if (tag > 0) - g_source_remove(tag); -} - -int proxy_connect(const char *host, int port, GaimInputFunction func, gpointer data) +int proxy_connect(const char *host, int port, b_event_handler func, gpointer data) { struct PHB *phb; diff --git a/protocols/proxy.h b/protocols/proxy.h index 47c966d2..680790a5 100644 --- a/protocols/proxy.h +++ b/protocols/proxy.h @@ -1,5 +1,5 @@ /* - * gaim + * nogaim * * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net> * @@ -35,6 +35,8 @@ #include <glib.h> #include <gmodule.h> +#include "events.h" + #define PROXY_NONE 0 #define PROXY_HTTP 1 #define PROXY_SOCKS4 2 @@ -46,15 +48,6 @@ extern int proxytype; extern char proxyuser[128]; extern char proxypass[128]; -typedef enum { - GAIM_INPUT_READ = 1 << 0, - GAIM_INPUT_WRITE = 1 << 1 -} GaimInputCondition; -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(const char *host, int port, GaimInputFunction func, gpointer data); +G_MODULE_EXPORT int proxy_connect(const char *host, int port, b_event_handler func, gpointer data); #endif /* _PROXY_H_ */ diff --git a/protocols/ssl_bogus.c b/protocols/ssl_bogus.c index 52406b75..00aaa7c4 100644 --- a/protocols/ssl_bogus.c +++ b/protocols/ssl_bogus.c @@ -51,7 +51,7 @@ int ssl_getfd( void *conn ) return( -1 ); } -GaimInputCondition ssl_getdirection( void *conn ) +b_input_condition ssl_getdirection( void *conn ) { return GAIM_INPUT_READ; } diff --git a/protocols/ssl_client.h b/protocols/ssl_client.h index 89189db9..1a9c79e9 100644 --- a/protocols/ssl_client.h +++ b/protocols/ssl_client.h @@ -32,11 +32,11 @@ extern int ssl_errno; -typedef void (*ssl_input_function)(gpointer, void*, GaimInputCondition); +typedef gboolean (*ssl_input_function)(gpointer, void*, b_input_condition); G_MODULE_EXPORT void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data ); G_MODULE_EXPORT int ssl_read( void *conn, char *buf, int len ); G_MODULE_EXPORT int ssl_write( void *conn, const char *buf, int len ); G_MODULE_EXPORT void ssl_disconnect( void *conn_ ); G_MODULE_EXPORT int ssl_getfd( void *conn ); -G_MODULE_EXPORT GaimInputCondition ssl_getdirection( void *conn ); +G_MODULE_EXPORT b_input_condition ssl_getdirection( void *conn ); diff --git a/protocols/ssl_gnutls.c b/protocols/ssl_gnutls.c index f2cb3e08..3ebe1756 100644 --- a/protocols/ssl_gnutls.c +++ b/protocols/ssl_gnutls.c @@ -47,7 +47,7 @@ struct scd gnutls_certificate_credentials xcred; }; -static void ssl_connected( gpointer data, gint source, GaimInputCondition cond ); +static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ); void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data ) @@ -80,9 +80,9 @@ void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data return( conn ); } -static void ssl_handshake( gpointer data, gint source, GaimInputCondition cond ); +static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond ); -static void ssl_connected( gpointer data, gint source, GaimInputCondition cond ) +static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ) { struct scd *conn = data; @@ -95,32 +95,26 @@ static void ssl_connected( gpointer data, gint source, GaimInputCondition cond ) g_free( conn ); - return; + return FALSE; } sock_make_nonblocking( conn->fd ); gnutls_transport_set_ptr( conn->session, (gnutls_transport_ptr) conn->fd ); - ssl_handshake( data, source, cond ); + return ssl_handshake( data, source, cond ); } -static void ssl_handshake( gpointer data, gint source, GaimInputCondition cond ) +static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond ) { struct scd *conn = data; int st; - if( conn->inpa != -1 ) - { - gaim_input_remove( conn->inpa ); - conn->inpa = -1; - } - if( ( st = gnutls_handshake( conn->session ) ) < 0 ) { if( st == GNUTLS_E_AGAIN || st == GNUTLS_E_INTERRUPTED ) { - conn->inpa = gaim_input_add( conn->fd, ssl_getdirection( conn ), - ssl_handshake, data ); + conn->inpa = b_input_add( conn->fd, ssl_getdirection( conn ), + ssl_handshake, data ); } else { @@ -141,6 +135,8 @@ static void ssl_handshake( gpointer data, gint source, GaimInputCondition cond ) conn->established = TRUE; conn->func( conn->data, conn, cond ); } + + return FALSE; } int ssl_read( void *conn, char *buf, int len ) @@ -186,7 +182,7 @@ void ssl_disconnect( void *conn_ ) struct scd *conn = conn_; if( conn->inpa != -1 ) - gaim_input_remove( conn->inpa ); + b_event_remove( conn->inpa ); if( conn->established ) gnutls_bye( conn->session, GNUTLS_SHUT_WR ); @@ -203,7 +199,7 @@ int ssl_getfd( void *conn ) return( ((struct scd*)conn)->fd ); } -GaimInputCondition ssl_getdirection( void *conn ) +b_input_condition ssl_getdirection( void *conn ) { return( gnutls_record_get_direction( ((struct scd*)conn)->session ) ? GAIM_INPUT_WRITE : GAIM_INPUT_READ ); diff --git a/protocols/ssl_nss.c b/protocols/ssl_nss.c index 00d32834..218b3a80 100644 --- a/protocols/ssl_nss.c +++ b/protocols/ssl_nss.c @@ -51,7 +51,7 @@ struct scd gboolean established; }; -static void ssl_connected( gpointer data, gint source, GaimInputCondition cond ); +static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ); static SECStatus nss_auth_cert (void *arg, PRFileDesc *socket, PRBool checksig, PRBool isserver) @@ -115,7 +115,7 @@ void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data return( conn ); } -static void ssl_connected( gpointer data, gint source, GaimInputCondition cond ) +static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ) { struct scd *conn = data; @@ -139,7 +139,7 @@ static void ssl_connected( gpointer data, gint source, GaimInputCondition cond ) conn->established = TRUE; conn->func( conn->data, conn, cond ); - return; + return FALSE; ssl_connected_failure: @@ -148,6 +148,8 @@ static void ssl_connected( gpointer data, gint source, GaimInputCondition cond ) PR_Close( conn -> prfd ); if( source >= 0 ) closesocket( source ); g_free( conn ); + + return FALSE; } int ssl_read( void *conn, char *buf, int len ) @@ -181,7 +183,7 @@ int ssl_getfd( void *conn ) return( ((struct scd*)conn)->fd ); } -GaimInputCondition ssl_getdirection( void *conn ) +b_input_condition ssl_getdirection( void *conn ) { /* Just in case someone calls us, let's return the most likely case: */ return GAIM_INPUT_READ; diff --git a/protocols/ssl_openssl.c b/protocols/ssl_openssl.c index b79088cc..b6f6c520 100644 --- a/protocols/ssl_openssl.c +++ b/protocols/ssl_openssl.c @@ -51,8 +51,7 @@ struct scd SSL_CTX *ssl_ctx; }; -static void ssl_connected( gpointer data, gint source, GaimInputCondition cond ); - +static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ); void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data ) @@ -94,47 +93,41 @@ void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data return( conn ); } -static void ssl_handshake( gpointer data, gint source, GaimInputCondition cond ); +static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond ); -static void ssl_connected( gpointer data, gint source, GaimInputCondition cond ) +static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ) { struct scd *conn = data; if( source == -1 ) return ssl_handshake( data, -1, cond ); - /* Make it non-blocking at least during the handshake... */ + /* We can do at least the handshake with non-blocking I/O */ sock_make_nonblocking( conn->fd ); SSL_set_fd( conn->ssl, conn->fd ); return ssl_handshake( data, source, cond ); } -static void ssl_handshake( gpointer data, gint source, GaimInputCondition cond ) +static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond ) { struct scd *conn = data; int st; - if( conn->inpa != -1 ) - { - gaim_input_remove( conn->inpa ); - conn->inpa = -1; - } - if( ( st = SSL_connect( conn->ssl ) ) < 0 ) { conn->lasterr = SSL_get_error( conn->ssl, st ); if( conn->lasterr != SSL_ERROR_WANT_READ && conn->lasterr != SSL_ERROR_WANT_WRITE ) goto ssl_connected_failure; - conn->inpa = gaim_input_add( conn->fd, ssl_getdirection( conn ), ssl_handshake, data ); - return; + conn->inpa = b_input_add( conn->fd, ssl_getdirection( conn ), ssl_handshake, data ); + return FALSE; } conn->established = TRUE; sock_make_blocking( conn->fd ); /* For now... */ conn->func( conn->data, conn, cond ); - return; + return FALSE; ssl_connected_failure: conn->func( conn->data, NULL, cond ); @@ -150,6 +143,8 @@ ssl_connected_failure: } if( source >= 0 ) closesocket( source ); g_free( conn ); + + return FALSE; } int ssl_read( void *conn, char *buf, int len ) @@ -203,7 +198,7 @@ void ssl_disconnect( void *conn_ ) struct scd *conn = conn_; if( conn->inpa != -1 ) - gaim_input_remove( conn->inpa ); + b_event_remove( conn->inpa ); if( conn->established ) SSL_shutdown( conn->ssl ); @@ -220,7 +215,7 @@ int ssl_getfd( void *conn ) return( ((struct scd*)conn)->fd ); } -GaimInputCondition ssl_getdirection( void *conn ) +b_input_condition ssl_getdirection( void *conn ) { return( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ? GAIM_INPUT_WRITE : GAIM_INPUT_READ ); } diff --git a/protocols/yahoo/yahoo.c b/protocols/yahoo/yahoo.c index 1c3c73d9..79c0febb 100644 --- a/protocols/yahoo/yahoo.c +++ b/protocols/yahoo/yahoo.c @@ -442,7 +442,7 @@ struct byahoo_connect_callback_data int id; }; -void byahoo_connect_callback( gpointer data, gint source, GaimInputCondition cond ) +void byahoo_connect_callback( gpointer data, gint source, b_input_condition cond ) { struct byahoo_connect_callback_data *d = data; @@ -464,18 +464,17 @@ struct byahoo_read_ready_data gpointer data; }; -void byahoo_read_ready_callback( gpointer data, gint source, GaimInputCondition cond ) +gboolean byahoo_read_ready_callback( gpointer data, gint source, b_input_condition cond ) { struct byahoo_read_ready_data *d = data; if( !byahoo_get_gc_by_id( d->id ) ) - { /* WTF doesn't libyahoo clean this up? */ - ext_yahoo_remove_handler( d->id, d->tag ); - return; - } + return FALSE; yahoo_read_ready( d->id, d->fd, d->data ); + + return TRUE; } struct byahoo_write_ready_data @@ -486,18 +485,17 @@ struct byahoo_write_ready_data gpointer data; }; -void byahoo_write_ready_callback( gpointer data, gint source, GaimInputCondition cond ) +gboolean byahoo_write_ready_callback( gpointer data, gint source, b_input_condition cond ) { struct byahoo_write_ready_data *d = data; if( !byahoo_get_gc_by_id( d->id ) ) - { /* WTF doesn't libyahoo clean this up? */ - ext_yahoo_remove_handler( d->id, d->tag ); - return; - } + return FALSE; yahoo_write_ready( d->id, d->fd, d->data ); + + return FALSE; } void ext_yahoo_login_response( int id, int succ, char *url ) @@ -686,7 +684,7 @@ int ext_yahoo_add_handler( int id, int fd, yahoo_input_condition cond, void *dat d->data = data; inp->d = d; - d->tag = inp->h = gaim_input_add( fd, GAIM_INPUT_READ, (GaimInputFunction) byahoo_read_ready_callback, (gpointer) d ); + d->tag = inp->h = b_input_add( fd, GAIM_INPUT_READ, (b_event_handler) byahoo_read_ready_callback, (gpointer) d ); } else if( cond == YAHOO_INPUT_WRITE ) { @@ -697,7 +695,7 @@ int ext_yahoo_add_handler( int id, int fd, yahoo_input_condition cond, void *dat d->data = data; inp->d = d; - d->tag = inp->h = gaim_input_add( fd, GAIM_INPUT_WRITE, (GaimInputFunction) byahoo_write_ready_callback, (gpointer) d ); + d->tag = inp->h = b_input_add( fd, GAIM_INPUT_WRITE, (b_event_handler) byahoo_write_ready_callback, (gpointer) d ); } else { @@ -728,7 +726,7 @@ void ext_yahoo_remove_handler( int id, int tag ) l = l->next; } - gaim_input_remove( tag ); + b_event_remove( tag ); } int ext_yahoo_connect_async( int id, char *host, int port, yahoo_connect_callback callback, void *data ) @@ -737,7 +735,7 @@ int ext_yahoo_connect_async( int id, char *host, int port, yahoo_connect_callbac int fd; d = g_new0( struct byahoo_connect_callback_data, 1 ); - if( ( fd = proxy_connect( host, port, (GaimInputFunction) byahoo_connect_callback, (gpointer) d ) ) < 0 ) + if( ( fd = proxy_connect( host, port, (b_event_handler) byahoo_connect_callback, (gpointer) d ) ) < 0 ) { g_free( d ); return( fd ); diff --git a/root_commands.c b/root_commands.c index d8611347..225912b7 100644 --- a/root_commands.c +++ b/root_commands.c @@ -141,8 +141,9 @@ static void cmd_identify( irc_t *irc, char **cmd ) irc_usermsg( irc, "Password accepted" ); irc_umode_set( irc, "+R", 1 ); break; + case STORAGE_OTHER_ERROR: default: - irc_usermsg( irc, "Something very weird happened" ); + irc_usermsg( irc, "Unknown error while loading configuration" ); break; } } @@ -200,7 +201,7 @@ static void cmd_account( irc_t *irc, char **cmd ) { account_t *a; - if( global.conf->authmode == AUTHMODE_REGISTERED && ! irc->status & USTATUS_IDENTIFIED ) + if( global.conf->authmode == AUTHMODE_REGISTERED && !( irc->status & USTATUS_IDENTIFIED ) ) { irc_usermsg( irc, "This server only accepts registered users" ); return; @@ -17,7 +17,9 @@ #define sock_make_nonblocking(fd) fcntl(fd, F_SETFL, O_NONBLOCK) #define sock_make_blocking(fd) fcntl(fd, F_SETFL, 0) #define sockerr_again() (errno == EINPROGRESS || errno == EINTR) +#ifndef EVENTS_LIBEVENT #define closesocket(a) close(a) +#endif #else # include <winsock2.h> # ifndef _MSC_VER @@ -6,6 +6,8 @@ /* Support for multiple storage backends */ +/* Copyright (C) 2005 Jelmer Vernooij <jelmer@samba.org> */ + /* 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 @@ -28,9 +30,9 @@ #include "crypting.h" extern storage_t storage_text; +extern storage_t storage_xml; -static GList text_entry = { &storage_text, NULL, NULL }; -static GList *storage_backends = &text_entry; +static GList *storage_backends = NULL; void register_storage_backend(storage_t *backend) { @@ -62,7 +64,10 @@ GList *storage_init(const char *primary, char **migrate) GList *ret = NULL; int i; storage_t *storage; - + + register_storage_backend(&storage_text); + register_storage_backend(&storage_xml); + storage = storage_init_single(primary); if (storage == NULL) return NULL; @@ -32,8 +32,8 @@ typedef enum { 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 */ + a database that is unreachable. log() will be + used for the exact error message */ } storage_status_t; typedef struct { diff --git a/storage_ldap.c b/storage_ldap.c new file mode 100644 index 00000000..4bc99de5 --- /dev/null +++ b/storage_ldap.c @@ -0,0 +1,177 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2004 Wilmer van der Gaast and others * + \********************************************************************/ + +/* Storage backend that uses a LDAP database */ + +/* Copyright (C) 2006 Jelmer Vernooij <jelmer@samba.org> */ + +/* + 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 <ldap.h> + +#define BB_LDAP_HOST "localhost" +#define BB_LDAP_BASE "" + +static char *nick_dn(const char *nick) +{ + return g_strdup_printf("bitlBeeNick=%s%s%s", nick, BB_LDAP_BASE?",":"", BB_LDAP_BASE?BB_LDAP_BASE:""); +} + +static storage_status_t nick_connect(const char *nick, const char *password, LDAP **ld) +{ + char *mydn; + int ret; + storage_status_t status; + *ld = ldap_init(BB_LDAP_HOST, LDAP_PORT); + + if (!ld) { + log_message( LOGLVL_WARNING, "Unable to connect to LDAP server at %s", BB_LDAP_HOST ); + return STORAGE_OTHER_ERROR; + } + + mydn = nick_dn(nick); + + ret = ldap_simple_bind_s(*ld, mydn, password); + + switch (ret) { + case LDAP_SUCCESS: status = STORAGE_OK; break; + case LDAP_INVALID_CREDENTIALS: status = STORAGE_INVALID_PASSWORD; break; + default: + log_message( LOGLVL_WARNING, "Unable to authenticate %s: %s", mydn, ldap_err2string(ret) ); + status = STORAGE_OTHER_ERROR; + break; + } + + g_free(mydn); + + return status; +} + +static storage_status_t sldap_load ( const char *my_nick, const char* password, irc_t *irc ) +{ + LDAPMessage *res, *msg; + LDAP *ld; + int ret, i; + storage_status_t status; + char *mydn; + + status = nick_connect(my_nick, password, &ld); + if (status != STORAGE_OK) + return status; + + mydn = nick_dn(my_nick); + + ret = ldap_search_s(ld, mydn, LDAP_SCOPE_BASE, "(objectClass=*)", NULL, 0, &res); + + if (ret != LDAP_SUCCESS) { + log_message( LOGLVL_WARNING, "Unable to search for %s: %s", mydn, ldap_err2string(ret) ); + ldap_unbind_s(ld); + return STORAGE_OTHER_ERROR; + } + + g_free(mydn); + + for (msg = ldap_first_entry(ld, res); msg; msg = ldap_next_entry(ld, msg)) { + } + + /* FIXME: Store in irc_t */ + + ldap_unbind_s(ld); + + return STORAGE_OK; +} + +static storage_status_t sldap_check_pass( const char *nick, const char *password ) +{ + LDAP *ld; + storage_status_t status; + + status = nick_connect(nick, password, &ld); + + ldap_unbind_s(ld); + + return status; +} + +static storage_status_t sldap_remove( const char *nick, const char *password ) +{ + storage_status_t status; + LDAP *ld; + char *mydn; + int ret; + + status = nick_connect(nick, password, &ld); + + if (status != STORAGE_OK) + return status; + + mydn = nick_dn(nick); + + ret = ldap_delete(ld, mydn); + + if (ret != LDAP_SUCCESS) { + log_message( LOGLVL_WARNING, "Error removing %s: %s", mydn, ldap_err2string(ret) ); + ldap_unbind_s(ld); + return STORAGE_OTHER_ERROR; + } + + ldap_unbind_s(ld); + + g_free(mydn); + return STORAGE_OK; +} + +static storage_status_t sldap_save( irc_t *irc, int overwrite ) +{ + LDAP *ld; + char *mydn; + storage_status_t status; + LDAPMessage *msg; + + status = nick_connect(irc->nick, irc->password, &ld); + if (status != STORAGE_OK) + return status; + + mydn = nick_dn(irc->nick); + + /* FIXME: Make this a bit more atomic? What if we crash after + * removing the old account but before adding the new one ? */ + if (overwrite) + sldap_remove(irc->nick, irc->password); + + g_free(mydn); + + ldap_unbind_s(ld); + + return STORAGE_OK; +} + + + +storage_t storage_ldap = { + .name = "ldap", + .check_pass = sldap_check_pass, + .remove = sldap_remove, + .load = sldap_load, + .save = sldap_save +}; diff --git a/storage_xml.c b/storage_xml.c new file mode 100644 index 00000000..5eda46cc --- /dev/null +++ b/storage_xml.c @@ -0,0 +1,381 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2006 Wilmer van der Gaast and others * + \********************************************************************/ + +/* Storage backend that uses an XMLish format for all data. */ + +/* + 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" + +typedef enum +{ + XML_PASS_CHECK_ONLY = -1, + XML_PASS_UNKNOWN = 0, + XML_PASS_OK +} xml_pass_st; + +#define XML_PASS_ERRORMSG "Wrong username or password" + +struct xml_parsedata +{ + irc_t *irc; + char *current_setting; + account_t *current_account; + char *given_nick; + char *given_pass; + xml_pass_st pass_st; +}; + +static char *xml_attr( const gchar **attr_names, const gchar **attr_values, const gchar *key ) +{ + int i; + + for( i = 0; attr_names[i]; i ++ ) + if( g_strcasecmp( attr_names[i], key ) == 0 ) + return (char*) attr_values[i]; + + return NULL; +} + +static void xml_destroy_xd( gpointer data ) +{ + struct xml_parsedata *xd = data; + + g_free( xd->given_nick ); + g_free( xd->given_pass ); + g_free( xd ); +} + +static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_name, const gchar **attr_names, const gchar **attr_values, gpointer data, GError **error ) +{ + struct xml_parsedata *xd = data; + irc_t *irc = xd->irc; + + if( g_strcasecmp( element_name, "user" ) == 0 ) + { + char *nick = xml_attr( attr_names, attr_values, "nick" ); + char *pass = xml_attr( attr_names, attr_values, "password" ); + + if( !nick || !pass ) + { + g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + "Missing attributes for %s element", element_name ); + } + else if( strcmp( nick, xd->given_nick ) == 0 && + strcmp( pass, xd->given_pass ) == 0 ) + { + if( xd->pass_st != XML_PASS_CHECK_ONLY ) + xd->pass_st = XML_PASS_OK; + } + else + { + g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + XML_PASS_ERRORMSG ); + } + } + else if( xd->pass_st < XML_PASS_OK ) + { + /* Let's not parse anything else if we only have to check + the password. */ + } + else if( g_strcasecmp( element_name, "account" ) == 0 ) + { + char *protocol, *handle, *server, *password; + struct prpl *prpl = NULL; + + handle = xml_attr( attr_names, attr_values, "handle" ); + password = xml_attr( attr_names, attr_values, "password" ); + server = xml_attr( attr_names, attr_values, "server" ); + + protocol = xml_attr( attr_names, attr_values, "protocol" ); + if( protocol ) + prpl = find_protocol( protocol ); + + if( !handle || !password ) + g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + "Missing attributes for %s element", element_name ); + else if( !prpl ) + g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + "Missing or unknown protocol %s element", element_name ); + else + { + xd->current_account = account_add( irc, prpl, handle, password ); + if( server ) + xd->current_account->server = g_strdup( server ); + } + } + else if( g_strcasecmp( element_name, "setting" ) == 0 ) + { + if( xd->current_account == NULL ) + { + char *setting; + + if( xd->current_setting ) + { + g_free( xd->current_setting ); + xd->current_setting = NULL; + } + + if( ( setting = xml_attr( attr_names, attr_values, "name" ) ) ) + xd->current_setting = g_strdup( setting ); + else + g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + "Missing attributes for %s element", element_name ); + } + } + else if( g_strcasecmp( element_name, "buddy" ) == 0 ) + { + char *handle, *nick; + + handle = xml_attr( attr_names, attr_values, "handle" ); + nick = xml_attr( attr_names, attr_values, "nick" ); + + if( xd->current_account && handle && nick ) + { + nick_set( irc, handle, xd->current_account->prpl, nick ); + } + else + { + g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + "Missing attributes for %s element", element_name ); + } + } + else + { + g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT, + "Unkown element: %s", element_name ); + } +} + +static void xml_end_element( GMarkupParseContext *ctx, const gchar *element_name, gpointer data, GError **error ) +{ + struct xml_parsedata *xd = data; + // irc_t *irc = xd->irc; + + if( g_strcasecmp( element_name, "setting" ) == 0 && xd->current_setting ) + { + g_free( xd->current_setting ); + xd->current_setting = NULL; + } + else if( g_strcasecmp( element_name, "account" ) == 0 ) + { + xd->current_account = NULL; + } +} + +static void xml_text( GMarkupParseContext *ctx, const gchar *text, gsize text_len, gpointer data, GError **error ) +{ + struct xml_parsedata *xd = data; + irc_t *irc = xd->irc; + + if( xd->pass_st < XML_PASS_OK ) + { + /* Let's not parse anything else if we only have to check + the password. */ + } + else if( g_strcasecmp( g_markup_parse_context_get_element( ctx ), "setting" ) == 0 && + xd->current_setting && xd->current_account == NULL ) + { + set_setstr( irc, xd->current_setting, (char*) text ); + g_free( xd->current_setting ); + xd->current_setting = NULL; + } +} + +GMarkupParser xml_parser = +{ + xml_start_element, + xml_end_element, + xml_text, + NULL, + NULL +}; + +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.", 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 xml_load( const char *my_nick, const char *password, irc_t *irc ) +{ + GMarkupParseContext *ctx; + struct xml_parsedata *xd; + char *fn, buf[512]; + GError *gerr = NULL; + int fd, st; + + if( irc->status & USTATUS_IDENTIFIED ) + return( 1 ); + + xd = g_new0( struct xml_parsedata, 1 ); + xd->irc = irc; + xd->given_nick = g_strdup( my_nick ); + xd->given_pass = g_strdup( password ); + nick_lc( xd->given_nick ); + + fn = g_strdup_printf( "%s%s%s", global.conf->configdir, xd->given_nick, ".xml" ); + if( ( fd = open( fn, O_RDONLY ) ) < 0 ) + { + xml_destroy_xd( xd ); + g_free( fn ); + return STORAGE_NO_SUCH_USER; + } + g_free( fn ); + + ctx = g_markup_parse_context_new( &xml_parser, 0, xd, xml_destroy_xd ); + + while( ( st = read( fd, buf, sizeof( buf ) ) ) > 0 ) + { + if( !g_markup_parse_context_parse( ctx, buf, st, &gerr ) || gerr ) + { + g_markup_parse_context_free( ctx ); + close( fd ); + + /* Slightly dirty... */ + if( gerr && strcmp( gerr->message, XML_PASS_ERRORMSG ) == 0 ) + return STORAGE_INVALID_PASSWORD; + else + { + if( gerr ) + irc_usermsg( irc, "Error from XML-parser: %s", gerr->message ); + + return STORAGE_OTHER_ERROR; + } + } + } + + g_markup_parse_context_free( ctx ); + close( fd ); + + irc->status |= USTATUS_IDENTIFIED; + + if( set_getint( irc, "auto_connect" ) ) + { + /* Can't do this directly because r_c_s alters the string */ + strcpy( buf, "account on" ); + root_command_string( irc, NULL, buf, 0 ); + } + + return STORAGE_OK; +} + +static int xml_printf( int fd, char *fmt, ... ) +{ + va_list params; + char *out; + int len; + + va_start( params, fmt ); + out = g_markup_vprintf_escaped( fmt, params ); + va_end( params ); + + len = strlen( out ); + len -= write( fd, out, len ); + g_free( out ); + + return len == 0; +} + +static storage_status_t xml_save( irc_t *irc, int overwrite ) +{ + char path[512], *path2; + set_t *set; + nick_t *nick; + account_t *acc; + int fd; + + g_snprintf( path, sizeof( path ) - 2, "%s%s%s", global.conf->configdir, irc->nick, ".xml" ); + + if( !overwrite && access( path, F_OK ) != -1 ) + return STORAGE_ALREADY_EXISTS; + + strcat( path, "~" ); + if( ( fd = open( path, O_WRONLY | O_CREAT, 0600 ) ) < 0 ) + { + irc_usermsg( irc, "Error while opening configuration file." ); + return STORAGE_OTHER_ERROR; + } + + if( !xml_printf( fd, "<user nick=\"%s\" password=\"%s\">\n", irc->nick, irc->password ) ) + goto write_error; + + for( set = irc->set; set; set = set->next ) + if( set->value && set->def ) + if( !xml_printf( fd, "\t<setting name=\"%s\">%s</setting>\n", set->key, set->value ) ) + goto write_error; + + for( acc = irc->accounts; acc; acc = acc->next ) + { + if( !xml_printf( fd, "\t<account protocol=\"%s\" handle=\"%s\" password=\"%s\" autoconnect=\"%s\"", acc->prpl->name, acc->user, acc->pass, "yes" ) ) + goto write_error; + if( acc->server && acc->server[0] && !xml_printf( fd, " server=\"%s\"", acc->server ) ) + goto write_error; + if( !xml_printf( fd, ">\n" ) ) + goto write_error; + + for( nick = irc->nicks; nick; nick = nick->next ) + if( nick->proto == acc->prpl ) + if( !xml_printf( fd, "\t\t<buddy handle=\"%s\" nick=\"%s\" />\n", nick->handle, nick->nick ) ) + goto write_error; + + if( !xml_printf( fd, "\t</account>\n" ) ) + goto write_error; + } + + if( !xml_printf( fd, "</user>\n" ) ) + goto write_error; + + close( fd ); + + path2 = g_strndup( path, strlen( path ) - 1 ); + if( rename( path, path2 ) != 0 ) + { + irc_usermsg( irc, "Error while renaming temporary configuration file." ); + + g_free( path2 ); + unlink( path ); + + return STORAGE_OTHER_ERROR; + } + + g_free( path2 ); + + return STORAGE_OK; + +write_error: + irc_usermsg( irc, "Write error. Disk full?" ); + close( fd ); + + return STORAGE_OTHER_ERROR; +} + +storage_t storage_xml = { + .name = "xml", + .init = xml_init, +// .check_pass = xml_check_pass, +// .remove = xml_remove, + .load = xml_load, + .save = xml_save +}; @@ -46,7 +46,7 @@ int main( int argc, char *argv[], char **envp ) memset( &global, 0, sizeof( global_t ) ); - global.loop = g_main_new( FALSE ); + b_main_init(); log_init(); @@ -116,7 +116,7 @@ int main( int argc, char *argv[], char **envp ) if( help_init( &(global.help) ) == NULL ) log_message( LOGLVL_WARNING, "Error opening helpfile %s.", HELP_FILE ); - g_main_run( global.loop ); + b_main_run(); if( global.restart ) { @@ -164,7 +164,7 @@ static void sighandler( int signal ) the user data now (not to mention writing them to disk), so add a timer. */ log_message( LOGLVL_ERROR, "SIGTERM received, cleaning up process." ); - g_timeout_add_full( G_PRIORITY_LOW, 1, (GSourceFunc) bitlbee_shutdown, NULL, NULL ); + b_timeout_add( 1, (b_event_handler) bitlbee_shutdown, NULL ); first = 0; } @@ -108,7 +108,7 @@ int user_del( irc_t *irc, char *nick ) if( u->away ) g_free( u->away ); if( u->handle ) g_free( u->handle ); if( u->sendbuf ) g_free( u->sendbuf ); - if( u->sendbuf_timer ) g_source_remove( u->sendbuf_timer ); + if( u->sendbuf_timer ) b_event_remove( u->sendbuf_timer ); g_free( u ); if( !g_hash_table_lookup_extended( irc->userhash, key, &okey, &ovalue ) || ovalue != u ) |