From 7308b63f3300d5b2a326edfde6c50a18bc05e3e5 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sun, 18 Dec 2005 17:21:49 +0100 Subject: Fix two typos --- doc/README | 2 +- protocols/ssl_openssl.c | 86 ++++++------------------------------------------- 2 files changed, 11 insertions(+), 77 deletions(-) diff --git a/doc/README b/doc/README index cd0085ff..12c21c51 100644 --- a/doc/README +++ b/doc/README @@ -49,7 +49,7 @@ BitlBee's only real dependency is GLib. This is available on virtually every platform. Any recent version of GLib (including 1.x versions) will work. These days, MSN Messenger clients have to connect to the MS Passport servers -through HTTPS. BitlBee can use serveral SSL libraries for this: GnuTLS, NSS +through HTTPS. BitlBee can use several SSL libraries for this: GnuTLS, NSS (which comes with Mozilla) and OpenSSL. OpenSSL is not GPL-compatible in some situations, so using GnuTLS or NSS is preferred. However, especially on *BSD, OpenSSL can be considered part of the operating system, which eliminates the diff --git a/protocols/ssl_openssl.c b/protocols/ssl_openssl.c index ae55f3f9..e62f95b9 100644 --- a/protocols/ssl_openssl.c +++ b/protocols/ssl_openssl.c @@ -4,7 +4,7 @@ * Copyright 2002-2004 Wilmer van der Gaast and others * \********************************************************************/ -/* SSL module - GnuTLS version */ +/* SSL module - OpenTLS version */ /* This program is free software; you can redistribute it and/or modify @@ -40,13 +40,11 @@ static gboolean initialized = FALSE; struct scd { - ssl_input_function func; + SslInputFunction func; gpointer data; int fd; gboolean established; - int inpa; - int lasterr; /* Necessary for SSL_get_error */ SSL *ssl; SSL_CTX *ssl_ctx; }; @@ -55,7 +53,7 @@ static void ssl_connected( gpointer data, gint source, GaimInputCondition cond ) -void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data ) +void *ssl_connect( char *host, int port, SslInputFunction func, gpointer data ) { struct scd *conn = g_new0( struct scd, 1 ); SSL_METHOD *meth; @@ -94,45 +92,19 @@ 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 void ssl_connected( gpointer data, gint source, GaimInputCondition cond ) { struct scd *conn = data; if( source == -1 ) - return ssl_handshake( data, -1, cond ); + goto ssl_connected_failure; - /* Make it non-blocking at least during the handshake... */ - 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 ) -{ - 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; - } + if( SSL_connect( conn->ssl ) < 0 ) + goto ssl_connected_failure; conn->established = TRUE; - sock_make_blocking( conn->fd ); /* For now... */ conn->func( conn->data, conn, cond ); return; @@ -154,57 +126,24 @@ ssl_connected_failure: int ssl_read( void *conn, char *buf, int len ) { - int st; - if( !((struct scd*)conn)->established ) - { - ssl_errno = SSL_NOHANDSHAKE; - return -1; - } - - st = SSL_read( ((struct scd*)conn)->ssl, buf, len ); + return( 0 ); - ssl_errno = SSL_OK; - if( st <= 0 ) - { - ((struct scd*)conn)->lasterr = SSL_get_error( ((struct scd*)conn)->ssl, st ); - if( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_READ || ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ) - ssl_errno = SSL_AGAIN; - } - - return st; + return( SSL_read( ((struct scd*)conn)->ssl, buf, len ) ); } int ssl_write( void *conn, const char *buf, int len ) { - int st; - if( !((struct scd*)conn)->established ) - { - ssl_errno = SSL_NOHANDSHAKE; - return -1; - } - - st = SSL_write( ((struct scd*)conn)->ssl, buf, len ); + return( 0 ); - ssl_errno = SSL_OK; - if( st <= 0 ) - { - ((struct scd*)conn)->lasterr = SSL_get_error( ((struct scd*)conn)->ssl, st ); - if( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_READ || ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ) - ssl_errno = SSL_AGAIN; - } - - return st; + return( SSL_write( ((struct scd*)conn)->ssl, buf, len ) ); } void ssl_disconnect( void *conn_ ) { struct scd *conn = conn_; - if( conn->inpa != -1 ) - gaim_input_remove( conn->inpa ); - if( conn->established ) SSL_shutdown( conn->ssl ); @@ -219,8 +158,3 @@ int ssl_getfd( void *conn ) { return( ((struct scd*)conn)->fd ); } - -GaimInputCondition ssl_getdirection( void *conn ) -{ - return( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ? GAIM_INPUT_WRITE : GAIM_INPUT_READ ); -} -- cgit v1.2.3 From 277674c82d3dbcb355214cbaceb34599832e1261 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Fri, 13 Jan 2006 17:41:46 +0100 Subject: Got rid of yahoo_list, since GLib has this all already. Couldn't test too well if this breaks anything, but it shouldn't. --- protocols/yahoo/Makefile | 2 +- protocols/yahoo/yahoo_list.c | 236 ------------------------------------------- protocols/yahoo/yahoo_list.h | 68 ++++--------- 3 files changed, 22 insertions(+), 284 deletions(-) delete mode 100644 protocols/yahoo/yahoo_list.c diff --git a/protocols/yahoo/Makefile b/protocols/yahoo/Makefile index e594cc1f..b4014f8a 100644 --- a/protocols/yahoo/Makefile +++ b/protocols/yahoo/Makefile @@ -9,7 +9,7 @@ -include ../../Makefile.settings # [SH] Program variables -objects = yahoo.o crypt.o libyahoo2.o yahoo_fn.o yahoo_httplib.o yahoo_list.o yahoo_util.o +objects = yahoo.o crypt.o libyahoo2.o yahoo_fn.o yahoo_httplib.o yahoo_util.o CFLAGS += -Wall -DSTDC_HEADERS -DHAVE_STRING_H -DHAVE_STRCHR -DHAVE_MEMCPY -DHAVE_GLIB LFLAGS += -r diff --git a/protocols/yahoo/yahoo_list.c b/protocols/yahoo/yahoo_list.c deleted file mode 100644 index cda631c6..00000000 --- a/protocols/yahoo/yahoo_list.c +++ /dev/null @@ -1,236 +0,0 @@ -/* - * yahoo_list.c: linked list routines - * - * Some code copyright (C) 2002-2004, Philip S Tellis - * Other code copyright Meredydd Luff - * - * 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 - * - * Some of this code was borrowed from elist.c in the eb-lite sources - * - */ - -#include - -#include "yahoo_list.h" - -YList *y_list_append(YList * list, void *data) -{ - YList *n; - YList *new_list = malloc(sizeof(YList)); - YList *attach_to = NULL; - - new_list->next = NULL; - new_list->data = data; - - for (n = list; n != NULL; n = n->next) { - attach_to = n; - } - - if (attach_to == NULL) { - new_list->prev = NULL; - return new_list; - } else { - new_list->prev = attach_to; - attach_to->next = new_list; - return list; - } -} - -YList *y_list_prepend(YList * list, void *data) -{ - YList *n = malloc(sizeof(YList)); - - n->next = list; - n->prev = NULL; - n->data = data; - if (list) - list->prev = n; - - return n; -} - -YList *y_list_concat(YList * list, YList * add) -{ - YList *l; - - if(!list) - return add; - - if(!add) - return list; - - for (l = list; l->next; l = l->next) - ; - - l->next = add; - add->prev = l; - - return list; -} - -YList *y_list_remove(YList * list, void *data) -{ - YList *n; - - for (n = list; n != NULL; n = n->next) { - if (n->data == data) { - list=y_list_remove_link(list, n); - y_list_free_1(n); - break; - } - } - - return list; -} - -/* Warning */ -/* link MUST be part of list */ -/* caller must free link using y_list_free_1 */ -YList *y_list_remove_link(YList * list, const YList * link) -{ - if (!link) - return list; - - if (link->next) - link->next->prev = link->prev; - if (link->prev) - link->prev->next = link->next; - - if (link == list) - list = link->next; - - return list; -} - -int y_list_length(const YList * list) -{ - int retval = 0; - const YList *n = list; - - for (n = list; n != NULL; n = n->next) { - retval++; - } - - return retval; -} - -/* well, you could just check for list == NULL, but that would be - * implementation dependent - */ -int y_list_empty(const YList * list) -{ - if(!list) - return 1; - else - return 0; -} - -int y_list_singleton(const YList * list) -{ - if(!list || list->next) - return 0; - return 1; -} - -YList *y_list_copy(YList * list) -{ - YList *n; - YList *copy = NULL; - - for (n = list; n != NULL; n = n->next) { - copy = y_list_append(copy, n->data); - } - - return copy; -} - -void y_list_free_1(YList * list) -{ - free(list); -} - -void y_list_free(YList * list) -{ - YList *n = list; - - while (n != NULL) { - YList *next = n->next; - free(n); - n = next; - } -} - -YList *y_list_find(YList * list, const void *data) -{ - YList *l; - for (l = list; l && l->data != data; l = l->next) - ; - - return l; -} - -void y_list_foreach(YList * list, YListFunc fn, void * user_data) -{ - for (; list; list = list->next) - fn(list->data, user_data); -} - -YList *y_list_find_custom(YList * list, const void *data, YListCompFunc comp) -{ - YList *l; - for (l = list; l; l = l->next) - if (comp(l->data, data) == 0) - return l; - - return NULL; -} - -YList *y_list_nth(YList * list, int n) -{ - int i=n; - for ( ; list && i; list = list->next, i--) - ; - - return list; -} - -YList *y_list_insert_sorted(YList * list, void *data, YListCompFunc comp) -{ - YList *l, *n, *prev = NULL; - if (!list) - return y_list_append(list, data); - - n = malloc(sizeof(YList)); - n->data = data; - for (l = list; l && comp(l->data, n->data) <= 0; l = l->next) - prev = l; - - if (l) { - n->prev = l->prev; - l->prev = n; - } else - n->prev = prev; - - n->next = l; - - if(n->prev) { - n->prev->next = n; - return list; - } else { - return n; - } - -} diff --git a/protocols/yahoo/yahoo_list.h b/protocols/yahoo/yahoo_list.h index a7a69635..0d335acd 100644 --- a/protocols/yahoo/yahoo_list.h +++ b/protocols/yahoo/yahoo_list.h @@ -20,55 +20,29 @@ * */ -/* - * This is a replacement for the GList. It only provides functions that - * we use in Ayttm. Thanks to Meredyyd from everybuddy dev for doing - * most of it. - */ - #ifndef __YLIST_H__ #define __YLIST_H__ -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct _YList { - struct _YList *next; - struct _YList *prev; - void *data; -} YList; - -typedef int (*YListCompFunc) (const void *, const void *); -typedef void (*YListFunc) (void *, void *); - -YList *y_list_append(YList * list, void *data); -YList *y_list_prepend(YList * list, void *data); -YList *y_list_remove_link(YList * list, const YList * link); -YList *y_list_remove(YList * list, void *data); - -YList *y_list_insert_sorted(YList * list, void * data, YListCompFunc comp); +/* GLib has linked list already, so I don't see why libyahoo2 has to copy this... */ + +typedef GList YList; + +#define y_list_append g_list_append +#define y_list_concat g_list_concat +#define y_list_copy g_list_copy +#define y_list_empty g_list_empty +#define y_list_find g_list_find +#define y_list_find_custom g_list_find_custom +#define y_list_foreach g_list_foreach +#define y_list_free g_list_free +#define y_list_free_1 g_list_free_1 +#define y_list_insert_sorted g_list_insert_sorted +#define y_list_length g_list_length +#define y_list_next g_list_next +#define y_list_nth g_list_nth +#define y_list_prepend g_list_prepend +#define y_list_remove g_list_remove +#define y_list_remove_link g_list_remove_link +#define y_list_singleton g_list_singleton -YList *y_list_copy(YList * list); - -YList *y_list_concat(YList * list, YList * add); - -YList *y_list_find(YList * list, const void *data); -YList *y_list_find_custom(YList * list, const void *data, YListCompFunc comp); - -YList *y_list_nth(YList * list, int n); - -void y_list_foreach(YList * list, YListFunc fn, void *user_data); - -void y_list_free_1(YList * list); -void y_list_free(YList * list); -int y_list_length(const YList * list); -int y_list_empty(const YList * list); -int y_list_singleton(const YList * list); - -#define y_list_next(list) list->next - -#ifdef __cplusplus -} -#endif #endif -- cgit v1.2.3 From 5c577bd5e2ee33dbe7389df6f4baf659c34de365 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Fri, 13 Jan 2006 23:10:29 +0100 Subject: IPC code (by no means final) --- bitlbee.c | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++------------ bitlbee.h | 3 +- irc.c | 4 ++ 3 files changed, 136 insertions(+), 31 deletions(-) diff --git a/bitlbee.c b/bitlbee.c index 6e36bd12..0e90b912 100644 --- a/bitlbee.c +++ b/bitlbee.c @@ -32,39 +32,17 @@ #include #include -gboolean bitlbee_io_new_client( GIOChannel *source, GIOCondition condition, gpointer data ) +struct bitlbee_child { - size_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; - - if( global.conf->runmode == RUNMODE_FORKDAEMON ) - client_pid = fork(); - - if( client_pid == 0 ) - { - log_message( LOGLVL_INFO, "Creating new connection with fd %d.", new_socket ); - irc_new( new_socket ); - - if( global.conf->runmode == RUNMODE_FORKDAEMON ) - { - /* Close the listening socket, we're a client. */ - close( global.listen_socket ); - g_source_remove( global.listen_watch_source_id ); - } - } - else - { - /* We don't need this one, only the client does. */ - close( new_socket ); - } - - return TRUE; -} - + pid_t pid; + int ipc_fd; + gint ipc_inpa; +}; +static GSList *child_list = NULL; +gboolean bitlbee_io_new_client( GIOChannel *source, GIOCondition condition, gpointer data ); + int bitlbee_daemon_init() { #ifdef IPV6 @@ -277,6 +255,71 @@ gboolean bitlbee_io_current_client_write( GIOChannel *source, GIOCondition condi } } +gboolean bitlbee_io_master_ipc_read( gpointer data, gint source, GaimInputCondition cond ); +gboolean bitlbee_io_child_ipc_read( gpointer data, gint source, GaimInputCondition cond ); + +gboolean bitlbee_io_new_client( GIOChannel *source, GIOCondition condition, gpointer data ) +{ + size_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; + + if( global.conf->runmode == RUNMODE_FORKDAEMON ) + { + int fds[2]; + + if( socketpair( AF_UNIX, SOCK_STREAM, 0, fds ) == -1 ) + { + log_message( LOGLVL_WARNING, "Could not create IPC socket for client: %s", strerror( errno ) ); + fds[0] = fds[1] = -1; + } + + sock_make_nonblocking( fds[0] ); + sock_make_nonblocking( fds[1] ); + + client_pid = fork(); + + if( client_pid > 0 && fds[0] != -1 ) + { + struct bitlbee_child *child; + + 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, bitlbee_io_master_ipc_read, child ); + child_list = g_slist_append( child_list, child ); + + close( fds[1] ); + } + else if( client_pid == 0 ) + { + /* Close the listening socket, we're a client. */ + close( global.listen_socket ); + g_source_remove( global.listen_watch_source_id ); + + /* 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, bitlbee_io_child_ipc_read, NULL ); + + close( fds[0] ); + } + } + + if( client_pid == 0 ) + { + log_message( LOGLVL_INFO, "Creating new connection with fd %d.", new_socket ); + irc_new( new_socket ); + } + else + { + /* We don't need this one, only the client does. */ + close( new_socket ); + } + + return TRUE; +} + void bitlbee_shutdown( gpointer data ) { /* Try to save data for all active connections (if desired). */ @@ -286,3 +329,60 @@ void bitlbee_shutdown( gpointer data ) /* We'll only reach this point when not running in inetd mode: */ g_main_quit( global.loop ); } + +gboolean bitlbee_io_master_ipc_read( gpointer data, gint source, GaimInputCondition cond ) +{ + struct bitlbee_child *child = data; + char buf[513], *eol; + int size; + + size = recv( child->ipc_fd, buf, sizeof( buf ) - 1, MSG_PEEK ); + + if( size < 0 || ( size < 0 && !sockerr_again() ) ) + goto error_abort; + else + buf[size] = 0; + + eol = strstr( buf, "\r\n" ); + if( eol == NULL ) + goto error_abort; + + size = recv( child->ipc_fd, buf, eol - buf + 2, 0 ); + buf[size] = 0; + + if( strcmp( buf, "DIE\r\n" ) == 0 ) + { + printf( "Bye...\n" ); + exit( 0 ); + } + + return TRUE; + +error_abort: + { + GSList *l; + struct bitlbee_child *c; + + for( l = child_list; l; l = l->next ) + { + c = l->data; + if( c->ipc_fd == source ) + { + close( c->ipc_fd ); + gaim_input_remove( c->ipc_inpa ); + g_free( c ); + + child_list = g_slist_remove( child_list, l ); + + break; + } + } + + return FALSE; + } +} + +gboolean bitlbee_io_child_ipc_read( gpointer data, gint source, GaimInputCondition cond ) +{ + return TRUE; +} diff --git a/bitlbee.h b/bitlbee.h index be58ad07..0bd7c90e 100644 --- a/bitlbee.h +++ b/bitlbee.h @@ -111,7 +111,8 @@ extern char *CONF_FILE; #include "query.h" #include "sock.h" -typedef struct global_t { +typedef struct global { + /* In forked mode, child processes store the fd of the IPC socket here. */ int listen_socket; gint listen_watch_source_id; help_t *help; diff --git a/irc.c b/irc.c index 8842ec41..66469f68 100644 --- a/irc.c +++ b/irc.c @@ -873,6 +873,10 @@ int irc_exec( irc_t *irc, char **cmd ) irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", "END" ); } + else if( g_strcasecmp( cmd[0], "DIE" ) == 0 ) + { + printf( "%d %d\n", global.listen_socket, write( global.listen_socket, "DIE\r\n", 5 ) ); + } else if( set_getint( irc, "debug" ) ) { irc_usermsg( irc, "\002--- Unknown command:" ); -- cgit v1.2.3 From 0298d1195bb76c1e400695916b4cf65480b0dd76 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 14 Jan 2006 00:51:21 +0100 Subject: Moved all IRC commands to separate functions in irc_commands.c. At least the PASS command doesn't work yet in this form. --- Makefile | 2 +- commands.c | 82 ++++---- commands.h | 27 +-- irc.c | 581 --------------------------------------------------- irc_commands.c | 646 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 694 insertions(+), 644 deletions(-) create mode 100644 irc_commands.c diff --git a/Makefile b/Makefile index 2e0d0faa..c9c396ee 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ -include Makefile.settings # Program variables -objects = account.o bitlbee.o commands.o conf.o crypting.o help.o ini.o irc.o log.o nick.o query.o set.o storage.o storage_text.o unix.o url.o user.o util.o +objects = account.o bitlbee.o commands.o conf.o crypting.o help.o ini.o irc.o irc_commands.o log.o nick.o query.o set.o storage.o storage_text.o unix.o url.o user.o util.o subdirs = protocols # Expansion of variables diff --git a/commands.c b/commands.c index 82143168..fbe378f6 100644 --- a/commands.c +++ b/commands.c @@ -31,29 +31,6 @@ #include -const command_t commands[] = { - { "help", 0, cmd_help }, - { "identify", 1, cmd_identify }, - { "register", 1, cmd_register }, - { "drop", 1, cmd_drop }, - { "account", 1, cmd_account }, - { "add", 2, cmd_add }, - { "info", 1, cmd_info }, - { "rename", 2, cmd_rename }, - { "remove", 1, cmd_remove }, - { "block", 1, cmd_block }, - { "allow", 1, cmd_allow }, - { "save", 0, cmd_save }, - { "set", 0, cmd_set }, - { "yes", 0, cmd_yesno }, - { "no", 0, cmd_yesno }, - { "blist", 0, cmd_blist }, - { "nick", 1, cmd_nick }, - { "import_buddies", 1, cmd_import_buddies }, - { "qlist", 0, cmd_qlist }, - { NULL } -}; - int root_command_string( irc_t *irc, user_t *u, char *command, int flags ) { char *cmd[IRC_MAX_ARGS]; @@ -113,7 +90,7 @@ int root_command( irc_t *irc, char *cmd[] ) return( 1 ); } -int cmd_help( irc_t *irc, char **cmd ) +static int cmd_help( irc_t *irc, char **cmd ) { char param[80]; int i; @@ -142,7 +119,7 @@ int cmd_help( irc_t *irc, char **cmd ) } } -int cmd_identify( irc_t *irc, char **cmd ) +static int cmd_identify( irc_t *irc, char **cmd ) { storage_status_t status = storage_load( irc->nick, cmd[1], irc ); @@ -165,7 +142,7 @@ int cmd_identify( irc_t *irc, char **cmd ) return( 0 ); } -int cmd_register( irc_t *irc, char **cmd ) +static int cmd_register( irc_t *irc, char **cmd ) { if( global.conf->authmode == AUTHMODE_REGISTERED ) { @@ -192,7 +169,7 @@ int cmd_register( irc_t *irc, char **cmd ) return( 0 ); } -int cmd_drop( irc_t *irc, char **cmd ) +static int cmd_drop( irc_t *irc, char **cmd ) { storage_status_t status; @@ -216,7 +193,7 @@ int cmd_drop( irc_t *irc, char **cmd ) } } -int cmd_account( irc_t *irc, char **cmd ) +static int cmd_account( irc_t *irc, char **cmd ) { account_t *a; @@ -376,7 +353,7 @@ int cmd_account( irc_t *irc, char **cmd ) return( 1 ); } -int cmd_add( irc_t *irc, char **cmd ) +static int cmd_add( irc_t *irc, char **cmd ) { account_t *a; @@ -416,7 +393,7 @@ int cmd_add( irc_t *irc, char **cmd ) return( 0 ); } -int cmd_info( irc_t *irc, char **cmd ) +static int cmd_info( irc_t *irc, char **cmd ) { struct gaim_connection *gc; account_t *a; @@ -453,7 +430,7 @@ int cmd_info( irc_t *irc, char **cmd ) return( 0 ); } -int cmd_rename( irc_t *irc, char **cmd ) +static int cmd_rename( irc_t *irc, char **cmd ) { user_t *u; @@ -494,7 +471,7 @@ int cmd_rename( irc_t *irc, char **cmd ) return( 0 ); } -int cmd_remove( irc_t *irc, char **cmd ) +static int cmd_remove( irc_t *irc, char **cmd ) { user_t *u; char *s; @@ -516,7 +493,7 @@ int cmd_remove( irc_t *irc, char **cmd ) return( 0 ); } -int cmd_block( irc_t *irc, char **cmd ) +static int cmd_block( irc_t *irc, char **cmd ) { struct gaim_connection *gc; account_t *a; @@ -557,7 +534,7 @@ int cmd_block( irc_t *irc, char **cmd ) return( 0 ); } -int cmd_allow( irc_t *irc, char **cmd ) +static int cmd_allow( irc_t *irc, char **cmd ) { struct gaim_connection *gc; account_t *a; @@ -599,7 +576,7 @@ int cmd_allow( irc_t *irc, char **cmd ) return( 0 ); } -int cmd_yesno( irc_t *irc, char **cmd ) +static int cmd_yesno( irc_t *irc, char **cmd ) { query_t *q = NULL; int numq = 0; @@ -639,7 +616,7 @@ int cmd_yesno( irc_t *irc, char **cmd ) return( 1 ); } -int cmd_set( irc_t *irc, char **cmd ) +static int cmd_set( irc_t *irc, char **cmd ) { if( cmd[1] && cmd[2] ) { @@ -665,7 +642,7 @@ int cmd_set( irc_t *irc, char **cmd ) return( 0 ); } -int cmd_save( irc_t *irc, char **cmd ) +static int cmd_save( irc_t *irc, char **cmd ) { if( storage_save( irc, TRUE ) == STORAGE_OK ) irc_usermsg( irc, "Configuration saved" ); @@ -675,7 +652,7 @@ int cmd_save( irc_t *irc, char **cmd ) return( 0 ); } -int cmd_blist( irc_t *irc, char **cmd ) +static int cmd_blist( irc_t *irc, char **cmd ) { int online = 0, away = 0, offline = 0; user_t *u; @@ -721,7 +698,7 @@ int cmd_blist( irc_t *irc, char **cmd ) return( 0 ); } -int cmd_nick( irc_t *irc, char **cmd ) +static int cmd_nick( irc_t *irc, char **cmd ) { account_t *a; @@ -757,7 +734,7 @@ int cmd_nick( irc_t *irc, char **cmd ) return( 1 ); } -int cmd_qlist( irc_t *irc, char **cmd ) +static int cmd_qlist( irc_t *irc, char **cmd ) { query_t *q = irc->queries; int num; @@ -779,7 +756,7 @@ int cmd_qlist( irc_t *irc, char **cmd ) return( 0 ); } -int cmd_import_buddies( irc_t *irc, char **cmd ) +static int cmd_import_buddies( irc_t *irc, char **cmd ) { struct gaim_connection *gc; account_t *a; @@ -831,3 +808,26 @@ int cmd_import_buddies( irc_t *irc, char **cmd ) return( 0 ); } + +const command_t commands[] = { + { "help", 0, cmd_help, 0 }, + { "identify", 1, cmd_identify, 0 }, + { "register", 1, cmd_register, 0 }, + { "drop", 1, cmd_drop, 0 }, + { "account", 1, cmd_account, 0 }, + { "add", 2, cmd_add, 0 }, + { "info", 1, cmd_info, 0 }, + { "rename", 2, cmd_rename, 0 }, + { "remove", 1, cmd_remove, 0 }, + { "block", 1, cmd_block, 0 }, + { "allow", 1, cmd_allow, 0 }, + { "save", 0, cmd_save, 0 }, + { "set", 0, cmd_set, 0 }, + { "yes", 0, cmd_yesno, 0 }, + { "no", 0, cmd_yesno, 0 }, + { "blist", 0, cmd_blist, 0 }, + { "nick", 1, cmd_nick, 0 }, + { "import_buddies", 1, cmd_import_buddies, 0 }, + { "qlist", 0, cmd_qlist, 0 }, + { NULL } +}; diff --git a/commands.h b/commands.h index 806126e6..69514a67 100644 --- a/commands.h +++ b/commands.h @@ -28,33 +28,18 @@ #include "bitlbee.h" -typedef struct command_t +typedef struct command { char *command; int required_parameters; int (*execute)(irc_t *, char **args); + int flags; } command_t; -int cmd_account( irc_t *irc, char **cmd ); -int cmd_help( irc_t *irc, char **args); -int cmd_info( irc_t *irc, char **args); -int cmd_add( irc_t *irc, char **args) ; -int cmd_rename( irc_t *irc, char **args ); -int cmd_remove( irc_t *irc, char **args ); -int cmd_block( irc_t *irc, char **args ); -int cmd_allow( irc_t *irc, char **args ); -int cmd_save( irc_t *irc, char **args ); -int cmd_set( irc_t *irc, char **args ); -int cmd_yesno( irc_t *irc, char **args ); -int cmd_identify( irc_t *irc, char **args ); -int cmd_register( irc_t *irc, char **args ); -int cmd_drop( irc_t *irc, char **args ); -int cmd_blist( irc_t *irc, char **cmd ); -int cmd_nick( irc_t *irc, char **cmd ); -int cmd_qlist( irc_t *irc, char **cmd ); -int cmd_import_buddies( irc_t *irc, char **cmd ); -int cmd_dump( irc_t *irc, char **cmd ); - extern const command_t commands[]; +#define IRC_CMD_PRE_LOGIN 1 +#define IRC_CMD_LOGGED_IN 2 +#define IRC_CMD_OPER_ONLY 4 + #endif diff --git a/irc.c b/irc.c index 32dadb7c..2339af71 100644 --- a/irc.c +++ b/irc.c @@ -418,471 +418,6 @@ int irc_process_line( irc_t *irc, char *line ) return(i); } -int irc_exec( irc_t *irc, char **cmd ) -{ - int i; - - if( (global.conf)->authmode == AUTHMODE_CLOSED && irc->status < USTATUS_AUTHORIZED ) - { - if( g_strcasecmp( cmd[0], "PASS" ) == 0 ) - { - if( !cmd[1] ) - { - irc_reply( irc, 461, "%s :Need more parameters", cmd[0] ); - } - else if( strcmp( cmd[1], (global.conf)->auth_pass ) == 0 ) - { - irc->status = USTATUS_AUTHORIZED; - } - else - { - irc_reply( irc, 464, ":Nope, maybe you should try it again..." ); - } - } - else - { - irc_reply( irc, 464, ":Uhh, fine, but I want the password first." ); - } - - return( 1 ); - } - - if( g_strcasecmp( cmd[0], "USER" ) == 0 ) - { - if( !( cmd[1] && cmd[2] && cmd[3] && cmd[4] ) ) - { - irc_reply( irc, 461, "%s :Need more parameters", cmd[0] ); - } - else if( irc->user ) - { - irc_reply( irc, 462, ":You can't change your nick/userinfo" ); - } - else - { - irc->user = g_strdup( cmd[1] ); - irc->realname = g_strdup( cmd[4] ); - if( irc->nick ) irc_login( irc ); - } - return( 1 ); - } - else if( g_strcasecmp( cmd[0], "NICK" ) == 0 ) - { - if( !cmd[1] ) - { - irc_reply( irc, 461, "%s :Need more parameters", cmd[0] ); - } - else if( irc->nick ) - { - irc_reply( irc, 438, ":The hand of the deity is upon thee, thy nick may not change" ); - } - /* This is not clean, but for now it'll have to be like this... */ - else if( ( nick_cmp( cmd[1], irc->mynick ) == 0 ) || ( nick_cmp( cmd[1], NS_NICK ) == 0 ) ) - { - irc_reply( irc, 433, ":This nick is already in use" ); - } - else if( !nick_ok( cmd[1] ) ) - { - /* [SH] Invalid characters. */ - irc_reply( irc, 432, ":This nick contains invalid characters" ); - } - else - { - irc->nick = g_strdup( cmd[1] ); - if( irc->user ) irc_login( irc ); - } - return( 1 ); - } - else if( g_strcasecmp( cmd[0], "QUIT" ) == 0 ) - { - irc_write( irc, "ERROR :%s%s", cmd[1]?"Quit: ":"", cmd[1]?cmd[1]:"Client Quit" ); - g_io_channel_close( irc->io_channel ); - return( 0 ); - } - - if( !irc->user || !irc->nick ) - { - irc_reply( irc, 451, ":Register first" ); - return( 1 ); - } - - if( g_strcasecmp( cmd[0], "PING" ) == 0 ) - { - irc_write( irc, ":%s PONG %s :%s", irc->myhost, irc->myhost, cmd[1]?cmd[1]:irc->myhost ); - } - else if( g_strcasecmp( cmd[0], "OPER" ) == 0 ) - { - if( !cmd[2] ) - irc_reply( irc, 461, "%s :Need more parameters", cmd[0] ); - else if( strcmp( cmd[2], global.conf->oper_pass ) == 0 ) - irc_umode_set( irc, "+o", 1 ); - // else - /* FIXME/TODO: Find out which reply to send now. */ - } - else if( g_strcasecmp( cmd[0], "MODE" ) == 0 ) - { - if( !cmd[1] ) - { - irc_reply( irc, 461, "%s :Need more parameters", cmd[0] ); - } - else if( *cmd[1] == '#' || *cmd[1] == '&' ) - { - if( cmd[2] ) - { - if( *cmd[2] == '+' || *cmd[2] == '-' ) - irc_reply( irc, 477, "%s :Can't change channel modes", cmd[1] ); - else if( *cmd[2] == 'b' ) - irc_reply( irc, 368, "%s :No bans possible", cmd[1] ); - } - else - irc_reply( irc, 324, "%s +%s", cmd[1], CMODE ); - } - else - { - if( nick_cmp( cmd[1], irc->nick ) == 0 ) - { - if( cmd[2] ) - irc_umode_set( irc, cmd[2], 0 ); - } - else - irc_reply( irc, 502, ":Don't touch their modes" ); - } - } - else if( g_strcasecmp( cmd[0], "NAMES" ) == 0 ) - { - irc_names( irc, cmd[1]?cmd[1]:irc->channel ); - } - else if( g_strcasecmp( cmd[0], "PART" ) == 0 ) - { - struct conversation *c; - - if( !cmd[1] ) - { - irc_reply( irc, 461, "%s :Need more parameters", cmd[0] ); - } - else if( g_strcasecmp( cmd[1], irc->channel ) == 0 ) - { - user_t *u = user_find( irc, irc->nick ); - - /* Not allowed to leave control channel */ - irc_part( irc, u, irc->channel ); - irc_join( irc, u, irc->channel ); - } - else if( ( c = conv_findchannel( cmd[1] ) ) ) - { - user_t *u = user_find( irc, irc->nick ); - - irc_part( irc, u, c->channel ); - - if( c->gc && c->gc->prpl ) - { - c->joined = 0; - c->gc->prpl->chat_leave( c->gc, c->id ); - } - } - else - { - irc_reply( irc, 403, "%s :No such channel", cmd[1] ); - } - } - else if( g_strcasecmp( cmd[0], "JOIN" ) == 0 ) - { - if( !cmd[1] ) - { - irc_reply( irc, 461, "%s :Need more parameters", cmd[0] ); - } - else if( g_strcasecmp( cmd[1], irc->channel ) == 0 ) - ; /* Dude, you're already there... - RFC doesn't have any reply for that though? */ - else if( cmd[1] ) - { - if( ( cmd[1][0] == '#' || cmd[1][0] == '&' ) && cmd[1][1] ) - { - user_t *u = user_find( irc, cmd[1] + 1 ); - - if( u && u->gc && u->gc->prpl && u->gc->prpl->chat_open ) - { - irc_reply( irc, 403, "%s :Initializing groupchat in a different channel", cmd[1] ); - - if( !u->gc->prpl->chat_open( u->gc, u->handle ) ) - { - irc_usermsg( irc, "Could not open a groupchat with %s, maybe you don't have a connection to him/her yet?", u->nick ); - } - } - else - { - irc_reply( irc, 403, "%s :Groupchats are not possible with %s", cmd[1], cmd[1]+1 ); - } - } - else - { - irc_reply( irc, 403, "%s :No such channel", cmd[1] ); - } - } - } - else if( g_strcasecmp( cmd[0], "INVITE" ) == 0 ) - { - if( cmd[1] && cmd[2] ) - irc_invite( irc, cmd[1], cmd[2] ); - else - irc_reply( irc, 461, "%s :Need more parameters", cmd[0] ); - } - else if( g_strcasecmp( cmd[0], "PRIVMSG" ) == 0 || g_strcasecmp( cmd[0], "NOTICE" ) == 0 ) - { - if( !cmd[1] ) - { - irc_reply( irc, 461, "%s :Need more parameters", cmd[0] ); - } - else if ( !cmd[2] ) - { - irc_reply( irc, 412, ":No text to send" ); - } - else if ( irc->nick && g_strcasecmp( cmd[1], irc->nick ) == 0 ) - { - irc_write( irc, ":%s!%s@%s %s %s :%s", irc->nick, irc->user, irc->host, cmd[0], cmd[1], cmd[2] ); - } - else - { - if( g_strcasecmp( cmd[1], irc->channel ) == 0 ) - { - unsigned int i; - char *t = set_getstr( irc, "default_target" ); - - if( g_strcasecmp( t, "last" ) == 0 && irc->last_target ) - cmd[1] = irc->last_target; - else if( g_strcasecmp( t, "root" ) == 0 ) - cmd[1] = irc->mynick; - - for( i = 0; i < strlen( cmd[2] ); i ++ ) - { - if( cmd[2][i] == ' ' ) break; - if( cmd[2][i] == ':' || cmd[2][i] == ',' ) - { - cmd[1] = cmd[2]; - cmd[2] += i; - *cmd[2] = 0; - while( *(++cmd[2]) == ' ' ); - break; - } - } - - irc->is_private = 0; - - if( cmd[1] != irc->last_target ) - { - if( irc->last_target ) - g_free( irc->last_target ); - irc->last_target = g_strdup( cmd[1] ); - } - } - else - { - irc->is_private = 1; - } - irc_send( irc, cmd[1], cmd[2], ( g_strcasecmp( cmd[0], "NOTICE" ) == 0 ) ? IM_FLAG_AWAY : 0 ); - } - } - else if( g_strcasecmp( cmd[0], "WHO" ) == 0 ) - { - irc_who( irc, cmd[1] ); - } - else if( g_strcasecmp( cmd[0], "USERHOST" ) == 0 ) - { - user_t *u; - - if( !cmd[1] ) - { - irc_reply( irc, 461, "%s :Need more parameters", cmd[0] ); - } - /* [TV] Usable USERHOST-implementation according to - RFC1459. Without this, mIRC shows an error - while connecting, and the used way of rejecting - breaks standards. - */ - - for( i = 1; cmd[i]; i ++ ) - if( ( u = user_find( irc, cmd[i] ) ) ) - { - if( u->online && u->away ) - irc_reply( irc, 302, ":%s=-%s@%s", u->nick, u->user, u->host ); - else - irc_reply( irc, 302, ":%s=+%s@%s", u->nick, u->user, u->host ); - } - } - else if( g_strcasecmp( cmd[0], "ISON" ) == 0 ) - { - user_t *u; - char buff[IRC_MAX_LINE]; - int lenleft; - - buff[0] = '\0'; - - /* [SH] Leave room for : and \0 */ - lenleft = IRC_MAX_LINE - 2; - - for( i = 1; cmd[i]; i ++ ) - { - if( ( u = user_find( irc, cmd[i] ) ) && u->online ) - { - /* [SH] Make sure we don't use too much buffer space. */ - lenleft -= strlen( u->nick ) + 1; - - if( lenleft < 0 ) - { - break; - } - - /* [SH] Add the nick to the buffer. Note - * that an extra space is always added. Even - * if it's the last nick in the list. Who - * cares? - */ - - strcat( buff, u->nick ); - strcat( buff, " " ); - } - } - - /* [WvG] Well, maybe someone cares, so why not remove it? */ - if( strlen( buff ) > 0 ) - buff[strlen(buff)-1] = '\0'; - - /* [SH] By the way, that really *was* WvG talking. */ - /* [WvG] Really? */ - /* [SH] Yeah... But *this* is WvG talking too. ;-P */ - /* [WvG] *sigh* */ - - irc_reply( irc, 303, ":%s", buff ); - } - else if( g_strcasecmp( cmd[0], "WATCH" ) == 0 ) - { - /* Obviously we could also mark a user structure as being - watched, but what if the WATCH command is sent right - after connecting? The user won't exist yet then... */ - for( i = 1; cmd[i]; i ++ ) - { - char *nick; - user_t *u; - - if( !cmd[i][0] || !cmd[i][1] ) - break; - - nick = g_strdup( cmd[i] + 1 ); - nick_lc( nick ); - - u = user_find( irc, nick ); - - if( cmd[i][0] == '+' ) - { - if( !g_hash_table_lookup( irc->watches, nick ) ) - g_hash_table_insert( irc->watches, nick, nick ); - - if( u && u->online ) - irc_reply( irc, 604, "%s %s %s %d :%s", u->nick, u->user, u->host, time( NULL ), "is online" ); - else - irc_reply( irc, 605, "%s %s %s %d :%s", nick, "*", "*", time( NULL ), "is offline" ); - } - else if( cmd[i][0] == '-' ) - { - gpointer okey, ovalue; - - if( g_hash_table_lookup_extended( irc->watches, nick, &okey, &ovalue ) ) - { - g_free( okey ); - g_hash_table_remove( irc->watches, okey ); - - irc_reply( irc, 602, "%s %s %s %d :%s", nick, "*", "*", 0, "Stopped watching" ); - } - } - } - } - else if( g_strcasecmp( cmd[0], "TOPIC" ) == 0 ) - { - if( cmd[1] && cmd[2] ) - irc_reply( irc, 482, "%s :Cannot change topic", cmd[1] ); - else if( cmd[1] ) - irc_topic( irc, cmd[1] ); - else - irc_reply( irc, 461, "%s :Need more parameters", cmd[0] ); - } - else if( g_strcasecmp( cmd[0], "AWAY" ) == 0 ) - { - irc_away( irc, cmd[1] ); - } - else if( g_strcasecmp( cmd[0], "WHOIS" ) == 0 ) - { - if( cmd[1] ) - { - irc_whois( irc, cmd[1] ); - } - else - { - irc_reply( irc, 461, "%s :Need more parameters", cmd[0] ); - } - } - else if( g_strcasecmp( cmd[0], "WHOWAS" ) == 0 ) - { - /* For some reason irssi tries a whowas when whois fails. We can - ignore this, but then the user never gets a "user not found" - message from irssi which is a bit annoying. So just respond - with not-found and irssi users will get better error messages */ - - if( cmd[1] ) - { - irc_reply( irc, 406, "%s :Nick does not exist", cmd[1] ); - irc_reply( irc, 369, "%s :End of WHOWAS", cmd[1] ); - } - else - { - irc_reply( irc, 461, "%s :Need more parameters", cmd[0] ); - } - } - else if( ( g_strcasecmp( cmd[0], "NICKSERV" ) == 0 ) || ( g_strcasecmp( cmd[0], "NS" ) == 0 ) ) - { - /* [SH] This aliases the NickServ command to PRIVMSG root */ - /* [TV] This aliases the NS command to PRIVMSG root as well */ - root_command( irc, cmd + 1 ); - } - else if( g_strcasecmp( cmd[0], "MOTD" ) == 0 ) - { - irc_motd( irc ); - } - else if( g_strcasecmp( cmd[0], "PONG" ) == 0 ) - { - /* We could check the value we get back from the user, but in - fact we don't care, we're just happy he's still alive. */ - irc->last_pong = gettime(); - irc->pinging = 0; - } - else if( g_strcasecmp( cmd[0], "COMPLETIONS" ) == 0 ) - { - user_t *u = user_find( irc, irc->mynick ); - help_t *h; - set_t *s; - int i; - - irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", "OK" ); - - for( i = 0; commands[i].command; i ++ ) - irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", commands[i].command ); - - for( h = global.help; h; h = h->next ) - irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS help ", h->string ); - - for( s = irc->set; s; s = s->next ) - irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS set ", s->key ); - - irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", "END" ); - } - else if( set_getint( irc, "debug" ) ) - { - irc_usermsg( irc, "\002--- Unknown command:" ); - for( i = 0; cmd[i]; i ++ ) irc_usermsg( irc, "%s", cmd[i] ); - irc_usermsg( irc, "\002--------------------" ); - } - - return( 1 ); -} - void irc_reply( irc_t *irc, int code, char *format, ... ) { char text[IRC_MAX_LINE]; @@ -1039,37 +574,6 @@ void irc_names( irc_t *irc, char *channel ) irc_reply( irc, 366, "%s :End of /NAMES list", channel ); } -void irc_who( irc_t *irc, char *channel ) -{ - user_t *u = irc->users; - struct conversation *c; - GList *l; - - if( !channel || *channel == '0' || *channel == '*' || !*channel ) - while( u ) - { - irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", u->online ? irc->channel : "*", u->user, u->host, irc->myhost, u->nick, u->online ? ( u->away ? 'G' : 'H' ) : 'G', u->realname ); - u = u->next; - } - else if( g_strcasecmp( channel, irc->channel ) == 0 ) - while( u ) - { - if( u->online ) - irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->away ? 'G' : 'H', u->realname ); - u = u->next; - } - else if( ( c = conv_findchannel( channel ) ) ) - for( l = c->in_room; l; l = l->next ) - { - if( ( u = user_findhandle( c->gc, l->data ) ) ) - irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->away ? 'G' : 'H', u->realname ); - } - else if( ( u = user_find( irc, channel ) ) ) - irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->online ? ( u->away ? 'G' : 'H' ) : 'G', u->realname ); - - irc_reply( irc, 315, "%s :End of /WHO list.", channel?channel:"**" ); -} - void irc_login( irc_t *irc ) { user_t *u; @@ -1179,34 +683,6 @@ void irc_topic( irc_t *irc, char *channel ) } } -void irc_whois( irc_t *irc, char *nick ) -{ - user_t *u = user_find( irc, nick ); - - if( u ) - { - irc_reply( irc, 311, "%s %s %s * :%s", u->nick, u->user, u->host, u->realname ); - - if( u->gc ) - irc_reply( irc, 312, "%s %s.%s :%s network", u->nick, u->gc->user->username, - *u->gc->user->proto_opt[0] ? u->gc->user->proto_opt[0] : "", u->gc->prpl->name ); - else - irc_reply( irc, 312, "%s %s :%s", u->nick, irc->myhost, IRCD_INFO ); - - if( !u->online ) - irc_reply( irc, 301, "%s :%s", u->nick, "User is offline" ); - else if( u->away ) - irc_reply( irc, 301, "%s :%s", u->nick, u->away ); - - irc_reply( irc, 318, "%s :End of /WHOIS list", nick ); - } - else - { - irc_reply( irc, 401, "%s :Nick does not exist", nick ); - } -} - - void irc_umode_set( irc_t *irc, char *s, int allow_priv ) { /* allow_priv: Set to 0 if s contains user input, 1 if you want @@ -1236,47 +712,6 @@ void irc_umode_set( irc_t *irc, char *s, int allow_priv ) irc_reply( irc, 221, "+%s", irc->umode ); } -int irc_away( irc_t *irc, char *away ) -{ - user_t *u = user_find( irc, irc->nick ); - GSList *c = get_connections(); - - if( !u ) return( 0 ); - - if( away && *away ) - { - int i, j; - - /* Copy away string, but skip control chars. Mainly because - Jabber really doesn't like them. */ - u->away = g_malloc( strlen( away ) + 1 ); - for( i = j = 0; away[i]; i ++ ) - if( ( u->away[j] = away[i] ) >= ' ' ) - j ++; - u->away[j] = 0; - - irc_reply( irc, 306, ":You're now away: %s", u->away ); - /* irc_umode_set( irc, irc->myhost, "+a" ); */ - } - else - { - if( u->away ) g_free( u->away ); - u->away = NULL; - /* irc_umode_set( irc, irc->myhost, "-a" ); */ - irc_reply( irc, 305, ":Welcome back" ); - } - - while( c ) - { - if( ((struct gaim_connection *)c->data)->flags & OPT_LOGGED_IN ) - proto_away( c->data, u->away ); - - c = c->next; - } - - return( 1 ); -} - void irc_spawn( irc_t *irc, user_t *u ) { irc_join( irc, u, irc->channel ); @@ -1330,22 +765,6 @@ void irc_kill( irc_t *irc, user_t *u ) g_free( nick ); } -void irc_invite( irc_t *irc, char *nick, char *channel ) -{ - struct conversation *c = conv_findchannel( channel ); - user_t *u = user_find( irc, nick ); - - if( u && c && ( u->gc == c->gc ) ) - if( c->gc && c->gc->prpl && c->gc->prpl->chat_invite ) - { - c->gc->prpl->chat_invite( c->gc, c->id, "", u->handle ); - irc_reply( irc, 341, "%s %s", nick, channel ); - return; - } - - irc_reply( irc, 482, "%s :Invite impossible; User/Channel non-existent or incompatible", channel ); -} - int irc_send( irc_t *irc, char *nick, char *s, int flags ) { struct conversation *c = NULL; diff --git a/irc_commands.c b/irc_commands.c new file mode 100644 index 00000000..b6eeab37 --- /dev/null +++ b/irc_commands.c @@ -0,0 +1,646 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2006 Wilmer van der Gaast and others * + \********************************************************************/ + +/* IRC commands */ + +/* + 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" + +static int irc_cmd_pass( irc_t *irc, char **cmd ) +{ + if( strcmp( cmd[1], (global.conf)->auth_pass ) == 0 ) + { + irc->status = USTATUS_AUTHORIZED; + } + else + { + irc_reply( irc, 464, ":Nope, maybe you should try it again..." ); + } + + return( 1 ); +} + +static int irc_cmd_user( irc_t *irc, char **cmd ) +{ + if( irc->user ) + { + irc_reply( irc, 462, ":You can't change your nick/userinfo" ); + } + else + { + irc->user = g_strdup( cmd[1] ); + irc->realname = g_strdup( cmd[4] ); + if( irc->nick ) irc_login( irc ); + } + + return( 1 ); +} + +static int irc_cmd_nick( irc_t *irc, char **cmd ) +{ + if( irc->nick ) + { + irc_reply( irc, 438, ":The hand of the deity is upon thee, thy nick may not change" ); + } + /* This is not clean, but for now it'll have to be like this... */ + else if( ( nick_cmp( cmd[1], irc->mynick ) == 0 ) || ( nick_cmp( cmd[1], NS_NICK ) == 0 ) ) + { + irc_reply( irc, 433, ":This nick is already in use" ); + } + else if( !nick_ok( cmd[1] ) ) + { + /* [SH] Invalid characters. */ + irc_reply( irc, 432, ":This nick contains invalid characters" ); + } + else + { + irc->nick = g_strdup( cmd[1] ); + if( irc->user ) irc_login( irc ); + } + + return( 1 ); +} + +static int irc_cmd_quit( irc_t *irc, char **cmd ) +{ + irc_write( irc, "ERROR :%s%s", cmd[1]?"Quit: ":"", cmd[1]?cmd[1]:"Client Quit" ); + g_io_channel_close( irc->io_channel ); + + return( 0 ); +} + +/* + if( !irc->user || !irc->nick ) + { + irc_reply( irc, 451, ":Register first" ); + return( 1 ); + } +*/ + +static int irc_cmd_ping( irc_t *irc, char **cmd ) +{ + irc_write( irc, ":%s PONG %s :%s", irc->myhost, irc->myhost, cmd[1]?cmd[1]:irc->myhost ); + + return( 1 ); +} + +static int irc_cmd_oper( irc_t *irc, char **cmd ) +{ + if( strcmp( cmd[2], global.conf->oper_pass ) == 0 ) + irc_umode_set( irc, "+o", 1 ); + // else + /* FIXME/TODO: Find out which reply to send now. */ + + return( 1 ); +} + +static int irc_cmd_mode( irc_t *irc, char **cmd ) +{ + if( *cmd[1] == '#' || *cmd[1] == '&' ) + { + if( cmd[2] ) + { + if( *cmd[2] == '+' || *cmd[2] == '-' ) + irc_reply( irc, 477, "%s :Can't change channel modes", cmd[1] ); + else if( *cmd[2] == 'b' ) + irc_reply( irc, 368, "%s :No bans possible", cmd[1] ); + } + else + irc_reply( irc, 324, "%s +%s", cmd[1], CMODE ); + } + else + { + if( nick_cmp( cmd[1], irc->nick ) == 0 ) + { + if( cmd[2] ) + irc_umode_set( irc, cmd[2], 0 ); + } + else + irc_reply( irc, 502, ":Don't touch their modes" ); + } + + return( 1 ); +} + +static int irc_cmd_names( irc_t *irc, char **cmd ) +{ + irc_names( irc, cmd[1]?cmd[1]:irc->channel ); + + return( 1 ); +} + +static int irc_cmd_part( irc_t *irc, char **cmd ) +{ + struct conversation *c; + + if( g_strcasecmp( cmd[1], irc->channel ) == 0 ) + { + user_t *u = user_find( irc, irc->nick ); + + /* Not allowed to leave control channel */ + irc_part( irc, u, irc->channel ); + irc_join( irc, u, irc->channel ); + } + else if( ( c = conv_findchannel( cmd[1] ) ) ) + { + user_t *u = user_find( irc, irc->nick ); + + irc_part( irc, u, c->channel ); + + if( c->gc && c->gc->prpl ) + { + c->joined = 0; + c->gc->prpl->chat_leave( c->gc, c->id ); + } + } + else + { + irc_reply( irc, 403, "%s :No such channel", cmd[1] ); + } + + return( 1 ); +} + +static int irc_cmd_join( irc_t *irc, char **cmd ) +{ + if( g_strcasecmp( cmd[1], irc->channel ) == 0 ) + ; /* Dude, you're already there... + RFC doesn't have any reply for that though? */ + else if( cmd[1] ) + { + if( ( cmd[1][0] == '#' || cmd[1][0] == '&' ) && cmd[1][1] ) + { + user_t *u = user_find( irc, cmd[1] + 1 ); + + if( u && u->gc && u->gc->prpl && u->gc->prpl->chat_open ) + { + irc_reply( irc, 403, "%s :Initializing groupchat in a different channel", cmd[1] ); + + if( !u->gc->prpl->chat_open( u->gc, u->handle ) ) + { + irc_usermsg( irc, "Could not open a groupchat with %s, maybe you don't have a connection to him/her yet?", u->nick ); + } + } + else if( u ) + { + irc_reply( irc, 403, "%s :Groupchats are not possible with %s", cmd[1], cmd[1]+1 ); + } + else + { + irc_reply( irc, 403, "%s :No such nick", cmd[1] ); + } + } + else + { + irc_reply( irc, 403, "%s :No such channel", cmd[1] ); + } + } + + return( 1 ); +} + +static int irc_cmd_invite( irc_t *irc, char **cmd ) +{ + char *nick = cmd[1], *channel = cmd[2]; + struct conversation *c = conv_findchannel( channel ); + user_t *u = user_find( irc, nick ); + + if( u && c && ( u->gc == c->gc ) ) + if( c->gc && c->gc->prpl && c->gc->prpl->chat_invite ) + { + c->gc->prpl->chat_invite( c->gc, c->id, "", u->handle ); + irc_reply( irc, 341, "%s %s", nick, channel ); + return( 1 ); + } + + irc_reply( irc, 482, "%s :Invite impossible; User/Channel non-existent or incompatible", channel ); + + return( 1 ); +} + +/* TODO: Attach this one to NOTICE too! */ +static int irc_cmd_privmsg( irc_t *irc, char **cmd ) +{ + if ( !cmd[2] ) + { + irc_reply( irc, 412, ":No text to send" ); + } + else if ( irc->nick && g_strcasecmp( cmd[1], irc->nick ) == 0 ) + { + irc_write( irc, ":%s!%s@%s %s %s :%s", irc->nick, irc->user, irc->host, cmd[0], cmd[1], cmd[2] ); + } + else + { + if( g_strcasecmp( cmd[1], irc->channel ) == 0 ) + { + unsigned int i; + char *t = set_getstr( irc, "default_target" ); + + if( g_strcasecmp( t, "last" ) == 0 && irc->last_target ) + cmd[1] = irc->last_target; + else if( g_strcasecmp( t, "root" ) == 0 ) + cmd[1] = irc->mynick; + + for( i = 0; i < strlen( cmd[2] ); i ++ ) + { + if( cmd[2][i] == ' ' ) break; + if( cmd[2][i] == ':' || cmd[2][i] == ',' ) + { + cmd[1] = cmd[2]; + cmd[2] += i; + *cmd[2] = 0; + while( *(++cmd[2]) == ' ' ); + break; + } + } + + irc->is_private = 0; + + if( cmd[1] != irc->last_target ) + { + if( irc->last_target ) + g_free( irc->last_target ); + irc->last_target = g_strdup( cmd[1] ); + } + } + else + { + irc->is_private = 1; + } + irc_send( irc, cmd[1], cmd[2], ( g_strcasecmp( cmd[0], "NOTICE" ) == 0 ) ? IM_FLAG_AWAY : 0 ); + } + + return( 1 ); +} + +static int irc_cmd_who( irc_t *irc, char **cmd ) +{ + char *channel = cmd[1]; + user_t *u = irc->users; + struct conversation *c; + GList *l; + + if( !channel || *channel == '0' || *channel == '*' || !*channel ) + while( u ) + { + irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", u->online ? irc->channel : "*", u->user, u->host, irc->myhost, u->nick, u->online ? ( u->away ? 'G' : 'H' ) : 'G', u->realname ); + u = u->next; + } + else if( g_strcasecmp( channel, irc->channel ) == 0 ) + while( u ) + { + if( u->online ) + irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->away ? 'G' : 'H', u->realname ); + u = u->next; + } + else if( ( c = conv_findchannel( channel ) ) ) + for( l = c->in_room; l; l = l->next ) + { + if( ( u = user_findhandle( c->gc, l->data ) ) ) + irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->away ? 'G' : 'H', u->realname ); + } + else if( ( u = user_find( irc, channel ) ) ) + irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->online ? ( u->away ? 'G' : 'H' ) : 'G', u->realname ); + + irc_reply( irc, 315, "%s :End of /WHO list.", channel?channel:"**" ); + + return( 1 ); +} + +static int irc_cmd_userhost( irc_t *irc, char **cmd ) +{ + user_t *u; + int i; + + /* [TV] Usable USERHOST-implementation according to + RFC1459. Without this, mIRC shows an error + while connecting, and the used way of rejecting + breaks standards. + */ + + for( i = 1; cmd[i]; i ++ ) + if( ( u = user_find( irc, cmd[i] ) ) ) + { + if( u->online && u->away ) + irc_reply( irc, 302, ":%s=-%s@%s", u->nick, u->user, u->host ); + else + irc_reply( irc, 302, ":%s=+%s@%s", u->nick, u->user, u->host ); + } + + return( 1 ); +} + +static int irc_cmd_ison( irc_t *irc, char **cmd ) +{ + user_t *u; + char buff[IRC_MAX_LINE]; + int lenleft, i; + + buff[0] = '\0'; + + /* [SH] Leave room for : and \0 */ + lenleft = IRC_MAX_LINE - 2; + + for( i = 1; cmd[i]; i ++ ) + { + if( ( u = user_find( irc, cmd[i] ) ) && u->online ) + { + /* [SH] Make sure we don't use too much buffer space. */ + lenleft -= strlen( u->nick ) + 1; + + if( lenleft < 0 ) + { + break; + } + + /* [SH] Add the nick to the buffer. Note + * that an extra space is always added. Even + * if it's the last nick in the list. Who + * cares? + */ + + strcat( buff, u->nick ); + strcat( buff, " " ); + } + } + + /* [WvG] Well, maybe someone cares, so why not remove it? */ + if( strlen( buff ) > 0 ) + buff[strlen(buff)-1] = '\0'; + + irc_reply( irc, 303, ":%s", buff ); + + return( 1 ); +} + +static int irc_cmd_watch( irc_t *irc, char **cmd ) +{ + int i; + + /* Obviously we could also mark a user structure as being + watched, but what if the WATCH command is sent right + after connecting? The user won't exist yet then... */ + for( i = 1; cmd[i]; i ++ ) + { + char *nick; + user_t *u; + + if( !cmd[i][0] || !cmd[i][1] ) + break; + + nick = g_strdup( cmd[i] + 1 ); + nick_lc( nick ); + + u = user_find( irc, nick ); + + if( cmd[i][0] == '+' ) + { + if( !g_hash_table_lookup( irc->watches, nick ) ) + g_hash_table_insert( irc->watches, nick, nick ); + + if( u && u->online ) + irc_reply( irc, 604, "%s %s %s %d :%s", u->nick, u->user, u->host, time( NULL ), "is online" ); + else + irc_reply( irc, 605, "%s %s %s %d :%s", nick, "*", "*", time( NULL ), "is offline" ); + } + else if( cmd[i][0] == '-' ) + { + gpointer okey, ovalue; + + if( g_hash_table_lookup_extended( irc->watches, nick, &okey, &ovalue ) ) + { + g_free( okey ); + g_hash_table_remove( irc->watches, okey ); + + irc_reply( irc, 602, "%s %s %s %d :%s", nick, "*", "*", 0, "Stopped watching" ); + } + } + } + + return( 1 ); +} + +static int irc_cmd_topic( irc_t *irc, char **cmd ) +{ + if( cmd[2] ) + irc_reply( irc, 482, "%s :Cannot change topic", cmd[1] ); + else + irc_topic( irc, cmd[1] ); + + return( 1 ); +} + +static int irc_cmd_away( irc_t *irc, char **cmd ) +{ + user_t *u = user_find( irc, irc->nick ); + GSList *c = get_connections(); + char *away = cmd[1]; + + if( !u ) return( 1 ); + + if( away && *away ) + { + int i, j; + + /* Copy away string, but skip control chars. Mainly because + Jabber really doesn't like them. */ + u->away = g_malloc( strlen( away ) + 1 ); + for( i = j = 0; away[i]; i ++ ) + if( ( u->away[j] = away[i] ) >= ' ' ) + j ++; + u->away[j] = 0; + + irc_reply( irc, 306, ":You're now away: %s", u->away ); + /* irc_umode_set( irc, irc->myhost, "+a" ); */ + } + else + { + if( u->away ) g_free( u->away ); + u->away = NULL; + /* irc_umode_set( irc, irc->myhost, "-a" ); */ + irc_reply( irc, 305, ":Welcome back" ); + } + + while( c ) + { + if( ((struct gaim_connection *)c->data)->flags & OPT_LOGGED_IN ) + proto_away( c->data, u->away ); + + c = c->next; + } + + return( 1 ); +} + +static int irc_cmd_whois( irc_t *irc, char **cmd ) +{ + char *nick = cmd[1]; + user_t *u = user_find( irc, nick ); + + if( u ) + { + irc_reply( irc, 311, "%s %s %s * :%s", u->nick, u->user, u->host, u->realname ); + + if( u->gc ) + irc_reply( irc, 312, "%s %s.%s :%s network", u->nick, u->gc->user->username, + *u->gc->user->proto_opt[0] ? u->gc->user->proto_opt[0] : "", u->gc->prpl->name ); + else + irc_reply( irc, 312, "%s %s :%s", u->nick, irc->myhost, IRCD_INFO ); + + if( !u->online ) + irc_reply( irc, 301, "%s :%s", u->nick, "User is offline" ); + else if( u->away ) + irc_reply( irc, 301, "%s :%s", u->nick, u->away ); + + irc_reply( irc, 318, "%s :End of /WHOIS list", nick ); + } + else + { + irc_reply( irc, 401, "%s :Nick does not exist", nick ); + } + + return( 1 ); +} + +static int irc_cmd_whowas( irc_t *irc, char **cmd ) +{ + /* For some reason irssi tries a whowas when whois fails. We can + ignore this, but then the user never gets a "user not found" + message from irssi which is a bit annoying. So just respond + with not-found and irssi users will get better error messages */ + + irc_reply( irc, 406, "%s :Nick does not exist", cmd[1] ); + irc_reply( irc, 369, "%s :End of WHOWAS", cmd[1] ); + + return( 1 ); +} + +/* TODO: Alias to NS */ +static int irc_cmd_nickserv( irc_t *irc, char **cmd ) +{ + /* [SH] This aliases the NickServ command to PRIVMSG root */ + /* [TV] This aliases the NS command to PRIVMSG root as well */ + root_command( irc, cmd + 1 ); + + return( 1 ); +} + +static int irc_cmd_motd( irc_t *irc, char **cmd ) +{ + irc_motd( irc ); + + return( 1 ); +} + +static int irc_cmd_pong( irc_t *irc, char **cmd ) +{ + /* We could check the value we get back from the user, but in + fact we don't care, we're just happy he's still alive. */ + irc->last_pong = gettime(); + irc->pinging = 0; + + return( 1 ); +} + +static int irc_cmd_completions( irc_t *irc, char **cmd ) +{ + user_t *u = user_find( irc, irc->mynick ); + help_t *h; + set_t *s; + int i; + + irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", "OK" ); + + for( i = 0; commands[i].command; i ++ ) + irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", commands[i].command ); + + for( h = global.help; h; h = h->next ) + irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS help ", h->string ); + + for( s = irc->set; s; s = s->next ) + irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS set ", s->key ); + + irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", "END" ); + + return( 1 ); +} + +static const command_t irc_commands[] = { + { "pass", 1, irc_cmd_pass, IRC_CMD_PRE_LOGIN }, + { "user", 4, irc_cmd_user, IRC_CMD_PRE_LOGIN }, + { "nick", 1, irc_cmd_nick, 0 }, + { "quit", 0, irc_cmd_quit, 0 }, + { "ping", 0, irc_cmd_ping, 0 }, + { "oper", 2, irc_cmd_oper, IRC_CMD_LOGGED_IN }, + { "mode", 1, irc_cmd_mode, IRC_CMD_LOGGED_IN }, + { "names", 0, irc_cmd_names, IRC_CMD_LOGGED_IN }, + { "part", 1, irc_cmd_part, IRC_CMD_LOGGED_IN }, + { "join", 1, irc_cmd_join, IRC_CMD_LOGGED_IN }, + { "invite", 2, irc_cmd_invite, IRC_CMD_LOGGED_IN }, + { "privmsg", 1, irc_cmd_privmsg, IRC_CMD_LOGGED_IN }, + { "notice", 1, irc_cmd_privmsg, IRC_CMD_LOGGED_IN }, + { "who", 0, irc_cmd_who, IRC_CMD_LOGGED_IN }, + { "userhost", 1, irc_cmd_userhost, IRC_CMD_LOGGED_IN }, + { "ison", 1, irc_cmd_ison, IRC_CMD_LOGGED_IN }, + { "watch", 1, irc_cmd_watch, IRC_CMD_LOGGED_IN }, + { "topic", 1, irc_cmd_topic, IRC_CMD_LOGGED_IN }, + { "away", 0, irc_cmd_away, IRC_CMD_LOGGED_IN }, + { "whois", 1, irc_cmd_whois, IRC_CMD_LOGGED_IN }, + { "whowas", 1, irc_cmd_whowas, IRC_CMD_LOGGED_IN }, + { "nickserv", 1, irc_cmd_nickserv, IRC_CMD_LOGGED_IN }, + { "ns", 1, irc_cmd_nickserv, IRC_CMD_LOGGED_IN }, + { "motd", 0, irc_cmd_motd, IRC_CMD_LOGGED_IN }, + { "pong", 0, irc_cmd_pong, IRC_CMD_LOGGED_IN }, + { "completions", 0, irc_cmd_completions, IRC_CMD_LOGGED_IN }, + { NULL } +}; + +int irc_exec( irc_t *irc, char *cmd[] ) +{ + int i, j; + + if( !cmd[0] ) + return( 1 ); + + for( i = 0; irc_commands[i].command; i++ ) + if( g_strcasecmp( irc_commands[i].command, cmd[0] ) == 0 ) + { + if( irc_commands[i].flags & IRC_CMD_PRE_LOGIN && irc->status > USTATUS_AUTHORIZED ) + continue; + if( irc_commands[i].flags & IRC_CMD_LOGGED_IN && irc->status < USTATUS_LOGGED_IN ) + continue; + if( irc_commands[i].flags & IRC_CMD_OPER_ONLY && !strchr( irc->umode, 'o' ) ) + continue; + + for( j = 1; j <= irc_commands[i].required_parameters; j ++ ) + if( !cmd[j] ) + { + irc_reply( irc, 461, "%s :Need more parameters", cmd[0] ); + return( 1 ); + } + + return irc_commands[i].execute( irc, cmd ); + } + + return( 1 ); +} -- cgit v1.2.3 From d2cbe0a03d2621a3a2b90055ea191cc11766dddf Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 14 Jan 2006 18:10:15 +0100 Subject: Fixed Yahoo! invisible status. (Thanks to a patch someone posted on FreshMeat some time ago.) --- protocols/yahoo/yahoo.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/protocols/yahoo/yahoo.c b/protocols/yahoo/yahoo.c index 832d1ab4..4f257d99 100644 --- a/protocols/yahoo/yahoo.c +++ b/protocols/yahoo/yahoo.c @@ -188,18 +188,18 @@ static int byahoo_send_typing( struct gaim_connection *gc, char *who, int typing static void byahoo_set_away( struct gaim_connection *gc, char *state, char *msg ) { struct byahoo_data *yd = (struct byahoo_data *) gc->proto_data; - + gc->away = NULL; - - if (msg) + + if( msg ) { yd->current_status = YAHOO_STATUS_CUSTOM; gc->away = ""; } - else if (state) + if( state ) { gc->away = ""; - if( g_strcasecmp(state, "Available" ) == 0 ) + if( g_strcasecmp( state, "Available" ) == 0 ) { yd->current_status = YAHOO_STATUS_AVAILABLE; gc->away = NULL; @@ -234,12 +234,15 @@ static void byahoo_set_away( struct gaim_connection *gc, char *state, char *msg gc->away = NULL; } } - else if ( gc->is_idle ) + else if( gc->is_idle ) yd->current_status = YAHOO_STATUS_IDLE; else yd->current_status = YAHOO_STATUS_AVAILABLE; - yahoo_set_away( yd->y2_id, yd->current_status, msg, gc->away != NULL ); + if( yd->current_status == YAHOO_STATUS_INVISIBLE ) + yahoo_set_away( yd->y2_id, yd->current_status, NULL, gc->away != NULL ); + else + yahoo_set_away( yd->y2_id, yd->current_status, msg, gc->away != NULL ); } static GList *byahoo_away_states( struct gaim_connection *gc ) -- cgit v1.2.3 From c22c210f560aee8a43b9fbff63c3dc408b434094 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 14 Jan 2006 18:48:29 +0100 Subject: Checks if there's an OPER password set before checking it, to prevent crashes. --- irc_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/irc_commands.c b/irc_commands.c index b6eeab37..37d530ea 100644 --- a/irc_commands.c +++ b/irc_commands.c @@ -106,7 +106,7 @@ static int irc_cmd_ping( irc_t *irc, char **cmd ) static int irc_cmd_oper( irc_t *irc, char **cmd ) { - if( strcmp( cmd[2], global.conf->oper_pass ) == 0 ) + if( global.conf->oper_pass && strcmp( cmd[2], global.conf->oper_pass ) == 0 ) irc_umode_set( irc, "+o", 1 ); // else /* FIXME/TODO: Find out which reply to send now. */ -- cgit v1.2.3 From edf965753380a165ec615b79d45251931ac3ea62 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 14 Jan 2006 19:25:00 +0100 Subject: Fixed the PASS-command, added error messages for invalid commands to irc_exec(). --- irc.c | 22 ++++++++++++++++++++++ irc.h | 1 + irc_commands.c | 47 ++++++++++++++++++++++------------------------- 3 files changed, 45 insertions(+), 25 deletions(-) diff --git a/irc.c b/irc.c index 2339af71..da6a70c7 100644 --- a/irc.c +++ b/irc.c @@ -574,6 +574,28 @@ void irc_names( irc_t *irc, char *channel ) irc_reply( irc, 366, "%s :End of /NAMES list", channel ); } +int irc_check_login( irc_t *irc ) +{ + if( irc->user && irc->nick ) + { + if( global.conf->authmode == AUTHMODE_CLOSED && irc->status < USTATUS_AUTHORIZED ) + { + irc_reply( irc, 464, ":This server is password-protected." ); + return 0; + } + else + { + irc_login( irc ); + return 1; + } + } + else + { + /* More information needed. */ + return 0; + } +} + void irc_login( irc_t *irc ) { user_t *u; diff --git a/irc.h b/irc.h index 32b19642..69d103b0 100644 --- a/irc.h +++ b/irc.h @@ -117,6 +117,7 @@ G_MODULE_EXPORT int irc_usermsg( irc_t *irc, char *format, ... ); char **irc_tokenize( char *buffer ); void irc_login( irc_t *irc ); +int irc_check_login( irc_t *irc ); void irc_motd( irc_t *irc ); void irc_names( irc_t *irc, char *channel ); void irc_topic( irc_t *irc, char *channel ); diff --git a/irc_commands.c b/irc_commands.c index 37d530ea..696c45d4 100644 --- a/irc_commands.c +++ b/irc_commands.c @@ -28,13 +28,14 @@ static int irc_cmd_pass( irc_t *irc, char **cmd ) { - if( strcmp( cmd[1], (global.conf)->auth_pass ) == 0 ) + if( global.conf->auth_pass && strcmp( cmd[1], global.conf->auth_pass ) == 0 ) { irc->status = USTATUS_AUTHORIZED; + irc_check_login(); } else { - irc_reply( irc, 464, ":Nope, maybe you should try it again..." ); + irc_reply( irc, 464, ":Incorrect password." ); } return( 1 ); @@ -42,16 +43,10 @@ static int irc_cmd_pass( irc_t *irc, char **cmd ) static int irc_cmd_user( irc_t *irc, char **cmd ) { - if( irc->user ) - { - irc_reply( irc, 462, ":You can't change your nick/userinfo" ); - } - else - { - irc->user = g_strdup( cmd[1] ); - irc->realname = g_strdup( cmd[4] ); - if( irc->nick ) irc_login( irc ); - } + irc->user = g_strdup( cmd[1] ); + irc->realname = g_strdup( cmd[4] ); + + irc_check_login( irc ); return( 1 ); } @@ -75,7 +70,8 @@ static int irc_cmd_nick( irc_t *irc, char **cmd ) else { irc->nick = g_strdup( cmd[1] ); - if( irc->user ) irc_login( irc ); + + irc_check_login( irc ); } return( 1 ); @@ -89,14 +85,6 @@ static int irc_cmd_quit( irc_t *irc, char **cmd ) return( 0 ); } -/* - if( !irc->user || !irc->nick ) - { - irc_reply( irc, 451, ":Register first" ); - return( 1 ); - } -*/ - static int irc_cmd_ping( irc_t *irc, char **cmd ) { irc_write( irc, ":%s PONG %s :%s", irc->myhost, irc->myhost, cmd[1]?cmd[1]:irc->myhost ); @@ -625,12 +613,21 @@ int irc_exec( irc_t *irc, char *cmd[] ) for( i = 0; irc_commands[i].command; i++ ) if( g_strcasecmp( irc_commands[i].command, cmd[0] ) == 0 ) { - if( irc_commands[i].flags & IRC_CMD_PRE_LOGIN && irc->status > USTATUS_AUTHORIZED ) - continue; + if( irc_commands[i].flags & IRC_CMD_PRE_LOGIN && irc->status >= USTATUS_LOGGED_IN ) + { + irc_reply( irc, 462, ":Only allowed before logging in" ); + return( 1 ); + } if( irc_commands[i].flags & IRC_CMD_LOGGED_IN && irc->status < USTATUS_LOGGED_IN ) - continue; + { + irc_reply( irc, 451, ":Register first" ); + return( 1 ); + } if( irc_commands[i].flags & IRC_CMD_OPER_ONLY && !strchr( irc->umode, 'o' ) ) - continue; + { + irc_reply( irc, 481, ":Permission denied - You're not an IRC operator" ); + return( 1 ); + } for( j = 1; j <= irc_commands[i].required_parameters; j ++ ) if( !cmd[j] ) -- cgit v1.2.3 From b23c5c758097e7c7e9e0141ba9467177c0c32114 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 14 Jan 2006 20:12:48 +0100 Subject: Added correct responses for OPER command, stripped some unnecessary periods. --- irc_commands.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/irc_commands.c b/irc_commands.c index 696c45d4..81b3d60b 100644 --- a/irc_commands.c +++ b/irc_commands.c @@ -35,7 +35,7 @@ static int irc_cmd_pass( irc_t *irc, char **cmd ) } else { - irc_reply( irc, 464, ":Incorrect password." ); + irc_reply( irc, 464, ":Incorrect password" ); } return( 1 ); @@ -95,9 +95,14 @@ static int irc_cmd_ping( irc_t *irc, char **cmd ) static int irc_cmd_oper( irc_t *irc, char **cmd ) { if( global.conf->oper_pass && strcmp( cmd[2], global.conf->oper_pass ) == 0 ) + { irc_umode_set( irc, "+o", 1 ); - // else - /* FIXME/TODO: Find out which reply to send now. */ + irc_reply( irc, 381, ":Password accepted" ); + } + else + { + irc_reply( irc, 432, ":Incorrect password" ); + } return( 1 ); } @@ -310,7 +315,7 @@ static int irc_cmd_who( irc_t *irc, char **cmd ) else if( ( u = user_find( irc, channel ) ) ) irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->online ? ( u->away ? 'G' : 'H' ) : 'G', u->realname ); - irc_reply( irc, 315, "%s :End of /WHO list.", channel?channel:"**" ); + irc_reply( irc, 315, "%s :End of /WHO list", channel?channel:"**" ); return( 1 ); } -- cgit v1.2.3 From de3e100b7fa676bb628ead4cca2b8cee91fc3a84 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 14 Jan 2006 21:31:59 +0100 Subject: Separated the IRC line splitting/parsing code (to use it for IPC too), and improved the splitting to deal with empty arguments. --- irc.c | 149 +++++++++++++++++++++++++++++++-------------------------- irc.h | 2 +- irc_commands.c | 2 +- 3 files changed, 84 insertions(+), 69 deletions(-) diff --git a/irc.c b/irc.c index da6a70c7..86bcba35 100644 --- a/irc.c +++ b/irc.c @@ -292,30 +292,45 @@ void irc_setpass (irc_t *irc, const char *pass) int irc_process( irc_t *irc ) { - char **lines, *temp; + char **lines, *temp, **cmd; int i; - if( irc->readbuffer != NULL ) { - lines = irc_tokenize(irc->readbuffer ); - for( i = 0; *lines[i] != '\0'; i++ ) { - if( lines[i+1] == NULL ) { + if( irc->readbuffer != NULL ) + { + lines = irc_tokenize( irc->readbuffer ); + + for( i = 0; *lines[i] != '\0'; i ++ ) + { + if( lines[i+1] == NULL ) + { temp = g_strdup( lines[i] ); g_free( irc->readbuffer ); irc->readbuffer = temp; - i++; + i ++; break; } - if (!irc_process_line(irc, lines[i])) { + + if( ( cmd = irc_parse_line( irc, lines[i] ) ) == NULL ) + continue; + if( !irc_exec( irc, cmd ) ) + { + g_free( cmd ); g_free( lines ); return 0; } + + g_free( cmd ); } - if(lines[i]!=NULL) { - g_free(irc->readbuffer); - irc->readbuffer=NULL; + + if( lines[i] != NULL ) + { + g_free( irc->readbuffer ); + irc->readbuffer = NULL; } + g_free( lines ); } + return 1; } @@ -325,97 +340,97 @@ char **irc_tokenize( char *buffer ) char **lines; /* Count the number of elements we're gonna need. */ - for(i=0, j=1; buffer[i]!='\0'; i++ ) { - if(buffer[i]=='\n' ) - if(buffer[i+1]!='\r' && buffer[i+1]!='\n') - j++; + for( i = 0, j = 1; buffer[i] != '\0'; i ++ ) + { + if( buffer[i] == '\n' ) + if( buffer[i+1] != '\r' && buffer[i+1] != '\n' ) + j ++; } /* Allocate j+1 elements. */ - lines=g_new (char *, j+1); + lines = g_new( char *, j + 1 ); /* NULL terminate our list. */ - lines[j]=NULL; + lines[j] = NULL; - lines[0]=buffer; + lines[0] = buffer; /* Split the buffer in several strings, using \r\n as our seperator, where \r is optional. * Although this is not in the RFC, some braindead ircds (newnet's) use this, so some clients might too. */ - for( i=0, j=0; buffer[i]!='\0'; i++) { - if(buffer[i]=='\n') { - buffer[i]='\0'; - - /* We dont want to read 1 byte before our buffer - * and (in rare cases) generate a SIGSEGV. - */ - if(i!=0) - if(buffer[i-1]=='\r') - buffer[i-1]='\0'; - if(buffer[i+1]!='\r'&&buffer[i+1]!='\n') - lines[++j]=buffer+i+1; + for( i = 0, j = 0; buffer[i] != '\0'; i ++) + { + if( buffer[i] == '\n' ) + { + buffer[i] = '\0'; + + if( i > 0 && buffer[i-1] == '\r' ) + buffer[i-1] = '\0'; + if( buffer[i+1] != '\r' && buffer[i+1] != '\n' ) + lines[++j] = buffer + i + 1; } } - - return(lines); + + return( lines ); } -int irc_process_line( irc_t *irc, char *line ) +char **irc_parse_line( irc_t *irc, char *line ) { int i, j; char **cmd; /* Move the line pointer to the start of the command, skipping spaces and the optional prefix. */ - if(line[0]==':') { - for(i=0; line[i]!=32; i++); - line=line+i; + if( line[0] == ':' ) + { + for( i = 0; line[i] != ' '; i ++ ); + line = line + i; } - for(i=0; line[i]==32; i++); - line=line+i; - + for( i = 0; line[i] == ' '; i ++ ); + line = line + i; + /* If we're already at the end of the line, return. If not, we're going to need at least one element. */ - if(line[0]=='\0') - return 1; - else - j=1; - - /* Count the number of char **cmd elements we're going to need. */ - for(i=0; line[i]!='\0'; i++) { - if((line[i]==32) && (line[i+1]!=32) && (line[i+1]!='\0') && (line[i+1]!=':')) - j++; - else if((line[i]==':') && (line[i+1]!='\0') && (line[i-1]==32)) { - j++; - break; - } + if( line[0] == '\0') + return NULL; + + /* Count the number of char **cmd elements we're going to need. */ + j = 1; + for( i = 0; line[i] != '\0'; i ++ ) + { + if( line[i] == ' ' ) + { + j ++; + if( line[i+1] == ':' ) + break; + } } /* Allocate the space we need. */ - cmd=g_new(char *, j+1); - cmd[j]=NULL; + cmd = g_new( char *, j + 1 ); + cmd[j] = NULL; /* Do the actual line splitting, format is: * Input: "PRIVMSG #bitlbee :foo bar" * Output: cmd[0]=="PRIVMSG", cmd[1]=="#bitlbee", cmd[2]=="foo bar", cmd[3]==NULL */ - cmd[0]=line; - for(i=0, j=0; line[i]!='\0'; i++) { - if((line[i]==32)) { - line[i]='\0'; - if((line[i+1]!=32) && (line[i+1]!='\0') && (line[i+1]!=':')) - cmd[++j]=line+i+1; - } - else if((line[i]==':') && (line[i+1]!='\0') && (line[i-1]=='\0')) { - cmd[++j]=line+i+1; - break; + cmd[0] = line; + for( i = 0, j = 0; line[i] != '\0'; i ++ ) + { + if( line[i] == ' ' ) + { + line[i] = '\0'; + cmd[++j] = line + i + 1; + + if( line[i+1] == ':' ) + { + cmd[j] ++; + break; + } } } - i=irc_exec(irc, cmd); - g_free(cmd); - - return(i); + return cmd; } void irc_reply( irc_t *irc, int code, char *format, ... ) diff --git a/irc.h b/irc.h index 69d103b0..e5b90ea5 100644 --- a/irc.h +++ b/irc.h @@ -107,7 +107,7 @@ void irc_free( irc_t *irc ); int irc_exec( irc_t *irc, char **cmd ); int irc_process( irc_t *irc ); -int irc_process_line( irc_t *irc, char *line ); +char **irc_parse_line( irc_t *irc, char *line ); void irc_vawrite( irc_t *irc, char *format, va_list params ); void irc_write( irc_t *irc, char *format, ... ); diff --git a/irc_commands.c b/irc_commands.c index 81b3d60b..a7cb9963 100644 --- a/irc_commands.c +++ b/irc_commands.c @@ -31,7 +31,7 @@ static int irc_cmd_pass( irc_t *irc, char **cmd ) if( global.conf->auth_pass && strcmp( cmd[1], global.conf->auth_pass ) == 0 ) { irc->status = USTATUS_AUTHORIZED; - irc_check_login(); + irc_check_login( irc ); } else { -- cgit v1.2.3 From e0ca412a709c80cc7fe26db0576c2bc38be4a45a Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 15 Jan 2006 12:33:54 +0100 Subject: s/WALLOP/WALLOPS/, added LILO command. --- ipc.c | 24 ++++++++++++++++++------ irc_commands.c | 3 ++- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/ipc.c b/ipc.c index 81ef4ce8..a60a1c0c 100644 --- a/ipc.c +++ b/ipc.c @@ -32,16 +32,17 @@ GSList *child_list = NULL; static int ipc_master_cmd_die( irc_t *data, char **cmd ) { + /* This shouldn't really be the final implementation... */ exit( 0 ); } -static int ipc_master_cmd_wallop( irc_t *data, char **cmd ) +static int ipc_master_cmd_wallops( irc_t *data, char **cmd ) { GSList *l; char msg_buf[513]; int msg_len; - if( ( msg_len = g_snprintf( msg_buf, sizeof( msg_buf ) - 1, "WALLOP :%s\r\n", cmd[1] ) ) > ( sizeof( msg_buf ) - 1 ) ) + if( ( msg_len = g_snprintf( msg_buf, sizeof( msg_buf ) - 1, "%s :%s\r\n", cmd[0], cmd[1] ) ) > ( sizeof( msg_buf ) - 1 ) ) return 0; for( l = child_list; l; l = l->next ) @@ -55,22 +56,33 @@ static int ipc_master_cmd_wallop( irc_t *data, char **cmd ) static const command_t ipc_master_commands[] = { { "die", 0, ipc_master_cmd_die, 0 }, - { "wallop", 1, ipc_master_cmd_wallop, 1 }, + { "wallops", 1, ipc_master_cmd_wallops, 1 }, + { "lilo", 1, ipc_master_cmd_wallops, 1 }, { NULL } }; -static int ipc_child_cmd_wallop( irc_t *data, char **cmd ) +static int ipc_child_cmd_wallops( irc_t *data, char **cmd ) { irc_t *irc = data; if( strchr( irc->umode, 'w' ) ) - irc_write( irc, ":%s WALLOP :%s", irc->myhost, cmd[1] ); + irc_write( irc, ":%s WALLOPS :%s", irc->myhost, cmd[1] ); + + return 1; +} + +static int ipc_child_cmd_lilo( irc_t *data, char **cmd ) +{ + irc_t *irc = data; + + irc_write( irc, ":%s NOTICE %s :%s", irc->myhost, irc->nick, cmd[1] ); return 1; } static const command_t ipc_child_commands[] = { - { "wallop", 1, ipc_child_cmd_wallop, 1 }, + { "wallops", 1, ipc_child_cmd_wallops, 1 }, + { "lilo", 1, ipc_child_cmd_lilo, 1 }, { NULL } }; diff --git a/irc_commands.c b/irc_commands.c index 3ef5566e..b2bde17b 100644 --- a/irc_commands.c +++ b/irc_commands.c @@ -607,7 +607,8 @@ static const command_t irc_commands[] = { { "pong", 0, irc_cmd_pong, IRC_CMD_LOGGED_IN }, { "completions", 0, irc_cmd_completions, IRC_CMD_LOGGED_IN }, { "die", 0, NULL, IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER }, - { "wallop", 0, NULL, IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER }, + { "wallops", 0, NULL, IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER }, + { "lilo", 0, NULL, IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER }, { NULL } }; -- cgit v1.2.3 From 13caf0aa5d1e5575b74221e0cd9e4ff9f4cd79a8 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 15 Jan 2006 15:16:49 +0100 Subject: Better implementation of /DIE --- ipc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ipc.c b/ipc.c index a60a1c0c..03c44827 100644 --- a/ipc.c +++ b/ipc.c @@ -32,8 +32,7 @@ GSList *child_list = NULL; static int ipc_master_cmd_die( irc_t *data, char **cmd ) { - /* This shouldn't really be the final implementation... */ - exit( 0 ); + bitlbee_shutdown( NULL ); } static int ipc_master_cmd_wallops( irc_t *data, char **cmd ) -- cgit v1.2.3 From 74c119dd1b066329eba59d057935ba7ec7249555 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 15 Jan 2006 16:42:20 +0100 Subject: Better DIE implementation, added SO_REUSEADDR to listening socket. --- bitlbee.c | 4 +++ conf.c | 12 +++++---- ipc.c | 86 +++++++++++++++++++++++++++++++++++---------------------------- ipc.h | 2 ++ irc.c | 31 +++++++++++++++++++++++ irc.h | 1 + 6 files changed, 93 insertions(+), 43 deletions(-) diff --git a/bitlbee.c b/bitlbee.c index f6605552..dc6b8261 100644 --- a/bitlbee.c +++ b/bitlbee.c @@ -55,6 +55,10 @@ int bitlbee_daemon_init() return( -1 ); } + /* TIME_WAIT (?) sucks.. */ + i = 1; + setsockopt( global.listen_socket, SOL_SOCKET, SO_REUSEADDR, &i, sizeof( i ) ); + #ifdef IPV6 listen_addr.sin6_family = AF_INETx; listen_addr.sin6_port = htons( global.conf->port ); diff --git a/conf.c b/conf.c index 6ec20015..dd165869 100644 --- a/conf.c +++ b/conf.c @@ -91,15 +91,15 @@ conf_t *conf_load( int argc, char *argv[] ) conf->port = i; } else if( opt == 'n' ) - conf->nofork=1; + conf->nofork = 1; else if( opt == 'v' ) - conf->verbose=1; + conf->verbose = 1; else if( opt == 'I' ) - conf->runmode=RUNMODE_INETD; + conf->runmode = RUNMODE_INETD; else if( opt == 'D' ) - conf->runmode=RUNMODE_DAEMON; + conf->runmode = RUNMODE_DAEMON; else if( opt == 'F' ) - conf->runmode=RUNMODE_FORKDAEMON; + conf->runmode = RUNMODE_FORKDAEMON; else if( opt == 'c' ) { if( strcmp( CONF_FILE, optarg ) != 0 ) @@ -107,6 +107,8 @@ conf_t *conf_load( int argc, char *argv[] ) g_free( CONF_FILE ); CONF_FILE = g_strdup( optarg ); g_free( conf ); + /* Re-evaluate arguments. */ + optind = 1; return( conf_load( argc, argv ) ); } } diff --git a/ipc.c b/ipc.c index 03c44827..f7435776 100644 --- a/ipc.c +++ b/ipc.c @@ -30,36 +30,39 @@ GSList *child_list = NULL; + static int 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 ); + + return 1; } static int ipc_master_cmd_wallops( irc_t *data, char **cmd ) { - GSList *l; - char msg_buf[513]; - int msg_len; - - if( ( msg_len = g_snprintf( msg_buf, sizeof( msg_buf ) - 1, "%s :%s\r\n", cmd[0], cmd[1] ) ) > ( sizeof( msg_buf ) - 1 ) ) - return 0; - - for( l = child_list; l; l = l->next ) - { - struct bitlbee_child *c = l->data; - write( c->ipc_fd, msg_buf, msg_len ); - } + ipc_to_children( cmd ); return 1; } static const command_t ipc_master_commands[] = { { "die", 0, ipc_master_cmd_die, 0 }, - { "wallops", 1, ipc_master_cmd_wallops, 1 }, - { "lilo", 1, ipc_master_cmd_wallops, 1 }, + { "wallops", 1, ipc_master_cmd_wallops, 0 }, + { "lilo", 1, ipc_master_cmd_wallops, 0 }, { NULL } }; + +static int ipc_child_cmd_die( irc_t *data, char **cmd ) +{ + bitlbee_shutdown( NULL ); + + return 1; +} + static int ipc_child_cmd_wallops( irc_t *data, char **cmd ) { irc_t *irc = data; @@ -74,17 +77,20 @@ static int ipc_child_cmd_lilo( irc_t *data, char **cmd ) { irc_t *irc = data; - irc_write( irc, ":%s NOTICE %s :%s", irc->myhost, irc->nick, cmd[1] ); + if( strchr( irc->umode, 's' ) ) + irc_write( irc, ":%s NOTICE %s :%s", irc->myhost, irc->nick, cmd[1] ); return 1; } static const command_t ipc_child_commands[] = { - { "wallops", 1, ipc_child_cmd_wallops, 1 }, - { "lilo", 1, ipc_child_cmd_lilo, 1 }, + { "die", 0, ipc_child_cmd_die, 0 }, + { "wallops", 1, ipc_child_cmd_wallops, 0 }, + { "lilo", 1, ipc_child_cmd_lilo, 0 }, { NULL } }; + static void ipc_command_exec( void *data, char **cmd, const command_t *commands ) { int i; @@ -190,29 +196,33 @@ void ipc_to_master( char **cmd ) { if( global.conf->runmode == RUNMODE_FORKDAEMON ) { - int i, len; - char *s; - - len = 1; - for( i = 0; cmd[i]; i ++ ) - len += strlen( cmd[i] ) + 1; - - if( strchr( cmd[i-1], ' ' ) != NULL ) - len ++; + char *s = irc_build_line( cmd ); + write( global.listen_socket, s, strlen( s ) ); + g_free( s ); + } +} + +void ipc_to_children( char **cmd ) +{ + if( global.conf->runmode == RUNMODE_FORKDAEMON ) + { + char *msg_buf = irc_build_line( cmd ); + ipc_to_children_str( msg_buf ); + g_free( msg_buf ); + } +} + +void ipc_to_children_str( char *msg_buf ) +{ + if( global.conf->runmode == RUNMODE_FORKDAEMON ) + { + int msg_len = strlen( msg_buf ); + GSList *l; - s = g_new0( char, len + 1 ); - for( i = 0; cmd[i]; i ++ ) + for( l = child_list; l; l = l->next ) { - if( cmd[i+1] == NULL && strchr( cmd[i], ' ' ) != NULL ) - strcat( s, ":" ); - - strcat( s, cmd[i] ); - - if( cmd[i+1] ) - strcat( s, " " ); + struct bitlbee_child *c = l->data; + write( c->ipc_fd, msg_buf, msg_len ); } - strcat( s, "\r\n" ); - - write( global.listen_socket, s, len ); } } diff --git a/ipc.h b/ipc.h index 8c48147c..393cb0aa 100644 --- a/ipc.h +++ b/ipc.h @@ -29,6 +29,8 @@ void ipc_master_read( gpointer data, gint source, GaimInputCondition cond ); void ipc_child_read( gpointer data, gint source, GaimInputCondition cond ); void ipc_to_master( char **cmd ); +void ipc_to_children( char **cmd ); +void ipc_to_children_str( char *msg_buf ); struct bitlbee_child { diff --git a/irc.c b/irc.c index a00c4192..a0ba6e53 100644 --- a/irc.c +++ b/irc.c @@ -433,6 +433,37 @@ char **irc_parse_line( char *line ) return cmd; } +char *irc_build_line( char **cmd ) +{ + int i, len; + char *s; + + if( cmd[0] == NULL ) + return NULL; + + len = 1; + for( i = 0; cmd[i]; i ++ ) + len += strlen( cmd[i] ) + 1; + + if( strchr( cmd[i-1], ' ' ) != NULL ) + len ++; + + s = g_new0( char, len + 1 ); + for( i = 0; cmd[i]; i ++ ) + { + if( cmd[i+1] == NULL && strchr( cmd[i], ' ' ) != NULL ) + strcat( s, ":" ); + + strcat( s, cmd[i] ); + + if( cmd[i+1] ) + strcat( s, " " ); + } + strcat( s, "\r\n" ); + + return s; +} + void irc_reply( irc_t *irc, int code, char *format, ... ) { char text[IRC_MAX_LINE]; diff --git a/irc.h b/irc.h index 8517bb7e..c8246c16 100644 --- a/irc.h +++ b/irc.h @@ -108,6 +108,7 @@ void irc_free( irc_t *irc ); int irc_exec( irc_t *irc, char **cmd ); int irc_process( irc_t *irc ); char **irc_parse_line( char *line ); +char *irc_build_line( char **cmd ); void irc_vawrite( irc_t *irc, char *format, va_list params ); void irc_write( irc_t *irc, char *format, ... ); -- cgit v1.2.3 From 6fda35070cadc83a6b78c85896fcaf85299e5ad8 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 15 Jan 2006 17:41:55 +0100 Subject: Fixed a bug in url.c that interpreted all http-urls as https. --- url.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/url.c b/url.c index 816f4ef3..e4deac78 100644 --- a/url.c +++ b/url.c @@ -39,10 +39,10 @@ int url_set( url_t *url, char *set_url ) } else { - if( g_strncasecmp( set_url, "https", i - set_url ) == 0 ) - url->proto = PROTO_HTTPS; - else if( g_strncasecmp( set_url, "http", i - set_url ) == 0 ) + if( g_strncasecmp( set_url, "http", i - set_url ) == 0 ) url->proto = PROTO_HTTP; + else if( g_strncasecmp( set_url, "https", i - set_url ) == 0 ) + url->proto = PROTO_HTTPS; else if( g_strncasecmp( set_url, "socks4", i - set_url ) == 0 ) url->proto = PROTO_SOCKS4; else if( g_strncasecmp( set_url, "socks5", i - set_url ) == 0 ) -- cgit v1.2.3 From f4a59408250b76173418fad090d4623e5300c90f Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 15 Jan 2006 21:31:59 +0100 Subject: Added REHASH command, IPC emulation in daemon (non-forked) mode. --- commands.h | 2 ++ conf.c | 8 ++++-- ipc.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---- ipc.h | 2 ++ irc_commands.c | 12 ++++++-- 5 files changed, 105 insertions(+), 10 deletions(-) diff --git a/commands.h b/commands.h index e43d275a..a881499a 100644 --- a/commands.h +++ b/commands.h @@ -43,4 +43,6 @@ extern const command_t commands[]; #define IRC_CMD_OPER_ONLY 4 #define IRC_CMD_TO_MASTER 8 +#define IPC_CMD_TO_CHILDREN 1 + #endif diff --git a/conf.c b/conf.c index dd165869..ae4b77a2 100644 --- a/conf.c +++ b/conf.c @@ -63,6 +63,7 @@ conf_t *conf_load( int argc, char *argv[] ) conf->motdfile = g_strdup( ETCDIR "/motd.txt" ); conf->ping_interval = 180; conf->ping_timeout = 300; + proxytype = 0; i = conf_loadini( conf, CONF_FILE ); if( i == 0 ) @@ -75,7 +76,8 @@ conf_t *conf_load( int argc, char *argv[] ) fprintf( stderr, "Warning: Unable to read configuration file `%s'.\n", CONF_FILE ); } - while( ( opt = getopt( argc, argv, "i:p:nvIDFc:d:h" ) ) >= 0 ) + while( argc > 0 && ( opt = getopt( argc, argv, "i:p:nvIDFc:d:h" ) ) >= 0 ) + /* ^^^^ Just to make sure we skip this step from the REHASH handler. */ { if( opt == 'i' ) { @@ -107,7 +109,9 @@ conf_t *conf_load( int argc, char *argv[] ) g_free( CONF_FILE ); CONF_FILE = g_strdup( optarg ); g_free( conf ); - /* Re-evaluate arguments. */ + /* Re-evaluate arguments. Don't use this option twice, + you'll end up in an infinite loop! Hope this trick + works with all libcs BTW.. */ optind = 1; return( conf_load( argc, argv ) ); } diff --git a/ipc.c b/ipc.c index f7435776..5d6790f0 100644 --- a/ipc.c +++ b/ipc.c @@ -41,17 +41,32 @@ static int ipc_master_cmd_die( irc_t *data, char **cmd ) return 1; } -static int ipc_master_cmd_wallops( irc_t *data, char **cmd ) +static int ipc_master_cmd_rehash( irc_t *data, char **cmd ) { - ipc_to_children( cmd ); + runmode_t oldmode; + + oldmode = global.conf->runmode; + + g_free( global.conf ); + global.conf = conf_load( 0, NULL ); + + if( global.conf->runmode != oldmode ) + { + log_message( LOGLVL_WARNING, "Can't change RunMode setting at runtime, restoring original setting" ); + global.conf->runmode = oldmode; + } + + if( global.conf->runmode == RUNMODE_FORKDAEMON ) + ipc_to_children( cmd ); return 1; } static const command_t ipc_master_commands[] = { { "die", 0, ipc_master_cmd_die, 0 }, - { "wallops", 1, ipc_master_cmd_wallops, 0 }, - { "lilo", 1, ipc_master_cmd_wallops, 0 }, + { "wallops", 1, NULL, IPC_CMD_TO_CHILDREN }, + { "lilo", 1, NULL, IPC_CMD_TO_CHILDREN }, + { "rehash", 0, ipc_master_cmd_rehash, 0 }, { NULL } }; @@ -83,10 +98,25 @@ static int ipc_child_cmd_lilo( irc_t *data, char **cmd ) return 1; } +static int ipc_child_cmd_rehash( irc_t *data, char **cmd ) +{ + runmode_t oldmode; + + oldmode = global.conf->runmode; + + g_free( global.conf ); + global.conf = conf_load( 0, NULL ); + + global.conf->runmode = oldmode; + + return 1; +} + static const command_t ipc_child_commands[] = { { "die", 0, ipc_child_cmd_die, 0 }, { "wallops", 1, ipc_child_cmd_wallops, 0 }, { "lilo", 1, ipc_child_cmd_lilo, 0 }, + { "rehash", 0, ipc_child_cmd_rehash, 0 }, { NULL } }; @@ -101,7 +131,11 @@ static void ipc_command_exec( void *data, char **cmd, const command_t *commands for( i = 0; commands[i].command; i ++ ) if( g_strcasecmp( commands[i].command, cmd[0] ) == 0 ) { - commands[i].execute( data, cmd ); + if( commands[i].flags & IPC_CMD_TO_CHILDREN ) + ipc_to_children( cmd ); + else + commands[i].execute( data, cmd ); + return; } } @@ -197,7 +231,32 @@ void ipc_to_master( char **cmd ) if( global.conf->runmode == RUNMODE_FORKDAEMON ) { char *s = irc_build_line( cmd ); - write( global.listen_socket, s, strlen( s ) ); + ipc_to_master_str( s ); + g_free( s ); + } + else if( global.conf->runmode == RUNMODE_DAEMON ) + { + ipc_command_exec( NULL, cmd, ipc_master_commands ); + } +} + +void ipc_to_master_str( char *msg_buf ) +{ + if( global.conf->runmode == RUNMODE_FORKDAEMON ) + { + write( global.listen_socket, msg_buf, strlen( msg_buf ) ); + } + else if( global.conf->runmode == RUNMODE_DAEMON ) + { + char *s, **cmd; + + /* irc_parse_line() wants a read-write string, so get it one: */ + s = g_strdup( msg_buf ); + cmd = irc_parse_line( s ); + + ipc_command_exec( NULL, cmd, ipc_master_commands ); + + g_free( cmd ); g_free( s ); } } @@ -210,6 +269,13 @@ void ipc_to_children( char **cmd ) ipc_to_children_str( msg_buf ); g_free( msg_buf ); } + else if( global.conf->runmode == RUNMODE_DAEMON ) + { + GSList *l; + + for( l = irc_connection_list; l; l = l->next ) + ipc_command_exec( l->data, cmd, ipc_child_commands ); + } } void ipc_to_children_str( char *msg_buf ) @@ -225,4 +291,17 @@ void ipc_to_children_str( char *msg_buf ) write( c->ipc_fd, msg_buf, msg_len ); } } + else if( global.conf->runmode == RUNMODE_DAEMON ) + { + char *s, **cmd; + + /* irc_parse_line() wants a read-write string, so get it one: */ + s = g_strdup( msg_buf ); + cmd = irc_parse_line( s ); + + ipc_to_children( cmd ); + + g_free( cmd ); + g_free( s ); + } } diff --git a/ipc.h b/ipc.h index 393cb0aa..57037d61 100644 --- a/ipc.h +++ b/ipc.h @@ -28,7 +28,9 @@ void ipc_master_read( gpointer data, gint source, GaimInputCondition cond ); void ipc_child_read( gpointer data, gint source, GaimInputCondition cond ); + void ipc_to_master( char **cmd ); +void ipc_to_master_str( char *msg_buf ); void ipc_to_children( char **cmd ); void ipc_to_children_str( char *msg_buf ); diff --git a/irc_commands.c b/irc_commands.c index b2bde17b..5f666702 100644 --- a/irc_commands.c +++ b/irc_commands.c @@ -232,7 +232,6 @@ static int irc_cmd_invite( irc_t *irc, char **cmd ) return( 1 ); } -/* TODO: Attach this one to NOTICE too! */ static int irc_cmd_privmsg( irc_t *irc, char **cmd ) { if ( !cmd[2] ) @@ -529,7 +528,6 @@ static int irc_cmd_whowas( irc_t *irc, char **cmd ) return( 1 ); } -/* TODO: Alias to NS */ static int irc_cmd_nickserv( irc_t *irc, char **cmd ) { /* [SH] This aliases the NickServ command to PRIVMSG root */ @@ -579,6 +577,15 @@ static int irc_cmd_completions( irc_t *irc, char **cmd ) return( 1 ); } +static int irc_cmd_rehash( irc_t *irc, char **cmd ) +{ + ipc_to_master( cmd ); + + irc_reply( irc, 382, "%s :Rehashing", CONF_FILE ); + + return( 1 ); +} + static const command_t irc_commands[] = { { "pass", 1, irc_cmd_pass, IRC_CMD_PRE_LOGIN }, { "user", 4, irc_cmd_user, IRC_CMD_PRE_LOGIN }, @@ -609,6 +616,7 @@ static const command_t irc_commands[] = { { "die", 0, NULL, IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER }, { "wallops", 0, NULL, IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER }, { "lilo", 0, NULL, IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER }, + { "rehash", 0, irc_cmd_rehash, IRC_CMD_OPER_ONLY }, { NULL } }; -- cgit v1.2.3 From d9909972078956f7f362ba479cc22250cc6e1b13 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 16 Jan 2006 00:37:13 +0100 Subject: The MOTD is not a socket... --- irc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/irc.c b/irc.c index 32dadb7c..782a63dc 100644 --- a/irc.c +++ b/irc.c @@ -1158,7 +1158,7 @@ void irc_motd( irc_t *irc ) } } irc_reply( irc, 376, ":End of MOTD" ); - closesocket( fd ); + close( fd ); } } -- cgit v1.2.3 From daa9e027e8c8d1bc91e104dba985d5d44fef8c77 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Tue, 17 Jan 2006 19:05:22 +0100 Subject: LILO/WALLOPS commands now check if the receiving user logged in yet. --- ipc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ipc.c b/ipc.c index 5d6790f0..5e7b7821 100644 --- a/ipc.c +++ b/ipc.c @@ -82,6 +82,9 @@ static int ipc_child_cmd_wallops( irc_t *data, char **cmd ) { irc_t *irc = data; + if( irc->status < USTATUS_LOGGED_IN ) + return 1; + if( strchr( irc->umode, 'w' ) ) irc_write( irc, ":%s WALLOPS :%s", irc->myhost, cmd[1] ); @@ -92,6 +95,9 @@ static int ipc_child_cmd_lilo( irc_t *data, char **cmd ) { irc_t *irc = data; + if( irc->status < USTATUS_LOGGED_IN ) + return 1; + if( strchr( irc->umode, 's' ) ) irc_write( irc, ":%s NOTICE %s :%s", irc->myhost, irc->nick, cmd[1] ); -- cgit v1.2.3 From 48721c328e574e0ff76c41734b78aab217edbf65 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Tue, 17 Jan 2006 22:15:42 +0100 Subject: A KILL command. Unfortunately the user doesn't see the KILL message yet. :-( --- ipc.c | 34 +++++++++++++++++++++++----------- irc_commands.c | 5 +++-- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/ipc.c b/ipc.c index 5e7b7821..cd30eb52 100644 --- a/ipc.c +++ b/ipc.c @@ -31,7 +31,7 @@ GSList *child_list = NULL; -static int ipc_master_cmd_die( irc_t *data, char **cmd ) +static int ipc_master_cmd_die( irc_t *irc, char **cmd ) { if( global.conf->runmode == RUNMODE_FORKDAEMON ) ipc_to_children_str( "DIE\r\n" ); @@ -41,7 +41,7 @@ static int ipc_master_cmd_die( irc_t *data, char **cmd ) return 1; } -static int ipc_master_cmd_rehash( irc_t *data, char **cmd ) +static int ipc_master_cmd_rehash( irc_t *irc, char **cmd ) { runmode_t oldmode; @@ -67,21 +67,20 @@ static const command_t ipc_master_commands[] = { { "wallops", 1, NULL, IPC_CMD_TO_CHILDREN }, { "lilo", 1, NULL, IPC_CMD_TO_CHILDREN }, { "rehash", 0, ipc_master_cmd_rehash, 0 }, + { "kill", 2, NULL, IPC_CMD_TO_CHILDREN }, { NULL } }; -static int ipc_child_cmd_die( irc_t *data, char **cmd ) +static int ipc_child_cmd_die( irc_t *irc, char **cmd ) { bitlbee_shutdown( NULL ); return 1; } -static int ipc_child_cmd_wallops( irc_t *data, char **cmd ) +static int ipc_child_cmd_wallops( irc_t *irc, char **cmd ) { - irc_t *irc = data; - if( irc->status < USTATUS_LOGGED_IN ) return 1; @@ -91,10 +90,8 @@ static int ipc_child_cmd_wallops( irc_t *data, char **cmd ) return 1; } -static int ipc_child_cmd_lilo( irc_t *data, char **cmd ) +static int ipc_child_cmd_lilo( irc_t *irc, char **cmd ) { - irc_t *irc = data; - if( irc->status < USTATUS_LOGGED_IN ) return 1; @@ -104,7 +101,7 @@ static int ipc_child_cmd_lilo( irc_t *data, char **cmd ) return 1; } -static int ipc_child_cmd_rehash( irc_t *data, char **cmd ) +static int ipc_child_cmd_rehash( irc_t *irc, char **cmd ) { runmode_t oldmode; @@ -118,11 +115,26 @@ static int ipc_child_cmd_rehash( irc_t *data, char **cmd ) return 1; } +static int ipc_child_cmd_kill( irc_t *irc, char **cmd ) +{ + if( irc->status < USTATUS_LOGGED_IN ) + return 1; + + if( nick_cmp( cmd[1], irc->nick ) != 0 ) + return 1; /* It's not for us. */ + + irc_write( irc, ":%s!%s@%s KILL %s :%s", irc->mynick, irc->mynick, irc->myhost, irc->nick, cmd[2] ); + g_io_channel_close( irc->io_channel ); + + return 0; +} + static const command_t ipc_child_commands[] = { { "die", 0, ipc_child_cmd_die, 0 }, { "wallops", 1, ipc_child_cmd_wallops, 0 }, { "lilo", 1, ipc_child_cmd_lilo, 0 }, - { "rehash", 0, ipc_child_cmd_rehash, 0 }, + { "rehash", 0, ipc_child_cmd_rehash, 0 }, + { "kill", 2, ipc_child_cmd_kill, 0 }, { NULL } }; diff --git a/irc_commands.c b/irc_commands.c index 5f666702..2e225702 100644 --- a/irc_commands.c +++ b/irc_commands.c @@ -614,9 +614,10 @@ static const command_t irc_commands[] = { { "pong", 0, irc_cmd_pong, IRC_CMD_LOGGED_IN }, { "completions", 0, irc_cmd_completions, IRC_CMD_LOGGED_IN }, { "die", 0, NULL, IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER }, - { "wallops", 0, NULL, IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER }, - { "lilo", 0, NULL, IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER }, + { "wallops", 1, NULL, IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER }, + { "lilo", 1, NULL, IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER }, { "rehash", 0, irc_cmd_rehash, IRC_CMD_OPER_ONLY }, + { "kill", 2, NULL, IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER }, { NULL } }; -- cgit v1.2.3 From ac9f0e965b5002c9eb022f77eb7c6f16cba662b1 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 18 Jan 2006 08:53:50 +0100 Subject: Formatting changes. --- log.c | 112 +++++++++++++++++++++++++++++++++--------------------------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/log.c b/log.c index ad39d775..4606fb88 100644 --- a/log.c +++ b/log.c @@ -37,11 +37,11 @@ static void log_console(int level, char *logmessage); void log_init(void) { openlog("bitlbee", LOG_PID, LOG_DAEMON); - logoutput.informational=&log_null; - logoutput.warning=&log_null; - logoutput.error=&log_null; + logoutput.informational = &log_null; + logoutput.warning = &log_null; + logoutput.error = &log_null; #ifdef DEBUG - logoutput.debug=&log_null; + logoutput.debug = &log_null; #endif return; @@ -50,46 +50,46 @@ void log_init(void) { void log_link(int level, int output) { /* I know it's ugly, but it works and I didn't feel like messing with pointer to function pointers */ - if(level==LOGLVL_INFO) { - if(output==LOGOUTPUT_NULL) - logoutput.informational=&log_null; - else if(output==LOGOUTPUT_IRC) - logoutput.informational=&log_irc; - else if(output==LOGOUTPUT_SYSLOG) - logoutput.informational=&log_syslog; - else if(output==LOGOUTPUT_CONSOLE) - logoutput.informational=&log_console; + if(level == LOGLVL_INFO) { + if(output == LOGOUTPUT_NULL) + logoutput.informational = &log_null; + else if(output == LOGOUTPUT_IRC) + logoutput.informational = &log_irc; + else if(output == LOGOUTPUT_SYSLOG) + logoutput.informational = &log_syslog; + else if(output == LOGOUTPUT_CONSOLE) + logoutput.informational = &log_console; } - else if(level==LOGLVL_WARNING) { - if(output==LOGOUTPUT_NULL) - logoutput.warning=&log_null; - else if(output==LOGOUTPUT_IRC) - logoutput.warning=&log_irc; - else if(output==LOGOUTPUT_SYSLOG) - logoutput.warning=&log_syslog; - else if(output==LOGOUTPUT_CONSOLE) - logoutput.warning=&log_console; + else if(level == LOGLVL_WARNING) { + if(output == LOGOUTPUT_NULL) + logoutput.warning = &log_null; + else if(output == LOGOUTPUT_IRC) + logoutput.warning = &log_irc; + else if(output == LOGOUTPUT_SYSLOG) + logoutput.warning = &log_syslog; + else if(output == LOGOUTPUT_CONSOLE) + logoutput.warning = &log_console; } - else if(level==LOGLVL_ERROR) { - if(output==LOGOUTPUT_NULL) - logoutput.error=&log_null; - else if(output==LOGOUTPUT_IRC) - logoutput.error=&log_irc; - else if(output==LOGOUTPUT_SYSLOG) - logoutput.error=&log_syslog; - else if(output==LOGOUTPUT_CONSOLE) - logoutput.error=&log_console; + else if(level == LOGLVL_ERROR) { + if(output == LOGOUTPUT_NULL) + logoutput.error = &log_null; + else if(output == LOGOUTPUT_IRC) + logoutput.error = &log_irc; + else if(output == LOGOUTPUT_SYSLOG) + logoutput.error = &log_syslog; + else if(output == LOGOUTPUT_CONSOLE) + logoutput.error = &log_console; } #ifdef DEBUG - else if(level==LOGLVL_DEBUG) { - if(output==LOGOUTPUT_NULL) - logoutput.debug=&log_null; - else if(output==LOGOUTPUT_IRC) - logoutput.debug=&log_irc; - else if(output==LOGOUTPUT_SYSLOG) - logoutput.debug=&log_syslog; - else if(output==LOGOUTPUT_CONSOLE) - logoutput.debug=&log_console; + else if(level == LOGLVL_DEBUG) { + if(output == LOGOUTPUT_NULL) + logoutput.debug = &log_null; + else if(output == LOGOUTPUT_IRC) + logoutput.debug = &log_irc; + else if(output == LOGOUTPUT_SYSLOG) + logoutput.debug = &log_syslog; + else if(output == LOGOUTPUT_CONSOLE) + logoutput.debug = &log_console; } #endif return; @@ -105,14 +105,14 @@ void log_message(int level, char *message, ... ) { msgstring = g_strdup_vprintf(message, ap); va_end(ap); - if(level==LOGLVL_INFO) + if(level == LOGLVL_INFO) (*(logoutput.informational))(level, msgstring); - if(level==LOGLVL_WARNING) + if(level == LOGLVL_WARNING) (*(logoutput.warning))(level, msgstring); - if(level==LOGLVL_ERROR) + if(level == LOGLVL_ERROR) (*(logoutput.error))(level, msgstring); #ifdef DEBUG - if(level==LOGLVL_DEBUG) + if(level == LOGLVL_DEBUG) (*(logoutput.debug))(level, msgstring); #endif @@ -132,14 +132,14 @@ static void log_null(int level, char *message) { } static void log_irc(int level, char *message) { - if(level==LOGLVL_ERROR) + if(level == LOGLVL_ERROR) irc_write_all(1, "ERROR :Error: %s", message); - if(level==LOGLVL_WARNING) + if(level == LOGLVL_WARNING) irc_write_all(0, "ERROR :Warning: %s", message); - if(level==LOGLVL_INFO) + if(level == LOGLVL_INFO) irc_write_all(0, "ERROR :Informational: %s", message); #ifdef DEBUG - if(level==LOGLVL_DEBUG) + if(level == LOGLVL_DEBUG) irc_write_all(0, "ERROR :Debug: %s", message); #endif @@ -147,28 +147,28 @@ static void log_irc(int level, char *message) { } static void log_syslog(int level, char *message) { - if(level==LOGLVL_ERROR) + if(level == LOGLVL_ERROR) syslog(LOG_ERR, "%s", message); - if(level==LOGLVL_WARNING) + if(level == LOGLVL_WARNING) syslog(LOG_WARNING, "%s", message); - if(level==LOGLVL_INFO) + if(level == LOGLVL_INFO) syslog(LOG_INFO, "%s", message); #ifdef DEBUG - if(level==LOGLVL_DEBUG) + if(level == LOGLVL_DEBUG) syslog(LOG_DEBUG, "%s", message); #endif return; } static void log_console(int level, char *message) { - if(level==LOGLVL_ERROR) + if(level == LOGLVL_ERROR) fprintf(stderr, "Error: %s\n", message); - if(level==LOGLVL_WARNING) + if(level == LOGLVL_WARNING) fprintf(stderr, "Warning: %s\n", message); - if(level==LOGLVL_INFO) + if(level == LOGLVL_INFO) fprintf(stdout, "Informational: %s\n", message); #ifdef DEBUG - if(level==LOGLVL_DEBUG) + if(level == LOGLVL_DEBUG) fprintf(stdout, "Debug: %s\n", message); #endif return; -- cgit v1.2.3 From 1ea13be2cf335a471f85ea54d610fb91b7d14564 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 18 Jan 2006 19:14:35 +0100 Subject: Fixed a bad mistake in ipc_readline() error handling. --- ipc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ipc.c b/ipc.c index cd30eb52..dfde24bd 100644 --- a/ipc.c +++ b/ipc.c @@ -173,6 +173,8 @@ static char *ipc_readline( int fd ) size = recv( fd, buf, 512, MSG_PEEK ); if( size == 0 || ( size < 0 && !sockerr_again() ) ) return NULL; + else if( size < 0 ) /* && sockerr_again() */ + return( g_strdup( "" ) ); else buf[size] = 0; -- cgit v1.2.3 From c1826c6f72d1fe85e1c5decf5207601dac2c23e7 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 18 Jan 2006 19:25:31 +0100 Subject: BitlBee now tries to empty sendbuffer before closing the connection. --- bitlbee.c | 26 +++++++++++++------------- irc.c | 18 ++++++++++++++++-- irc.h | 4 +++- 3 files changed, 32 insertions(+), 16 deletions(-) diff --git a/bitlbee.c b/bitlbee.c index f4eba866..d8bf12d7 100644 --- a/bitlbee.c +++ b/bitlbee.c @@ -199,7 +199,7 @@ gboolean bitlbee_io_current_client_read( GIOChannel *source, GIOCondition condit if( !irc_process( irc ) ) { log_message( LOGLVL_INFO, "Destroying connection with fd %d.", irc->fd ); - irc_free( irc ); + irc_abort( irc ); return FALSE; } @@ -207,7 +207,7 @@ gboolean bitlbee_io_current_client_read( GIOChannel *source, GIOCondition condit if( irc->readbuffer && ( strlen( irc->readbuffer ) > 1024 ) ) { log_message( LOGLVL_ERROR, "Maximum line length exceeded." ); - irc_free( irc ); + irc_abort( irc ); return FALSE; } @@ -226,25 +226,25 @@ gboolean bitlbee_io_current_client_write( GIOChannel *source, GIOCondition condi size = strlen( irc->sendbuffer ); st = write( irc->fd, irc->sendbuffer, size ); - if( st <= 0 ) + if( st == 0 || ( st < 0 && !sockerr_again() ) ) { - if( sockerr_again() ) - { - return TRUE; - } - else - { - irc_free( irc ); - return FALSE; - } + irc_free( irc ); + return FALSE; + } + else if( st < 0 ) /* && sockerr_again() */ + { + return TRUE; } if( st == size ) { g_free( irc->sendbuffer ); irc->sendbuffer = NULL; - irc->w_watch_source_id = 0; + + if( irc->status == USTATUS_SHUTDOWN ) + irc_free( irc ); + return( FALSE ); } else diff --git a/irc.c b/irc.c index 32dadb7c..9db4becb 100644 --- a/irc.c +++ b/irc.c @@ -150,6 +150,20 @@ irc_t *irc_new( int fd ) return( irc ); } +void irc_abort( irc_t *irc ) +{ + irc->status = USTATUS_SHUTDOWN; + if( irc->sendbuffer ) + { + 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 ); + } + else + { + irc_free( irc ); + } +} + static gboolean irc_free_userhash( gpointer key, gpointer value, gpointer data ) { g_free( key ); @@ -158,7 +172,7 @@ static gboolean irc_free_userhash( gpointer key, gpointer value, gpointer data ) } /* Because we have no garbage collection, this is quite annoying */ -void irc_free(irc_t * irc) +void irc_free( irc_t * irc ) { account_t *account, *accounttmp; user_t *user, *usertmp; @@ -495,7 +509,7 @@ int irc_exec( irc_t *irc, char **cmd ) else if( g_strcasecmp( cmd[0], "QUIT" ) == 0 ) { irc_write( irc, "ERROR :%s%s", cmd[1]?"Quit: ":"", cmd[1]?cmd[1]:"Client Quit" ); - g_io_channel_close( irc->io_channel ); + /* g_io_channel_close( irc->io_channel ); */ return( 0 ); } diff --git a/irc.h b/irc.h index 32b19642..46391cb7 100644 --- a/irc.h +++ b/irc.h @@ -43,7 +43,8 @@ typedef enum USTATUS_OFFLINE, USTATUS_AUTHORIZED, USTATUS_LOGGED_IN, - USTATUS_IDENTIFIED + USTATUS_IDENTIFIED, + USTATUS_SHUTDOWN } irc_status_t; typedef struct channel @@ -103,6 +104,7 @@ typedef struct irc extern GSList *irc_connection_list; irc_t *irc_new( int fd ); +void irc_abort( irc_t *irc ); void irc_free( irc_t *irc ); int irc_exec( irc_t *irc, char **cmd ); -- cgit v1.2.3 From e8f8b187fea053e207224848720514372ede8d4b Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Thu, 19 Jan 2006 14:45:15 +0100 Subject: Fixed read() error handling in Jabber module. --- protocols/jabber/jabber.c | 2 +- protocols/oscar/oscar.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index d4b5bde5..ba652b8a 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -412,7 +412,7 @@ static void gjab_recv(gjconn gjc) XML_Parse(gjc->parser, buf, len, 0); if (jd->die) signoff(GJ_GC(gjc)); - } else if (len < 0 || errno != EAGAIN) { + } else if (len == 0 || (len < 0 && (!sockerr_again() || gjc->ssl))) { STATE_EVT(JCONN_STATE_OFF) } } diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c index b4bfb220..4e552bce 100644 --- a/protocols/oscar/oscar.c +++ b/protocols/oscar/oscar.c @@ -607,6 +607,7 @@ static void damn_you(gpointer data, gint source, GaimInputCondition c) g_free(pos); return; } + /* [WvG] Wheeeee! Who needs error checking anyway? ;-) */ read(pos->fd, m, 16); m[16] = '\0'; gaim_input_remove(pos->inpa); -- cgit v1.2.3 From bd9b00f4fed3560eab98f15cf9923aed13467d5d Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Thu, 19 Jan 2006 18:07:47 +0100 Subject: Fixes for single-process daemon mode, changed value of USTATUS_SHUTDOWN. If this still causes problems, shutting down should be an extra flag instead of a status code. --- ipc.c | 21 +++++++++++++++------ irc.c | 4 +++- irc.h | 4 ++-- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/ipc.c b/ipc.c index 5fda047c..4777113a 100644 --- a/ipc.c +++ b/ipc.c @@ -35,12 +35,15 @@ static int ipc_master_cmd_client( irc_t *data, char **cmd ) { struct bitlbee_child *child = (void*) data; - child->host = g_strdup( cmd[1] ); - child->nick = g_strdup( cmd[2] ); - child->realname = g_strdup( cmd[3] ); + if( child ) + { + child->host = g_strdup( cmd[1] ); + child->nick = g_strdup( cmd[2] ); + child->realname = g_strdup( cmd[3] ); + } ipc_to_children_str( "OPERMSG :Client connecting (PID=%d): %s@%s (%s)\r\n", - child->pid, child->nick, child->host, child->realname ); + child ? child->pid : -1, cmd[2], cmd[1], cmd[3] ); return 1; } @@ -307,7 +310,10 @@ void ipc_to_master_str( char *format, ... ) } else if( global.conf->runmode == RUNMODE_DAEMON ) { - char **cmd; + char **cmd, *s; + + if( ( s = strchr( msg_buf, '\r' ) ) ) + *s = 0; cmd = irc_parse_line( msg_buf ); ipc_command_exec( NULL, cmd, ipc_master_commands ); @@ -360,7 +366,10 @@ void ipc_to_children_str( char *format, ... ) } else if( global.conf->runmode == RUNMODE_DAEMON ) { - char **cmd; + char **cmd, *s; + + if( ( s = strchr( msg_buf, '\r' ) ) ) + *s = 0; cmd = irc_parse_line( msg_buf ); ipc_to_children( cmd ); diff --git a/irc.c b/irc.c index aedbbc83..2f2937cc 100644 --- a/irc.c +++ b/irc.c @@ -187,6 +187,8 @@ void irc_free(irc_t * irc) if( storage_save( irc, TRUE ) != STORAGE_OK ) irc_usermsg( irc, "Error while saving settings!" ); + closesocket( irc->fd ); + if( irc->ping_source_id > 0 ) g_source_remove( irc->ping_source_id ); g_source_remove( irc->r_watch_source_id ); @@ -693,7 +695,7 @@ void irc_login( irc_t *irc ) irc_usermsg( irc, "Welcome to the BitlBee gateway!\n\nIf you've never used BitlBee before, please do read the help information using the \x02help\x02 command. Lots of FAQ's are answered there." ); - if( global.conf->runmode == RUNMODE_FORKDAEMON ) + if( global.conf->runmode == RUNMODE_FORKDAEMON || global.conf->runmode == RUNMODE_DAEMON ) ipc_to_master_str( "CLIENT %s %s :%s\r\n", irc->host, irc->nick, irc->realname ); irc->status = USTATUS_LOGGED_IN; diff --git a/irc.h b/irc.h index 093de7c9..309f79e6 100644 --- a/irc.h +++ b/irc.h @@ -40,11 +40,11 @@ typedef enum { - USTATUS_OFFLINE, + USTATUS_OFFLINE = 0, USTATUS_AUTHORIZED, USTATUS_LOGGED_IN, USTATUS_IDENTIFIED, - USTATUS_SHUTDOWN + USTATUS_SHUTDOWN = -1 } irc_status_t; typedef struct channel -- cgit v1.2.3 From 5424c76c7813f82e2f98546f6a46b73d80181877 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Thu, 19 Jan 2006 18:52:19 +0100 Subject: Rehash command now also works in inetd mode. Other "IPC" commands only make sense in daemon mode. --- ipc.c | 2 +- ipc.h | 6 ++++++ irc_commands.c | 7 ++++++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/ipc.c b/ipc.c index 4777113a..e0bf1319 100644 --- a/ipc.c +++ b/ipc.c @@ -58,7 +58,7 @@ static int ipc_master_cmd_die( irc_t *data, char **cmd ) return 1; } -static int ipc_master_cmd_rehash( irc_t *data, char **cmd ) +int ipc_master_cmd_rehash( irc_t *data, char **cmd ) { runmode_t oldmode; diff --git a/ipc.h b/ipc.h index 56449a7c..308b6e4b 100644 --- a/ipc.h +++ b/ipc.h @@ -26,6 +26,7 @@ #define BITLBEE_CORE #include "bitlbee.h" + struct bitlbee_child { pid_t pid; @@ -37,6 +38,7 @@ struct bitlbee_child char *realname; }; + void ipc_master_read( gpointer data, gint source, GaimInputCondition cond ); void ipc_child_read( gpointer data, gint source, GaimInputCondition cond ); @@ -48,4 +50,8 @@ void ipc_to_master_str( char *format, ... ); void ipc_to_children( char **cmd ); void ipc_to_children_str( char *format, ... ); +/* We need this function in inetd mode, so let's just make it non-static. */ +int ipc_master_cmd_rehash( irc_t *data, char **cmd ); + + extern GSList *child_list; diff --git a/irc_commands.c b/irc_commands.c index 152df767..e31a92e8 100644 --- a/irc_commands.c +++ b/irc_commands.c @@ -579,7 +579,10 @@ static int irc_cmd_completions( irc_t *irc, char **cmd ) static int irc_cmd_rehash( irc_t *irc, char **cmd ) { - ipc_to_master( cmd ); + if( global.conf->runmode == RUNMODE_INETD ) + ipc_master_cmd_rehash( NULL, NULL ); + else + ipc_to_master( cmd ); irc_reply( irc, 382, "%s :Rehashing", CONF_FILE ); @@ -655,6 +658,8 @@ int irc_exec( irc_t *irc, char *cmd[] ) } if( irc_commands[i].flags & IRC_CMD_TO_MASTER ) + /* IPC doesn't make sense in inetd mode, + but the function will catch that. */ ipc_to_master( cmd ); else return irc_commands[i].execute( irc, cmd ); -- cgit v1.2.3 From 2fa825ba7c79a0ab4ed9a534865974e918b49100 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Thu, 19 Jan 2006 23:23:03 +0100 Subject: Removed some very unpleasant check from the OSCAR code. (Caused testing.bitlbee.org to get ... quite busy.) --- protocols/oscar/rxqueue.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/protocols/oscar/rxqueue.c b/protocols/oscar/rxqueue.c index d8adaa73..6e8dd29c 100644 --- a/protocols/oscar/rxqueue.c +++ b/protocols/oscar/rxqueue.c @@ -352,8 +352,15 @@ int aim_get_command(aim_session_t *sess, aim_conn_t *conn) if (conn->fd == -1) return -1; /* its a aim_conn_close()'d connection */ - if (conn->fd < 3) /* can happen when people abuse the interface */ + /* KIDS, THIS IS WHAT HAPPENS IF YOU USE CODE WRITTEN FOR GUIS IN A DAEMON! + + And wouldn't it make sense to return something that prevents this function + from being called again IMMEDIATELY (and making the program suck up all + CPU time)?... + + if (conn->fd < 3) return 0; + */ if (conn->status & AIM_CONN_STATUS_INPROGRESS) return aim_conn_completeconnect(sess, conn); -- cgit v1.2.3 From fc50d482ae5a7836fbf7c72df168b51d1cf714a5 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Fri, 20 Jan 2006 13:21:24 +0100 Subject: irc_abort() does logging (including a reason) now. --- bitlbee.c | 11 +++++------ irc.c | 38 ++++++++++++++++++++++++++++++++++---- irc.h | 2 +- 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/bitlbee.c b/bitlbee.c index d8bf12d7..891bd195 100644 --- a/bitlbee.c +++ b/bitlbee.c @@ -162,14 +162,14 @@ gboolean bitlbee_io_current_client_read( GIOChannel *source, GIOCondition condit if( condition & G_IO_ERR || condition & G_IO_HUP ) { - irc_free( irc ); + irc_abort( irc, 1, "Read error" ); return FALSE; } st = read( irc->fd, line, sizeof( line ) - 1 ); if( st == 0 ) { - irc_free( irc ); + irc_abort( irc, 1, "Connection reset by peer" ); return FALSE; } else if( st < 0 ) @@ -180,7 +180,7 @@ gboolean bitlbee_io_current_client_read( GIOChannel *source, GIOCondition condit } else { - irc_free( irc ); + irc_abort( irc, 1, "Read error: %s", strerror( errno ) ); return FALSE; } } @@ -206,8 +206,7 @@ gboolean bitlbee_io_current_client_read( GIOChannel *source, GIOCondition condit /* Very naughty, go read the RFCs! >:) */ if( irc->readbuffer && ( strlen( irc->readbuffer ) > 1024 ) ) { - log_message( LOGLVL_ERROR, "Maximum line length exceeded." ); - irc_abort( irc ); + irc_abort( irc, 0, "Maximum line length exceeded" ); return FALSE; } @@ -228,7 +227,7 @@ gboolean bitlbee_io_current_client_write( GIOChannel *source, GIOCondition condi if( st == 0 || ( st < 0 && !sockerr_again() ) ) { - irc_free( irc ); + irc_abort( irc, 1, "Write error: %s", strerror( errno ) ); return FALSE; } else if( st < 0 ) /* && sockerr_again() */ diff --git a/irc.c b/irc.c index 1055c3c8..f3e926f7 100644 --- a/irc.c +++ b/irc.c @@ -150,11 +150,42 @@ irc_t *irc_new( int fd ) return( irc ); } -void irc_abort( irc_t *irc ) +void irc_abort( irc_t *irc, int immed, char *format, ... ) { + va_list params; + + if( format != NULL ) + { + char *reason; + + va_start( params, format ); + reason = g_strdup_printf( format, params ); + va_end( params ); + + if( !immed ) + irc_write( irc, "ERROR :Closing link: %s", reason ); + + ipc_to_master_str( "OPERMSG :Client exiting: %s@%s [%s]\r\n", + irc->nick, irc->host, reason" ); + + g_free( reason ); + } + else + { + if( !immed ) + irc_write( irc, "ERROR :Closing link" ); + + ipc_to_master_str( "OPERMSG :Client exiting: %s@%s [%s]\r\n", + irc->nick, irc->host, "No reason given" ); + } + irc->status = USTATUS_SHUTDOWN; - if( irc->sendbuffer ) + if( irc->sendbuffer && !immed ) { + /* We won't read from this socket anymore. Instead, we'll connect a timer + 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 ); } @@ -1622,8 +1653,7 @@ static gboolean irc_userping( gpointer _irc ) if( rv > 0 ) { - irc_write( irc, "ERROR :Closing Link: Ping Timeout: %d seconds", rv ); - irc_free( irc ); + irc_abort( irc, "ERROR :Closing Link: Ping Timeout: %d seconds", rv ); return FALSE; } diff --git a/irc.h b/irc.h index 46391cb7..77628b26 100644 --- a/irc.h +++ b/irc.h @@ -104,7 +104,7 @@ typedef struct irc extern GSList *irc_connection_list; irc_t *irc_new( int fd ); -void irc_abort( irc_t *irc ); +void irc_abort( irc_t *irc, int immed, char *format, ... ); void irc_free( irc_t *irc ); int irc_exec( irc_t *irc, char **cmd ); -- cgit v1.2.3 From f73b9697f9be18e04ec7458634520f9dd2e2432f Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Fri, 20 Jan 2006 16:15:49 +0100 Subject: Renamed commands.c, got rid of return values in all command functions. --- Makefile | 2 +- bitlbee.c | 8 +- bitlbee.h | 4 +- commands.c | 833 -------------------------------------------------------- commands.h | 2 +- ipc.c | 54 ++-- ipc.h | 2 +- irc.c | 43 +-- irc.h | 7 +- irc_commands.c | 147 ++++------ root_commands.c | 800 +++++++++++++++++++++++++++++++++++++++++++++++++++++ user.h | 2 +- 12 files changed, 901 insertions(+), 1003 deletions(-) delete mode 100644 commands.c create mode 100644 root_commands.c diff --git a/Makefile b/Makefile index 26dd3d0f..295fe69e 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ -include Makefile.settings # Program variables -objects = account.o bitlbee.o commands.o conf.o crypting.o help.o ini.o ipc.o irc.o irc_commands.o log.o nick.o query.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 unix.o url.o user.o util.o subdirs = protocols # Expansion of variables diff --git a/bitlbee.c b/bitlbee.c index 218caf01..9a4688d8 100644 --- a/bitlbee.c +++ b/bitlbee.c @@ -166,10 +166,12 @@ gboolean bitlbee_io_current_client_read( GIOChannel *source, GIOCondition condit strcpy( ( irc->readbuffer + strlen( irc->readbuffer ) ), line ); } - if( !irc_process( irc ) ) + irc_process( irc ); + + /* 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_INFO, "Destroying connection with fd %d.", irc->fd ); - irc_abort( irc ); + log_message( LOGLVL_WARNING, "Abnormal termination of connection with fd %d.", irc->fd ); return FALSE; } diff --git a/bitlbee.h b/bitlbee.h index 0bd7c90e..e459f07d 100644 --- a/bitlbee.h +++ b/bitlbee.h @@ -128,8 +128,8 @@ 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 ); -int root_command_string( irc_t *irc, user_t *u, char *command, int flags ); -int root_command( irc_t *irc, char *command[] ); +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 ); double gettime( void ); G_MODULE_EXPORT void http_encode( char *s ); diff --git a/commands.c b/commands.c deleted file mode 100644 index fbe378f6..00000000 --- a/commands.c +++ /dev/null @@ -1,833 +0,0 @@ - /********************************************************************\ - * BitlBee -- An IRC to other IM-networks gateway * - * * - * Copyright 2002-2004 Wilmer van der Gaast and others * - \********************************************************************/ - -/* User manager (root) commands */ - -/* - 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 "commands.h" -#include "crypting.h" -#include "bitlbee.h" -#include "help.h" - -#include - -int root_command_string( irc_t *irc, user_t *u, char *command, int flags ) -{ - char *cmd[IRC_MAX_ARGS]; - char *s; - int k; - char q = 0; - - memset( cmd, 0, sizeof( cmd ) ); - cmd[0] = command; - k = 1; - for( s = command; *s && k < ( IRC_MAX_ARGS - 1 ); s ++ ) - if( *s == ' ' && !q ) - { - *s = 0; - while( *++s == ' ' ); - if( *s == '"' || *s == '\'' ) - { - q = *s; - s ++; - } - if( *s ) - { - cmd[k++] = s; - s --; - } - } - else if( *s == q ) - { - q = *s = 0; - } - cmd[k] = NULL; - - return( root_command( irc, cmd ) ); -} - -int root_command( irc_t *irc, char *cmd[] ) -{ - int i; - - if( !cmd[0] ) - return( 0 ); - - for( i = 0; commands[i].command; i++ ) - if( g_strcasecmp( commands[i].command, cmd[0] ) == 0 ) - { - if( !cmd[commands[i].required_parameters] ) - { - irc_usermsg( irc, "Not enough parameters given (need %d)", commands[i].required_parameters ); - return( 0 ); - } - commands[i].execute( irc, cmd ); - return( 1 ); - } - - irc_usermsg( irc, "Unknown command: %s. Please use \x02help commands\x02 to get a list of available commands.", cmd[0] ); - - return( 1 ); -} - -static int cmd_help( irc_t *irc, char **cmd ) -{ - char param[80]; - int i; - char *s; - - memset( param, 0, sizeof(param) ); - for ( i = 1; (cmd[i] != NULL && ( strlen(param) < (sizeof(param)-1) ) ); i++ ) { - if ( i != 1 ) // prepend space except for the first parameter - strcat(param, " "); - strncat( param, cmd[i], sizeof(param) - strlen(param) - 1 ); - } - - s = help_get( &(global.help), param ); - if( !s ) s = help_get( &(global.help), "" ); - - if( s ) - { - irc_usermsg( irc, "%s", s ); - g_free( s ); - return( 1 ); - } - else - { - irc_usermsg( irc, "Error opening helpfile." ); - return( 0 ); - } -} - -static int cmd_identify( irc_t *irc, char **cmd ) -{ - storage_status_t status = storage_load( irc->nick, cmd[1], irc ); - - switch (status) { - case STORAGE_INVALID_PASSWORD: - irc_usermsg( irc, "Incorrect password" ); - break; - case STORAGE_NO_SUCH_USER: - irc_usermsg( irc, "The nick is (probably) not registered" ); - break; - case STORAGE_OK: - irc_usermsg( irc, "Password accepted" ); - irc_umode_set( irc, "+R", 1 ); - break; - default: - irc_usermsg( irc, "Something very weird happened" ); - break; - } - - return( 0 ); -} - -static int cmd_register( irc_t *irc, char **cmd ) -{ - if( global.conf->authmode == AUTHMODE_REGISTERED ) - { - irc_usermsg( irc, "This server does not allow registering new accounts" ); - return( 0 ); - } - - irc_setpass( irc, cmd[1] ); - switch( storage_save( irc, FALSE )) { - case STORAGE_ALREADY_EXISTS: - irc_usermsg( irc, "Nick is already registered" ); - break; - - case STORAGE_OK: - irc->status = USTATUS_IDENTIFIED; - irc_umode_set( irc, "+R", 1 ); - break; - - default: - irc_usermsg( irc, "Error registering" ); - break; - } - - return( 0 ); -} - -static int cmd_drop( irc_t *irc, char **cmd ) -{ - storage_status_t status; - - status = storage_remove (irc->nick, cmd[1]); - switch (status) { - case STORAGE_NO_SUCH_USER: - irc_usermsg( irc, "That account does not exist" ); - return( 0 ); - case STORAGE_INVALID_PASSWORD: - irc_usermsg( irc, "Password invalid" ); - return( 0 ); - case STORAGE_OK: - irc_setpass( irc, NULL ); - irc->status = USTATUS_LOGGED_IN; - irc_umode_set( irc, "-R", 1 ); - irc_usermsg( irc, "Account `%s' removed", irc->nick ); - return( 0 ); - default: - irc_usermsg( irc, "Error: '%d'", status ); - return( 0 ); - } -} - -static int cmd_account( irc_t *irc, char **cmd ) -{ - account_t *a; - - if( global.conf->authmode == AUTHMODE_REGISTERED && irc->status < USTATUS_IDENTIFIED ) - { - irc_usermsg( irc, "This server only accepts registered users" ); - return( 0 ); - } - - if( g_strcasecmp( cmd[1], "add" ) == 0 ) - { - struct prpl *prpl; - - if( cmd[2] == NULL || cmd[3] == NULL || cmd[4] == NULL ) - { - irc_usermsg( irc, "Not enough parameters" ); - return( 0 ); - } - - prpl = find_protocol(cmd[2]); - - if( prpl == NULL ) - { - irc_usermsg( irc, "Unknown protocol" ); - return( 0 ); - } - - a = account_add( irc, prpl, cmd[3], cmd[4] ); - - if( cmd[5] ) - a->server = g_strdup( cmd[5] ); - - irc_usermsg( irc, "Account successfully added" ); - } - else if( g_strcasecmp( cmd[1], "del" ) == 0 ) - { - if( !cmd[2] ) - { - irc_usermsg( irc, "Not enough parameters given (need %d)", 2 ); - } - else if( !( a = account_get( irc, cmd[2] ) ) ) - { - irc_usermsg( irc, "Invalid account" ); - } - else if( a->gc ) - { - irc_usermsg( irc, "Account is still logged in, can't delete" ); - } - else - { - account_del( irc, a ); - irc_usermsg( irc, "Account deleted" ); - } - } - else if( g_strcasecmp( cmd[1], "list" ) == 0 ) - { - int i = 0; - - for( a = irc->accounts; a; a = a->next ) - { - char *con; - - if( a->gc && ( a->gc->flags & OPT_LOGGED_IN ) ) - con = " (connected)"; - else if( a->gc ) - con = " (connecting)"; - else if( a->reconnect ) - con = " (awaiting reconnect)"; - else - con = ""; - - irc_usermsg( irc, "%2d. %s, %s%s", i, a->prpl->name, a->user, con ); - - i ++; - } - irc_usermsg( irc, "End of account list" ); - } - else if( g_strcasecmp( cmd[1], "on" ) == 0 ) - { - if( cmd[2] ) - { - if( ( a = account_get( irc, cmd[2] ) ) ) - { - if( a->gc ) - { - irc_usermsg( irc, "Account already online" ); - return( 0 ); - } - else - { - account_on( irc, a ); - } - } - else - { - irc_usermsg( irc, "Invalid account" ); - return( 0 ); - } - } - else - { - if ( irc->accounts ) { - irc_usermsg( irc, "Trying to get all accounts connected..." ); - - for( a = irc->accounts; a; a = a->next ) - if( !a->gc ) - account_on( irc, a ); - } - else - { - irc_usermsg( irc, "No accounts known. Use 'account add' to add one." ); - } - } - } - else if( g_strcasecmp( cmd[1], "off" ) == 0 ) - { - if( !cmd[2] ) - { - irc_usermsg( irc, "Deactivating all active (re)connections..." ); - - for( a = irc->accounts; a; a = a->next ) - { - if( a->gc ) - account_off( irc, a ); - else if( a->reconnect ) - cancel_auto_reconnect( a ); - } - } - else if( ( a = account_get( irc, cmd[2] ) ) ) - { - if( a->gc ) - { - account_off( irc, a ); - } - else if( a->reconnect ) - { - cancel_auto_reconnect( a ); - irc_usermsg( irc, "Reconnect cancelled" ); - } - else - { - irc_usermsg( irc, "Account already offline" ); - return( 0 ); - } - } - else - { - irc_usermsg( irc, "Invalid account" ); - return( 0 ); - } - } - else - { - irc_usermsg( irc, "Unknown command: account %s. Please use \x02help commands\x02 to get a list of available commands.", cmd[1] ); - } - - return( 1 ); -} - -static int cmd_add( irc_t *irc, char **cmd ) -{ - account_t *a; - - if( !( a = account_get( irc, cmd[1] ) ) ) - { - irc_usermsg( irc, "Invalid account" ); - return( 1 ); - } - else if( !( a->gc && ( a->gc->flags & OPT_LOGGED_IN ) ) ) - { - irc_usermsg( irc, "That account is not on-line" ); - return( 1 ); - } - - if( cmd[3] ) - { - if( !nick_ok( cmd[3] ) ) - { - irc_usermsg( irc, "The requested nick `%s' is invalid", cmd[3] ); - return( 0 ); - } - else if( user_find( irc, cmd[3] ) ) - { - irc_usermsg( irc, "The requested nick `%s' already exists", cmd[3] ); - return( 0 ); - } - else - { - nick_set( irc, cmd[2], a->gc->prpl, cmd[3] ); - } - } - a->gc->prpl->add_buddy( a->gc, cmd[2] ); - add_buddy( a->gc, NULL, cmd[2], cmd[2] ); - - irc_usermsg( irc, "User `%s' added to your contact list as `%s'", cmd[2], user_findhandle( a->gc, cmd[2] )->nick ); - - return( 0 ); -} - -static int cmd_info( irc_t *irc, char **cmd ) -{ - struct gaim_connection *gc; - account_t *a; - - if( !cmd[2] ) - { - user_t *u = user_find( irc, cmd[1] ); - if( !u || !u->gc ) - { - irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] ); - return( 1 ); - } - gc = u->gc; - cmd[2] = u->handle; - } - else if( !( a = account_get( irc, cmd[1] ) ) ) - { - irc_usermsg( irc, "Invalid account" ); - return( 1 ); - } - else if( !( ( gc = a->gc ) && ( a->gc->flags & OPT_LOGGED_IN ) ) ) - { - irc_usermsg( irc, "That account is not on-line" ); - return( 1 ); - } - - if( !gc->prpl->get_info ) - { - irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] ); - return( 1 ); - } - gc->prpl->get_info( gc, cmd[2] ); - - return( 0 ); -} - -static int cmd_rename( irc_t *irc, char **cmd ) -{ - user_t *u; - - if( g_strcasecmp( cmd[1], irc->nick ) == 0 ) - { - irc_usermsg( irc, "Nick `%s' can't be changed", cmd[1] ); - return( 1 ); - } - if( user_find( irc, cmd[2] ) && ( nick_cmp( cmd[1], cmd[2] ) != 0 ) ) - { - irc_usermsg( irc, "Nick `%s' already exists", cmd[2] ); - return( 1 ); - } - if( !nick_ok( cmd[2] ) ) - { - irc_usermsg( irc, "Nick `%s' is invalid", cmd[2] ); - return( 1 ); - } - if( !( u = user_find( irc, cmd[1] ) ) ) - { - irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] ); - return( 1 ); - } - user_rename( irc, cmd[1], cmd[2] ); - irc_write( irc, ":%s!%s@%s NICK %s", cmd[1], u->user, u->host, cmd[2] ); - if( g_strcasecmp( cmd[1], irc->mynick ) == 0 ) - { - g_free( irc->mynick ); - irc->mynick = g_strdup( cmd[2] ); - } - else if( u->send_handler == buddy_send_handler ) - { - nick_set( irc, u->handle, u->gc->prpl, cmd[2] ); - } - - irc_usermsg( irc, "Nick successfully changed" ); - - return( 0 ); -} - -static int cmd_remove( irc_t *irc, char **cmd ) -{ - user_t *u; - char *s; - - if( !( u = user_find( irc, cmd[1] ) ) || !u->gc ) - { - irc_usermsg( irc, "Buddy `%s' not found", cmd[1] ); - return( 1 ); - } - s = g_strdup( u->handle ); - - u->gc->prpl->remove_buddy( u->gc, u->handle, NULL ); - user_del( irc, cmd[1] ); - nick_del( irc, cmd[1] ); - - irc_usermsg( irc, "Buddy `%s' (nick %s) removed from contact list", s, cmd[1] ); - g_free( s ); - - return( 0 ); -} - -static int cmd_block( irc_t *irc, char **cmd ) -{ - struct gaim_connection *gc; - account_t *a; - - if( !cmd[2] ) - { - user_t *u = user_find( irc, cmd[1] ); - if( !u || !u->gc ) - { - irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] ); - return( 1 ); - } - gc = u->gc; - cmd[2] = u->handle; - } - else if( !( a = account_get( irc, cmd[1] ) ) ) - { - irc_usermsg( irc, "Invalid account" ); - return( 1 ); - } - else if( !( ( gc = a->gc ) && ( a->gc->flags & OPT_LOGGED_IN ) ) ) - { - irc_usermsg( irc, "That account is not on-line" ); - return( 1 ); - } - - if( !gc->prpl->add_deny || !gc->prpl->rem_permit ) - { - irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] ); - } - else - { - gc->prpl->rem_permit( gc, cmd[2] ); - gc->prpl->add_deny( gc, cmd[2] ); - irc_usermsg( irc, "Buddy `%s' moved from your permit- to your deny-list", cmd[2] ); - } - - return( 0 ); -} - -static int cmd_allow( irc_t *irc, char **cmd ) -{ - struct gaim_connection *gc; - account_t *a; - - if( !cmd[2] ) - { - user_t *u = user_find( irc, cmd[1] ); - if( !u || !u->gc ) - { - irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] ); - return( 1 ); - } - gc = u->gc; - cmd[2] = u->handle; - } - else if( !( a = account_get( irc, cmd[1] ) ) ) - { - irc_usermsg( irc, "Invalid account" ); - return( 1 ); - } - else if( !( ( gc = a->gc ) && ( a->gc->flags & OPT_LOGGED_IN ) ) ) - { - irc_usermsg( irc, "That account is not on-line" ); - return( 1 ); - } - - if( !gc->prpl->rem_deny || !gc->prpl->add_permit ) - { - irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] ); - } - else - { - gc->prpl->rem_deny( gc, cmd[2] ); - gc->prpl->add_permit( gc, cmd[2] ); - - irc_usermsg( irc, "Buddy `%s' moved from your deny- to your permit-list", cmd[2] ); - } - - return( 0 ); -} - -static int cmd_yesno( irc_t *irc, char **cmd ) -{ - query_t *q = NULL; - int numq = 0; - - if( irc->queries == NULL ) - { - irc_usermsg( irc, "Did I ask you something?" ); - return( 0 ); - } - - /* If there's an argument, the user seems to want to answer another question than the - first/last (depending on the query_order setting) one. */ - if( cmd[1] ) - { - if( sscanf( cmd[1], "%d", &numq ) != 1 ) - { - irc_usermsg( irc, "Invalid query number" ); - return( 0 ); - } - - for( q = irc->queries; q; q = q->next, numq -- ) - if( numq == 0 ) - break; - - if( !q ) - { - irc_usermsg( irc, "Uhm, I never asked you something like that..." ); - return( 0 ); - } - } - - if( g_strcasecmp( cmd[0], "yes" ) == 0 ) - query_answer( irc, q, 1 ); - else if( g_strcasecmp( cmd[0], "no" ) == 0 ) - query_answer( irc, q, 0 ); - - return( 1 ); -} - -static int cmd_set( irc_t *irc, char **cmd ) -{ - if( cmd[1] && cmd[2] ) - { - set_setstr( irc, cmd[1], cmd[2] ); - } - if( cmd[1] ) /* else 'forgotten' on purpose.. Must show new value after changing */ - { - char *s = set_getstr( irc, cmd[1] ); - if( s ) - irc_usermsg( irc, "%s = `%s'", cmd[1], s ); - } - else - { - set_t *s = irc->set; - while( s ) - { - if( s->value || s->def ) - irc_usermsg( irc, "%s = `%s'", s->key, s->value?s->value:s->def ); - s = s->next; - } - } - - return( 0 ); -} - -static int cmd_save( irc_t *irc, char **cmd ) -{ - if( storage_save( irc, TRUE ) == STORAGE_OK ) - irc_usermsg( irc, "Configuration saved" ); - else - irc_usermsg( irc, "Configuration could not be saved!" ); - - return( 0 ); -} - -static int cmd_blist( irc_t *irc, char **cmd ) -{ - int online = 0, away = 0, offline = 0; - user_t *u; - char s[64]; - int n_online = 0, n_away = 0, n_offline = 0; - - if( cmd[1] && g_strcasecmp( cmd[1], "all" ) == 0 ) - online = offline = away = 1; - else if( cmd[1] && g_strcasecmp( cmd[1], "offline" ) == 0 ) - offline = 1; - else if( cmd[1] && g_strcasecmp( cmd[1], "away" ) == 0 ) - away = 1; - else if( cmd[1] && g_strcasecmp( cmd[1], "online" ) == 0 ) - online = 1; - else - online = away = 1; - - irc_usermsg( irc, "%-16.16s %-40.40s %s", "Nick", "User/Host/Network", "Status" ); - - if( online == 1 ) for( u = irc->users; u; u = u->next ) if( u->gc && u->online && !u->away ) - { - g_snprintf( s, 63, "%s@%s (%s)", u->user, u->host, u->gc->user->prpl->name ); - irc_usermsg( irc, "%-16.16s %-40.40s %s", u->nick, s, "Online" ); - n_online ++; - } - - if( away == 1 ) for( u = irc->users; u; u = u->next ) if( u->gc && u->online && u->away ) - { - g_snprintf( s, 63, "%s@%s (%s)", u->user, u->host, u->gc->user->prpl->name ); - irc_usermsg( irc, "%-16.16s %-40.40s %s", u->nick, s, u->away ); - n_away ++; - } - - if( offline == 1 ) for( u = irc->users; u; u = u->next ) if( u->gc && !u->online ) - { - g_snprintf( s, 63, "%s@%s (%s)", u->user, u->host, u->gc->user->prpl->name ); - irc_usermsg( irc, "%-16.16s %-40.40s %s", u->nick, s, "Offline" ); - n_offline ++; - } - - irc_usermsg( irc, "%d buddies (%d available, %d away, %d offline)", n_online + n_away + n_offline, n_online, n_away, n_offline ); - - return( 0 ); -} - -static int cmd_nick( irc_t *irc, char **cmd ) -{ - account_t *a; - - if( !cmd[1] || !( a = account_get( irc, cmd[1] ) ) ) - { - irc_usermsg( irc, "Invalid account"); - } - else if( !( a->gc && ( a->gc->flags & OPT_LOGGED_IN ) ) ) - { - irc_usermsg( irc, "That account is not on-line" ); - } - else if ( !cmd[2] ) - { - irc_usermsg( irc, "Your name is `%s'" , a->gc->displayname ? a->gc->displayname : "NULL" ); - } - else if ( !a->gc->prpl->set_info ) - { - irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] ); - } - else - { - char utf8[1024]; - - irc_usermsg( irc, "Setting your name to `%s'", cmd[2] ); - - if( g_strncasecmp( set_getstr( irc, "charset" ), "none", 4 ) != 0 && - do_iconv( set_getstr( irc, "charset" ), "UTF-8", cmd[2], utf8, 0, 1024 ) != -1 ) - a->gc->prpl->set_info( a->gc, utf8 ); - else - a->gc->prpl->set_info( a->gc, cmd[2] ); - } - - return( 1 ); -} - -static int cmd_qlist( irc_t *irc, char **cmd ) -{ - query_t *q = irc->queries; - int num; - - if( !q ) - { - irc_usermsg( irc, "There are no pending questions." ); - return( 0 ); - } - - irc_usermsg( irc, "Pending queries:" ); - - for( num = 0; q; q = q->next, num ++ ) - if( q->gc ) /* Not necessary yet, but it might come later */ - irc_usermsg( irc, "%d, %s(%s): %s", num, q->gc->prpl->name, q->gc->username, q->question ); - else - irc_usermsg( irc, "%d, BitlBee: %s", num, q->question ); - - return( 0 ); -} - -static int cmd_import_buddies( irc_t *irc, char **cmd ) -{ - struct gaim_connection *gc; - account_t *a; - nick_t *n; - - if( !( a = account_get( irc, cmd[1] ) ) ) - { - irc_usermsg( irc, "Invalid account" ); - return( 0 ); - } - else if( !( ( gc = a->gc ) && ( a->gc->flags & OPT_LOGGED_IN ) ) ) - { - irc_usermsg( irc, "That account is not on-line" ); - return( 0 ); - } - - if( cmd[2] ) - { - if( g_strcasecmp( cmd[2], "clear" ) == 0 ) - { - user_t *u; - - for( u = irc->users; u; u = u->next ) - if( u->gc == gc ) - { - u->gc->prpl->remove_buddy( u->gc, u->handle, NULL ); - user_del( irc, u->nick ); - } - - irc_usermsg( irc, "Old buddy list cleared." ); - } - else - { - irc_usermsg( irc, "Invalid argument: %s", cmd[2] ); - return( 0 ); - } - } - - for( n = gc->irc->nicks; n; n = n->next ) - { - if( n->proto == gc->prpl && !user_findhandle( gc, n->handle ) ) - { - gc->prpl->add_buddy( gc, n->handle ); - add_buddy( gc, NULL, n->handle, NULL ); - } - } - - irc_usermsg( irc, "Sent all add requests. Please wait for a while, the server needs some time to handle all the adds." ); - - return( 0 ); -} - -const command_t commands[] = { - { "help", 0, cmd_help, 0 }, - { "identify", 1, cmd_identify, 0 }, - { "register", 1, cmd_register, 0 }, - { "drop", 1, cmd_drop, 0 }, - { "account", 1, cmd_account, 0 }, - { "add", 2, cmd_add, 0 }, - { "info", 1, cmd_info, 0 }, - { "rename", 2, cmd_rename, 0 }, - { "remove", 1, cmd_remove, 0 }, - { "block", 1, cmd_block, 0 }, - { "allow", 1, cmd_allow, 0 }, - { "save", 0, cmd_save, 0 }, - { "set", 0, cmd_set, 0 }, - { "yes", 0, cmd_yesno, 0 }, - { "no", 0, cmd_yesno, 0 }, - { "blist", 0, cmd_blist, 0 }, - { "nick", 1, cmd_nick, 0 }, - { "import_buddies", 1, cmd_import_buddies, 0 }, - { "qlist", 0, cmd_qlist, 0 }, - { NULL } -}; diff --git a/commands.h b/commands.h index a881499a..38572360 100644 --- a/commands.h +++ b/commands.h @@ -32,7 +32,7 @@ typedef struct command { char *command; int required_parameters; - int (*execute)(irc_t *, char **args); + void (*execute)(irc_t *, char **args); int flags; } command_t; diff --git a/ipc.c b/ipc.c index e0bf1319..8d44e4eb 100644 --- a/ipc.c +++ b/ipc.c @@ -31,7 +31,7 @@ GSList *child_list = NULL; -static int ipc_master_cmd_client( irc_t *data, char **cmd ) +static void ipc_master_cmd_client( irc_t *data, char **cmd ) { struct bitlbee_child *child = (void*) data; @@ -44,21 +44,17 @@ static int ipc_master_cmd_client( irc_t *data, char **cmd ) ipc_to_children_str( "OPERMSG :Client connecting (PID=%d): %s@%s (%s)\r\n", child ? child->pid : -1, cmd[2], cmd[1], cmd[3] ); - - return 1; } -static int ipc_master_cmd_die( irc_t *data, char **cmd ) +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 ); - - return 1; } -int ipc_master_cmd_rehash( irc_t *data, char **cmd ) +void ipc_master_cmd_rehash( irc_t *data, char **cmd ) { runmode_t oldmode; @@ -75,8 +71,6 @@ int ipc_master_cmd_rehash( irc_t *data, char **cmd ) if( global.conf->runmode == RUNMODE_FORKDAEMON ) ipc_to_children( cmd ); - - return 1; } static const command_t ipc_master_commands[] = { @@ -91,50 +85,39 @@ static const command_t ipc_master_commands[] = { }; -static int ipc_child_cmd_die( irc_t *irc, char **cmd ) +static void ipc_child_cmd_die( irc_t *irc, char **cmd ) { - if( irc->status >= USTATUS_LOGGED_IN ) - irc_write( irc, "ERROR :Operator requested server shutdown, bye bye!" ); - - irc_abort( irc ); - - return 1; + irc_abort( irc, 1, "Shutdown requested by operator" ); } -static int ipc_child_cmd_wallops( irc_t *irc, char **cmd ) +static void ipc_child_cmd_wallops( irc_t *irc, char **cmd ) { if( irc->status < USTATUS_LOGGED_IN ) - return 1; + return; if( strchr( irc->umode, 'w' ) ) irc_write( irc, ":%s WALLOPS :%s", irc->myhost, cmd[1] ); - - return 1; } -static int ipc_child_cmd_lilo( irc_t *irc, char **cmd ) +static void ipc_child_cmd_lilo( irc_t *irc, char **cmd ) { if( irc->status < USTATUS_LOGGED_IN ) - return 1; + return; if( strchr( irc->umode, 's' ) ) irc_write( irc, ":%s NOTICE %s :%s", irc->myhost, irc->nick, cmd[1] ); - - return 1; } -static int ipc_child_cmd_opermsg( irc_t *irc, char **cmd ) +static void ipc_child_cmd_opermsg( irc_t *irc, char **cmd ) { if( irc->status < USTATUS_LOGGED_IN ) - return 1; + return; if( strchr( irc->umode, 'o' ) ) irc_write( irc, ":%s NOTICE %s :*** OperMsg *** %s", irc->myhost, irc->nick, cmd[1] ); - - return 1; } -static int ipc_child_cmd_rehash( irc_t *irc, char **cmd ) +static void ipc_child_cmd_rehash( irc_t *irc, char **cmd ) { runmode_t oldmode; @@ -144,23 +127,18 @@ static int ipc_child_cmd_rehash( irc_t *irc, char **cmd ) global.conf = conf_load( 0, NULL ); global.conf->runmode = oldmode; - - return 1; } -static int ipc_child_cmd_kill( irc_t *irc, char **cmd ) +static void ipc_child_cmd_kill( irc_t *irc, char **cmd ) { if( irc->status < USTATUS_LOGGED_IN ) - return 1; + return; if( nick_cmp( cmd[1], irc->nick ) != 0 ) - return 1; /* It's not for us. */ + return; /* It's not for us. */ irc_write( irc, ":%s!%s@%s KILL %s :%s", irc->mynick, irc->mynick, irc->myhost, irc->nick, cmd[2] ); - irc_abort( irc ); - /* g_io_channel_close( irc->io_channel ); */ - - return 0; + irc_abort( irc, 0, "Killed by operator: %s", cmd[2] ); } static const command_t ipc_child_commands[] = { diff --git a/ipc.h b/ipc.h index 308b6e4b..b69a6ae5 100644 --- a/ipc.h +++ b/ipc.h @@ -51,7 +51,7 @@ void ipc_to_children( char **cmd ); void ipc_to_children_str( char *format, ... ); /* We need this function in inetd mode, so let's just make it non-static. */ -int ipc_master_cmd_rehash( irc_t *data, char **cmd ); +void ipc_master_cmd_rehash( irc_t *data, char **cmd ); extern GSList *child_list; diff --git a/irc.c b/irc.c index 5c1b0e69..93cbc293 100644 --- a/irc.c +++ b/irc.c @@ -151,23 +151,25 @@ irc_t *irc_new( int fd ) return( irc ); } +/* immed=1 makes this function pretty much equal to irc_free(), except that + this one will "log". In case the connection is already broken and we + shouldn't try to write to it. */ void irc_abort( irc_t *irc, int immed, char *format, ... ) { - va_list params; - if( format != NULL ) { + va_list params; char *reason; va_start( params, format ); - reason = g_strdup_printf( format, params ); + reason = g_strdup_vprintf( format, params ); va_end( params ); if( !immed ) irc_write( irc, "ERROR :Closing link: %s", reason ); ipc_to_master_str( "OPERMSG :Client exiting: %s@%s [%s]\r\n", - irc->nick, irc->host, reason" ); + irc->nick ? irc->nick : "(NONE)", irc->host, reason ); g_free( reason ); } @@ -177,7 +179,7 @@ void irc_abort( irc_t *irc, int immed, char *format, ... ) irc_write( irc, "ERROR :Closing link" ); ipc_to_master_str( "OPERMSG :Client exiting: %s@%s [%s]\r\n", - irc->nick, irc->host, "No reason given" ); + irc->nick ? irc->nick : "(NONE)", irc->host, "No reason given" ); } irc->status = USTATUS_SHUTDOWN; @@ -338,7 +340,7 @@ void irc_setpass (irc_t *irc, const char *pass) } } -int irc_process( irc_t *irc ) +void irc_process( irc_t *irc ) { char **lines, *temp, **cmd; int i; @@ -360,14 +362,16 @@ int irc_process( irc_t *irc ) if( ( cmd = irc_parse_line( lines[i] ) ) == NULL ) continue; - if( !irc_exec( irc, cmd ) ) + irc_exec( irc, cmd ); + + g_free( cmd ); + + /* Shouldn't really happen, but just in case... */ + if( !g_slist_find( irc_connection_list, irc ) ) { - g_free( cmd ); g_free( lines ); - return 0; + return; } - - g_free( cmd ); } if( lines[i] != NULL ) @@ -378,8 +382,6 @@ int irc_process( irc_t *irc ) g_free( lines ); } - - return 1; } char **irc_tokenize( char *buffer ) @@ -971,7 +973,10 @@ int irc_send( irc_t *irc, char *nick, char *s, int flags ) } if( u->send_handler ) - return( u->send_handler( irc, u, s, flags ) ); + { + u->send_handler( irc, u, s, flags ); + return 1; + } } else if( c && c->gc && c->gc->prpl ) { @@ -997,9 +1002,9 @@ gboolean buddy_send_handler_delayed( gpointer data ) return( FALSE ); } -int buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags ) +void buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags ) { - if( !u || !u->gc ) return( 0 ); + if( !u || !u->gc ) return; if( set_getint( irc, "buddy_sendbuffer" ) && set_getint( irc, "buddy_sendbuffer_delay" ) > 0 ) { @@ -1035,12 +1040,10 @@ int buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags ) if( u->sendbuf_timer > 0 ) g_source_remove( u->sendbuf_timer ); u->sendbuf_timer = g_timeout_add( delay, buddy_send_handler_delayed, u ); - - return( 1 ); } else { - return( serv_send_im( irc, u, msg, flags ) ); + serv_send_im( irc, u, msg, flags ); } } @@ -1145,7 +1148,7 @@ static gboolean irc_userping( gpointer _irc ) if( rv > 0 ) { - irc_abort( irc, "ERROR :Closing Link: Ping Timeout: %d seconds", rv ); + irc_abort( irc, 0, "Ping Timeout: %d seconds", rv ); return FALSE; } diff --git a/irc.h b/irc.h index 1cf39504..5c53273a 100644 --- a/irc.h +++ b/irc.h @@ -107,8 +107,8 @@ irc_t *irc_new( int fd ); void irc_abort( irc_t *irc, int immed, char *format, ... ); void irc_free( irc_t *irc ); -int irc_exec( irc_t *irc, char **cmd ); -int irc_process( irc_t *irc ); +void irc_exec( irc_t *irc, char **cmd ); +void irc_process( irc_t *irc ); char **irc_parse_line( char *line ); char *irc_build_line( char **cmd ); @@ -133,7 +133,6 @@ void irc_kick( irc_t *irc, user_t *u, char *channel, user_t *kicker ); void irc_kill( irc_t *irc, user_t *u ); void irc_invite( irc_t *irc, char *nick, char *channel ); void irc_whois( irc_t *irc, char *nick ); -int irc_away( irc_t *irc, char *away ); void irc_setpass( irc_t *irc, const char *pass ); /* USE WITH CAUTION! */ int irc_send( irc_t *irc, char *nick, char *s, int flags ); @@ -141,6 +140,6 @@ int irc_privmsg( irc_t *irc, user_t *u, char *type, char *to, char *prefix, char int irc_msgfrom( irc_t *irc, char *nick, char *msg ); int irc_noticefrom( irc_t *irc, char *nick, char *msg ); -int buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags ); +void buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags ); #endif diff --git a/irc_commands.c b/irc_commands.c index e31a92e8..e4dc4f3e 100644 --- a/irc_commands.c +++ b/irc_commands.c @@ -27,7 +27,7 @@ #include "bitlbee.h" #include "ipc.h" -static int irc_cmd_pass( irc_t *irc, char **cmd ) +static void irc_cmd_pass( irc_t *irc, char **cmd ) { if( global.conf->auth_pass && strcmp( cmd[1], global.conf->auth_pass ) == 0 ) { @@ -38,21 +38,17 @@ static int irc_cmd_pass( irc_t *irc, char **cmd ) { irc_reply( irc, 464, ":Incorrect password" ); } - - return( 1 ); } -static int irc_cmd_user( irc_t *irc, char **cmd ) +static void irc_cmd_user( irc_t *irc, char **cmd ) { irc->user = g_strdup( cmd[1] ); irc->realname = g_strdup( cmd[4] ); irc_check_login( irc ); - - return( 1 ); } -static int irc_cmd_nick( irc_t *irc, char **cmd ) +static void irc_cmd_nick( irc_t *irc, char **cmd ) { if( irc->nick ) { @@ -74,26 +70,22 @@ static int irc_cmd_nick( irc_t *irc, char **cmd ) irc_check_login( irc ); } - - return( 1 ); } -static int irc_cmd_quit( irc_t *irc, char **cmd ) +static void irc_cmd_quit( irc_t *irc, char **cmd ) { - irc_write( irc, "ERROR :%s%s", cmd[1]?"Quit: ":"", cmd[1]?cmd[1]:"Client Quit" ); - /* g_io_channel_close( irc->io_channel ); */ - - return( 0 ); + if( cmd[1] && *cmd[1] ) + irc_abort( irc, 0, "Quit: %s", cmd[1] ); + else + irc_abort( irc, 0, "Leaving..." ); } -static int irc_cmd_ping( irc_t *irc, char **cmd ) +static void irc_cmd_ping( irc_t *irc, char **cmd ) { irc_write( irc, ":%s PONG %s :%s", irc->myhost, irc->myhost, cmd[1]?cmd[1]:irc->myhost ); - - return( 1 ); } -static int irc_cmd_oper( irc_t *irc, char **cmd ) +static void irc_cmd_oper( irc_t *irc, char **cmd ) { if( global.conf->oper_pass && strcmp( cmd[2], global.conf->oper_pass ) == 0 ) { @@ -104,11 +96,9 @@ static int irc_cmd_oper( irc_t *irc, char **cmd ) { irc_reply( irc, 432, ":Incorrect password" ); } - - return( 1 ); } -static int irc_cmd_mode( irc_t *irc, char **cmd ) +static void irc_cmd_mode( irc_t *irc, char **cmd ) { if( *cmd[1] == '#' || *cmd[1] == '&' ) { @@ -132,18 +122,14 @@ static int irc_cmd_mode( irc_t *irc, char **cmd ) else irc_reply( irc, 502, ":Don't touch their modes" ); } - - return( 1 ); } -static int irc_cmd_names( irc_t *irc, char **cmd ) +static void irc_cmd_names( irc_t *irc, char **cmd ) { irc_names( irc, cmd[1]?cmd[1]:irc->channel ); - - return( 1 ); } -static int irc_cmd_part( irc_t *irc, char **cmd ) +static void irc_cmd_part( irc_t *irc, char **cmd ) { struct conversation *c; @@ -171,11 +157,9 @@ static int irc_cmd_part( irc_t *irc, char **cmd ) { irc_reply( irc, 403, "%s :No such channel", cmd[1] ); } - - return( 1 ); } -static int irc_cmd_join( irc_t *irc, char **cmd ) +static void irc_cmd_join( irc_t *irc, char **cmd ) { if( g_strcasecmp( cmd[1], irc->channel ) == 0 ) ; /* Dude, you're already there... @@ -209,11 +193,9 @@ static int irc_cmd_join( irc_t *irc, char **cmd ) irc_reply( irc, 403, "%s :No such channel", cmd[1] ); } } - - return( 1 ); } -static int irc_cmd_invite( irc_t *irc, char **cmd ) +static void irc_cmd_invite( irc_t *irc, char **cmd ) { char *nick = cmd[1], *channel = cmd[2]; struct conversation *c = conv_findchannel( channel ); @@ -224,15 +206,13 @@ static int irc_cmd_invite( irc_t *irc, char **cmd ) { c->gc->prpl->chat_invite( c->gc, c->id, "", u->handle ); irc_reply( irc, 341, "%s %s", nick, channel ); - return( 1 ); + return; } irc_reply( irc, 482, "%s :Invite impossible; User/Channel non-existent or incompatible", channel ); - - return( 1 ); } -static int irc_cmd_privmsg( irc_t *irc, char **cmd ) +static void irc_cmd_privmsg( irc_t *irc, char **cmd ) { if ( !cmd[2] ) { @@ -282,11 +262,9 @@ static int irc_cmd_privmsg( irc_t *irc, char **cmd ) } irc_send( irc, cmd[1], cmd[2], ( g_strcasecmp( cmd[0], "NOTICE" ) == 0 ) ? IM_FLAG_AWAY : 0 ); } - - return( 1 ); } -static int irc_cmd_who( irc_t *irc, char **cmd ) +static void irc_cmd_who( irc_t *irc, char **cmd ) { char *channel = cmd[1]; user_t *u = irc->users; @@ -316,11 +294,9 @@ static int irc_cmd_who( irc_t *irc, char **cmd ) irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->online ? ( u->away ? 'G' : 'H' ) : 'G', u->realname ); irc_reply( irc, 315, "%s :End of /WHO list", channel?channel:"**" ); - - return( 1 ); } -static int irc_cmd_userhost( irc_t *irc, char **cmd ) +static void irc_cmd_userhost( irc_t *irc, char **cmd ) { user_t *u; int i; @@ -339,11 +315,9 @@ static int irc_cmd_userhost( irc_t *irc, char **cmd ) else irc_reply( irc, 302, ":%s=+%s@%s", u->nick, u->user, u->host ); } - - return( 1 ); } -static int irc_cmd_ison( irc_t *irc, char **cmd ) +static void irc_cmd_ison( irc_t *irc, char **cmd ) { user_t *u; char buff[IRC_MAX_LINE]; @@ -382,11 +356,9 @@ static int irc_cmd_ison( irc_t *irc, char **cmd ) buff[strlen(buff)-1] = '\0'; irc_reply( irc, 303, ":%s", buff ); - - return( 1 ); } -static int irc_cmd_watch( irc_t *irc, char **cmd ) +static void irc_cmd_watch( irc_t *irc, char **cmd ) { int i; @@ -429,27 +401,23 @@ static int irc_cmd_watch( irc_t *irc, char **cmd ) } } } - - return( 1 ); } -static int irc_cmd_topic( irc_t *irc, char **cmd ) +static void irc_cmd_topic( irc_t *irc, char **cmd ) { if( cmd[2] ) irc_reply( irc, 482, "%s :Cannot change topic", cmd[1] ); else irc_topic( irc, cmd[1] ); - - return( 1 ); } -static int irc_cmd_away( irc_t *irc, char **cmd ) +static void irc_cmd_away( irc_t *irc, char **cmd ) { user_t *u = user_find( irc, irc->nick ); GSList *c = get_connections(); char *away = cmd[1]; - if( !u ) return( 1 ); + if( !u ) return; if( away && *away ) { @@ -481,11 +449,9 @@ static int irc_cmd_away( irc_t *irc, char **cmd ) c = c->next; } - - return( 1 ); } -static int irc_cmd_whois( irc_t *irc, char **cmd ) +static void irc_cmd_whois( irc_t *irc, char **cmd ) { char *nick = cmd[1]; user_t *u = user_find( irc, nick ); @@ -511,11 +477,9 @@ static int irc_cmd_whois( irc_t *irc, char **cmd ) { irc_reply( irc, 401, "%s :Nick does not exist", nick ); } - - return( 1 ); } -static int irc_cmd_whowas( irc_t *irc, char **cmd ) +static void irc_cmd_whowas( irc_t *irc, char **cmd ) { /* For some reason irssi tries a whowas when whois fails. We can ignore this, but then the user never gets a "user not found" @@ -524,37 +488,29 @@ static int irc_cmd_whowas( irc_t *irc, char **cmd ) irc_reply( irc, 406, "%s :Nick does not exist", cmd[1] ); irc_reply( irc, 369, "%s :End of WHOWAS", cmd[1] ); - - return( 1 ); } -static int irc_cmd_nickserv( irc_t *irc, char **cmd ) +static void irc_cmd_nickserv( irc_t *irc, char **cmd ) { /* [SH] This aliases the NickServ command to PRIVMSG root */ /* [TV] This aliases the NS command to PRIVMSG root as well */ root_command( irc, cmd + 1 ); - - return( 1 ); } -static int irc_cmd_motd( irc_t *irc, char **cmd ) +static void irc_cmd_motd( irc_t *irc, char **cmd ) { irc_motd( irc ); - - return( 1 ); } -static int irc_cmd_pong( irc_t *irc, char **cmd ) +static void irc_cmd_pong( irc_t *irc, char **cmd ) { /* We could check the value we get back from the user, but in fact we don't care, we're just happy he's still alive. */ irc->last_pong = gettime(); irc->pinging = 0; - - return( 1 ); } -static int irc_cmd_completions( irc_t *irc, char **cmd ) +static void irc_cmd_completions( irc_t *irc, char **cmd ) { user_t *u = user_find( irc, irc->mynick ); help_t *h; @@ -573,11 +529,9 @@ static int irc_cmd_completions( irc_t *irc, char **cmd ) irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS set ", s->key ); irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", "END" ); - - return( 1 ); } -static int irc_cmd_rehash( irc_t *irc, char **cmd ) +static void irc_cmd_rehash( irc_t *irc, char **cmd ) { if( global.conf->runmode == RUNMODE_INETD ) ipc_master_cmd_rehash( NULL, NULL ); @@ -585,8 +539,6 @@ static int irc_cmd_rehash( irc_t *irc, char **cmd ) ipc_to_master( cmd ); irc_reply( irc, 382, "%s :Rehashing", CONF_FILE ); - - return( 1 ); } static const command_t irc_commands[] = { @@ -624,12 +576,12 @@ static const command_t irc_commands[] = { { NULL } }; -int irc_exec( irc_t *irc, char *cmd[] ) +void irc_exec( irc_t *irc, char *cmd[] ) { - int i, j; + int i; if( !cmd[0] ) - return( 1 ); + return; for( i = 0; irc_commands[i].command; i++ ) if( g_strcasecmp( irc_commands[i].command, cmd[0] ) == 0 ) @@ -637,33 +589,30 @@ int irc_exec( irc_t *irc, char *cmd[] ) if( irc_commands[i].flags & IRC_CMD_PRE_LOGIN && irc->status >= USTATUS_LOGGED_IN ) { irc_reply( irc, 462, ":Only allowed before logging in" ); - return( 1 ); } - 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" ); - return( 1 ); } - if( irc_commands[i].flags & IRC_CMD_OPER_ONLY && !strchr( irc->umode, 'o' ) ) + else if( irc_commands[i].flags & IRC_CMD_OPER_ONLY && !strchr( irc->umode, 'o' ) ) { irc_reply( irc, 481, ":Permission denied - You're not an IRC operator" ); - return( 1 ); } - - for( j = 1; j <= irc_commands[i].required_parameters; j ++ ) - if( !cmd[j] ) - { - irc_reply( irc, 461, "%s :Need more parameters", cmd[0] ); - return( 1 ); - } - - if( irc_commands[i].flags & IRC_CMD_TO_MASTER ) + else if( !cmd[irc_commands[i].required_parameters] ) + { + irc_reply( irc, 461, "%s :Need more parameters", cmd[0] ); + } + else if( irc_commands[i].flags & IRC_CMD_TO_MASTER ) + { /* IPC doesn't make sense in inetd mode, but the function will catch that. */ ipc_to_master( cmd ); + } else - return irc_commands[i].execute( irc, cmd ); + { + irc_commands[i].execute( irc, cmd ); + } + + break; } - - return( 1 ); } diff --git a/root_commands.c b/root_commands.c new file mode 100644 index 00000000..426cf6e8 --- /dev/null +++ b/root_commands.c @@ -0,0 +1,800 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2004 Wilmer van der Gaast and others * + \********************************************************************/ + +/* User manager (root) commands */ + +/* + 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 "commands.h" +#include "crypting.h" +#include "bitlbee.h" +#include "help.h" + +#include + +void root_command_string( irc_t *irc, user_t *u, char *command, int flags ) +{ + char *cmd[IRC_MAX_ARGS]; + char *s; + int k; + char q = 0; + + memset( cmd, 0, sizeof( cmd ) ); + cmd[0] = command; + k = 1; + for( s = command; *s && k < ( IRC_MAX_ARGS - 1 ); s ++ ) + if( *s == ' ' && !q ) + { + *s = 0; + while( *++s == ' ' ); + if( *s == '"' || *s == '\'' ) + { + q = *s; + s ++; + } + if( *s ) + { + cmd[k++] = s; + s --; + } + } + else if( *s == q ) + { + q = *s = 0; + } + cmd[k] = NULL; + + root_command( irc, cmd ); +} + +void root_command( irc_t *irc, char *cmd[] ) +{ + int i; + + if( !cmd[0] ) + return; + + for( i = 0; commands[i].command; i++ ) + if( g_strcasecmp( commands[i].command, cmd[0] ) == 0 ) + { + if( !cmd[commands[i].required_parameters] ) + { + irc_usermsg( irc, "Not enough parameters given (need %d)", commands[i].required_parameters ); + return; + } + commands[i].execute( irc, cmd ); + return; + } + + irc_usermsg( irc, "Unknown command: %s. Please use \x02help commands\x02 to get a list of available commands.", cmd[0] ); +} + +static void cmd_help( irc_t *irc, char **cmd ) +{ + char param[80]; + int i; + char *s; + + memset( param, 0, sizeof(param) ); + for ( i = 1; (cmd[i] != NULL && ( strlen(param) < (sizeof(param)-1) ) ); i++ ) { + if ( i != 1 ) // prepend space except for the first parameter + strcat(param, " "); + strncat( param, cmd[i], sizeof(param) - strlen(param) - 1 ); + } + + s = help_get( &(global.help), param ); + if( !s ) s = help_get( &(global.help), "" ); + + if( s ) + { + irc_usermsg( irc, "%s", s ); + g_free( s ); + } + else + { + irc_usermsg( irc, "Error opening helpfile." ); + } +} + +static void cmd_identify( irc_t *irc, char **cmd ) +{ + storage_status_t status = storage_load( irc->nick, cmd[1], irc ); + + switch (status) { + case STORAGE_INVALID_PASSWORD: + irc_usermsg( irc, "Incorrect password" ); + break; + case STORAGE_NO_SUCH_USER: + irc_usermsg( irc, "The nick is (probably) not registered" ); + break; + case STORAGE_OK: + irc_usermsg( irc, "Password accepted" ); + irc_umode_set( irc, "+R", 1 ); + break; + default: + irc_usermsg( irc, "Something very weird happened" ); + break; + } +} + +static void cmd_register( irc_t *irc, char **cmd ) +{ + if( global.conf->authmode == AUTHMODE_REGISTERED ) + { + irc_usermsg( irc, "This server does not allow registering new accounts" ); + return; + } + + irc_setpass( irc, cmd[1] ); + switch( storage_save( irc, FALSE )) { + case STORAGE_ALREADY_EXISTS: + irc_usermsg( irc, "Nick is already registered" ); + break; + + case STORAGE_OK: + irc->status = USTATUS_IDENTIFIED; + irc_umode_set( irc, "+R", 1 ); + break; + + default: + irc_usermsg( irc, "Error registering" ); + break; + } +} + +static void cmd_drop( irc_t *irc, char **cmd ) +{ + storage_status_t status; + + status = storage_remove (irc->nick, cmd[1]); + switch (status) { + case STORAGE_NO_SUCH_USER: + irc_usermsg( irc, "That account does not exist" ); + break; + case STORAGE_INVALID_PASSWORD: + irc_usermsg( irc, "Password invalid" ); + break; + case STORAGE_OK: + irc_setpass( irc, NULL ); + irc->status = USTATUS_LOGGED_IN; + irc_umode_set( irc, "-R", 1 ); + irc_usermsg( irc, "Account `%s' removed", irc->nick ); + break; + default: + irc_usermsg( irc, "Error: '%d'", status ); + break; + } +} + +static void cmd_account( irc_t *irc, char **cmd ) +{ + account_t *a; + + if( global.conf->authmode == AUTHMODE_REGISTERED && irc->status < USTATUS_IDENTIFIED ) + { + irc_usermsg( irc, "This server only accepts registered users" ); + return; + } + + if( g_strcasecmp( cmd[1], "add" ) == 0 ) + { + struct prpl *prpl; + + if( cmd[2] == NULL || cmd[3] == NULL || cmd[4] == NULL ) + { + irc_usermsg( irc, "Not enough parameters" ); + return; + } + + prpl = find_protocol(cmd[2]); + + if( prpl == NULL ) + { + irc_usermsg( irc, "Unknown protocol" ); + return; + } + + a = account_add( irc, prpl, cmd[3], cmd[4] ); + + if( cmd[5] ) + a->server = g_strdup( cmd[5] ); + + irc_usermsg( irc, "Account successfully added" ); + } + else if( g_strcasecmp( cmd[1], "del" ) == 0 ) + { + if( !cmd[2] ) + { + irc_usermsg( irc, "Not enough parameters given (need %d)", 2 ); + } + else if( !( a = account_get( irc, cmd[2] ) ) ) + { + irc_usermsg( irc, "Invalid account" ); + } + else if( a->gc ) + { + irc_usermsg( irc, "Account is still logged in, can't delete" ); + } + else + { + account_del( irc, a ); + irc_usermsg( irc, "Account deleted" ); + } + } + else if( g_strcasecmp( cmd[1], "list" ) == 0 ) + { + int i = 0; + + for( a = irc->accounts; a; a = a->next ) + { + char *con; + + if( a->gc && ( a->gc->flags & OPT_LOGGED_IN ) ) + con = " (connected)"; + else if( a->gc ) + con = " (connecting)"; + else if( a->reconnect ) + con = " (awaiting reconnect)"; + else + con = ""; + + irc_usermsg( irc, "%2d. %s, %s%s", i, a->prpl->name, a->user, con ); + + i ++; + } + irc_usermsg( irc, "End of account list" ); + } + else if( g_strcasecmp( cmd[1], "on" ) == 0 ) + { + if( cmd[2] ) + { + if( ( a = account_get( irc, cmd[2] ) ) ) + { + if( a->gc ) + { + irc_usermsg( irc, "Account already online" ); + return; + } + else + { + account_on( irc, a ); + } + } + else + { + irc_usermsg( irc, "Invalid account" ); + return; + } + } + else + { + if ( irc->accounts ) { + irc_usermsg( irc, "Trying to get all accounts connected..." ); + + for( a = irc->accounts; a; a = a->next ) + if( !a->gc ) + account_on( irc, a ); + } + else + { + irc_usermsg( irc, "No accounts known. Use 'account add' to add one." ); + } + } + } + else if( g_strcasecmp( cmd[1], "off" ) == 0 ) + { + if( !cmd[2] ) + { + irc_usermsg( irc, "Deactivating all active (re)connections..." ); + + for( a = irc->accounts; a; a = a->next ) + { + if( a->gc ) + account_off( irc, a ); + else if( a->reconnect ) + cancel_auto_reconnect( a ); + } + } + else if( ( a = account_get( irc, cmd[2] ) ) ) + { + if( a->gc ) + { + account_off( irc, a ); + } + else if( a->reconnect ) + { + cancel_auto_reconnect( a ); + irc_usermsg( irc, "Reconnect cancelled" ); + } + else + { + irc_usermsg( irc, "Account already offline" ); + return; + } + } + else + { + irc_usermsg( irc, "Invalid account" ); + return; + } + } + else + { + irc_usermsg( irc, "Unknown command: account %s. Please use \x02help commands\x02 to get a list of available commands.", cmd[1] ); + } +} + +static void cmd_add( irc_t *irc, char **cmd ) +{ + account_t *a; + + if( !( a = account_get( irc, cmd[1] ) ) ) + { + irc_usermsg( irc, "Invalid account" ); + return; + } + else if( !( a->gc && ( a->gc->flags & OPT_LOGGED_IN ) ) ) + { + irc_usermsg( irc, "That account is not on-line" ); + return; + } + + if( cmd[3] ) + { + if( !nick_ok( cmd[3] ) ) + { + irc_usermsg( irc, "The requested nick `%s' is invalid", cmd[3] ); + return; + } + else if( user_find( irc, cmd[3] ) ) + { + irc_usermsg( irc, "The requested nick `%s' already exists", cmd[3] ); + return; + } + else + { + nick_set( irc, cmd[2], a->gc->prpl, cmd[3] ); + } + } + a->gc->prpl->add_buddy( a->gc, cmd[2] ); + add_buddy( a->gc, NULL, cmd[2], cmd[2] ); + + irc_usermsg( irc, "User `%s' added to your contact list as `%s'", cmd[2], user_findhandle( a->gc, cmd[2] )->nick ); +} + +static void cmd_info( irc_t *irc, char **cmd ) +{ + struct gaim_connection *gc; + account_t *a; + + if( !cmd[2] ) + { + user_t *u = user_find( irc, cmd[1] ); + if( !u || !u->gc ) + { + irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] ); + return; + } + gc = u->gc; + cmd[2] = u->handle; + } + else if( !( a = account_get( irc, cmd[1] ) ) ) + { + irc_usermsg( irc, "Invalid account" ); + return; + } + else if( !( ( gc = a->gc ) && ( a->gc->flags & OPT_LOGGED_IN ) ) ) + { + irc_usermsg( irc, "That account is not on-line" ); + return; + } + + if( !gc->prpl->get_info ) + { + irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] ); + } + else + { + gc->prpl->get_info( gc, cmd[2] ); + } +} + +static void cmd_rename( irc_t *irc, char **cmd ) +{ + user_t *u; + + if( g_strcasecmp( cmd[1], irc->nick ) == 0 ) + { + irc_usermsg( irc, "Nick `%s' can't be changed", cmd[1] ); + } + else if( user_find( irc, cmd[2] ) && ( nick_cmp( cmd[1], cmd[2] ) != 0 ) ) + { + irc_usermsg( irc, "Nick `%s' already exists", cmd[2] ); + } + else if( !nick_ok( cmd[2] ) ) + { + irc_usermsg( irc, "Nick `%s' is invalid", cmd[2] ); + } + else if( !( u = user_find( irc, cmd[1] ) ) ) + { + irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] ); + } + else + { + user_rename( irc, cmd[1], cmd[2] ); + irc_write( irc, ":%s!%s@%s NICK %s", cmd[1], u->user, u->host, cmd[2] ); + if( g_strcasecmp( cmd[1], irc->mynick ) == 0 ) + { + g_free( irc->mynick ); + irc->mynick = g_strdup( cmd[2] ); + } + else if( u->send_handler == buddy_send_handler ) + { + nick_set( irc, u->handle, u->gc->prpl, cmd[2] ); + } + + irc_usermsg( irc, "Nick successfully changed" ); + } +} + +static void cmd_remove( irc_t *irc, char **cmd ) +{ + user_t *u; + char *s; + + if( !( u = user_find( irc, cmd[1] ) ) || !u->gc ) + { + irc_usermsg( irc, "Buddy `%s' not found", cmd[1] ); + return; + } + s = g_strdup( u->handle ); + + u->gc->prpl->remove_buddy( u->gc, u->handle, NULL ); + user_del( irc, cmd[1] ); + nick_del( irc, cmd[1] ); + + irc_usermsg( irc, "Buddy `%s' (nick %s) removed from contact list", s, cmd[1] ); + g_free( s ); + + return; +} + +static void cmd_block( irc_t *irc, char **cmd ) +{ + struct gaim_connection *gc; + account_t *a; + + if( !cmd[2] ) + { + user_t *u = user_find( irc, cmd[1] ); + if( !u || !u->gc ) + { + irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] ); + return; + } + gc = u->gc; + cmd[2] = u->handle; + } + else if( !( a = account_get( irc, cmd[1] ) ) ) + { + irc_usermsg( irc, "Invalid account" ); + return; + } + else if( !( ( gc = a->gc ) && ( a->gc->flags & OPT_LOGGED_IN ) ) ) + { + irc_usermsg( irc, "That account is not on-line" ); + return; + } + + if( !gc->prpl->add_deny || !gc->prpl->rem_permit ) + { + irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] ); + } + else + { + gc->prpl->rem_permit( gc, cmd[2] ); + gc->prpl->add_deny( gc, cmd[2] ); + irc_usermsg( irc, "Buddy `%s' moved from your permit- to your deny-list", cmd[2] ); + } +} + +static void cmd_allow( irc_t *irc, char **cmd ) +{ + struct gaim_connection *gc; + account_t *a; + + if( !cmd[2] ) + { + user_t *u = user_find( irc, cmd[1] ); + if( !u || !u->gc ) + { + irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] ); + return; + } + gc = u->gc; + cmd[2] = u->handle; + } + else if( !( a = account_get( irc, cmd[1] ) ) ) + { + irc_usermsg( irc, "Invalid account" ); + return; + } + else if( !( ( gc = a->gc ) && ( a->gc->flags & OPT_LOGGED_IN ) ) ) + { + irc_usermsg( irc, "That account is not on-line" ); + return; + } + + if( !gc->prpl->rem_deny || !gc->prpl->add_permit ) + { + irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] ); + } + else + { + gc->prpl->rem_deny( gc, cmd[2] ); + gc->prpl->add_permit( gc, cmd[2] ); + + irc_usermsg( irc, "Buddy `%s' moved from your deny- to your permit-list", cmd[2] ); + } +} + +static void cmd_yesno( irc_t *irc, char **cmd ) +{ + query_t *q = NULL; + int numq = 0; + + if( irc->queries == NULL ) + { + irc_usermsg( irc, "Did I ask you something?" ); + return; + } + + /* If there's an argument, the user seems to want to answer another question than the + first/last (depending on the query_order setting) one. */ + if( cmd[1] ) + { + if( sscanf( cmd[1], "%d", &numq ) != 1 ) + { + irc_usermsg( irc, "Invalid query number" ); + return; + } + + for( q = irc->queries; q; q = q->next, numq -- ) + if( numq == 0 ) + break; + + if( !q ) + { + irc_usermsg( irc, "Uhm, I never asked you something like that..." ); + return; + } + } + + if( g_strcasecmp( cmd[0], "yes" ) == 0 ) + query_answer( irc, q, 1 ); + else if( g_strcasecmp( cmd[0], "no" ) == 0 ) + query_answer( irc, q, 0 ); +} + +static void cmd_set( irc_t *irc, char **cmd ) +{ + if( cmd[1] && cmd[2] ) + { + set_setstr( irc, cmd[1], cmd[2] ); + } + if( cmd[1] ) /* else 'forgotten' on purpose.. Must show new value after changing */ + { + char *s = set_getstr( irc, cmd[1] ); + if( s ) + irc_usermsg( irc, "%s = `%s'", cmd[1], s ); + } + else + { + set_t *s = irc->set; + while( s ) + { + if( s->value || s->def ) + irc_usermsg( irc, "%s = `%s'", s->key, s->value?s->value:s->def ); + s = s->next; + } + } +} + +static void cmd_save( irc_t *irc, char **cmd ) +{ + if( storage_save( irc, TRUE ) == STORAGE_OK ) + irc_usermsg( irc, "Configuration saved" ); + else + irc_usermsg( irc, "Configuration could not be saved!" ); +} + +static void cmd_blist( irc_t *irc, char **cmd ) +{ + int online = 0, away = 0, offline = 0; + user_t *u; + char s[64]; + int n_online = 0, n_away = 0, n_offline = 0; + + if( cmd[1] && g_strcasecmp( cmd[1], "all" ) == 0 ) + online = offline = away = 1; + else if( cmd[1] && g_strcasecmp( cmd[1], "offline" ) == 0 ) + offline = 1; + else if( cmd[1] && g_strcasecmp( cmd[1], "away" ) == 0 ) + away = 1; + else if( cmd[1] && g_strcasecmp( cmd[1], "online" ) == 0 ) + online = 1; + else + online = away = 1; + + irc_usermsg( irc, "%-16.16s %-40.40s %s", "Nick", "User/Host/Network", "Status" ); + + if( online == 1 ) for( u = irc->users; u; u = u->next ) if( u->gc && u->online && !u->away ) + { + g_snprintf( s, 63, "%s@%s (%s)", u->user, u->host, u->gc->user->prpl->name ); + irc_usermsg( irc, "%-16.16s %-40.40s %s", u->nick, s, "Online" ); + n_online ++; + } + + if( away == 1 ) for( u = irc->users; u; u = u->next ) if( u->gc && u->online && u->away ) + { + g_snprintf( s, 63, "%s@%s (%s)", u->user, u->host, u->gc->user->prpl->name ); + irc_usermsg( irc, "%-16.16s %-40.40s %s", u->nick, s, u->away ); + n_away ++; + } + + if( offline == 1 ) for( u = irc->users; u; u = u->next ) if( u->gc && !u->online ) + { + g_snprintf( s, 63, "%s@%s (%s)", u->user, u->host, u->gc->user->prpl->name ); + irc_usermsg( irc, "%-16.16s %-40.40s %s", u->nick, s, "Offline" ); + n_offline ++; + } + + irc_usermsg( irc, "%d buddies (%d available, %d away, %d offline)", n_online + n_away + n_offline, n_online, n_away, n_offline ); +} + +static void cmd_nick( irc_t *irc, char **cmd ) +{ + account_t *a; + + if( !cmd[1] || !( a = account_get( irc, cmd[1] ) ) ) + { + irc_usermsg( irc, "Invalid account"); + } + else if( !( a->gc && ( a->gc->flags & OPT_LOGGED_IN ) ) ) + { + irc_usermsg( irc, "That account is not on-line" ); + } + else if ( !cmd[2] ) + { + irc_usermsg( irc, "Your name is `%s'" , a->gc->displayname ? a->gc->displayname : "NULL" ); + } + else if ( !a->gc->prpl->set_info ) + { + irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] ); + } + else + { + char utf8[1024]; + + irc_usermsg( irc, "Setting your name to `%s'", cmd[2] ); + + if( g_strncasecmp( set_getstr( irc, "charset" ), "none", 4 ) != 0 && + do_iconv( set_getstr( irc, "charset" ), "UTF-8", cmd[2], utf8, 0, 1024 ) != -1 ) + a->gc->prpl->set_info( a->gc, utf8 ); + else + a->gc->prpl->set_info( a->gc, cmd[2] ); + } +} + +static void cmd_qlist( irc_t *irc, char **cmd ) +{ + query_t *q = irc->queries; + int num; + + if( !q ) + { + irc_usermsg( irc, "There are no pending questions." ); + return; + } + + irc_usermsg( irc, "Pending queries:" ); + + for( num = 0; q; q = q->next, num ++ ) + if( q->gc ) /* Not necessary yet, but it might come later */ + irc_usermsg( irc, "%d, %s(%s): %s", num, q->gc->prpl->name, q->gc->username, q->question ); + else + irc_usermsg( irc, "%d, BitlBee: %s", num, q->question ); +} + +static void cmd_import_buddies( irc_t *irc, char **cmd ) +{ + struct gaim_connection *gc; + account_t *a; + nick_t *n; + + if( !( a = account_get( irc, cmd[1] ) ) ) + { + irc_usermsg( irc, "Invalid account" ); + return; + } + else if( !( ( gc = a->gc ) && ( a->gc->flags & OPT_LOGGED_IN ) ) ) + { + irc_usermsg( irc, "That account is not on-line" ); + return; + } + + if( cmd[2] ) + { + if( g_strcasecmp( cmd[2], "clear" ) == 0 ) + { + user_t *u; + + for( u = irc->users; u; u = u->next ) + if( u->gc == gc ) + { + u->gc->prpl->remove_buddy( u->gc, u->handle, NULL ); + user_del( irc, u->nick ); + } + + irc_usermsg( irc, "Old buddy list cleared." ); + } + else + { + irc_usermsg( irc, "Invalid argument: %s", cmd[2] ); + return; + } + } + + for( n = gc->irc->nicks; n; n = n->next ) + { + if( n->proto == gc->prpl && !user_findhandle( gc, n->handle ) ) + { + gc->prpl->add_buddy( gc, n->handle ); + add_buddy( gc, NULL, n->handle, NULL ); + } + } + + irc_usermsg( irc, "Sent all add requests. Please wait for a while, the server needs some time to handle all the adds." ); +} + +const command_t commands[] = { + { "help", 0, cmd_help, 0 }, + { "identify", 1, cmd_identify, 0 }, + { "register", 1, cmd_register, 0 }, + { "drop", 1, cmd_drop, 0 }, + { "account", 1, cmd_account, 0 }, + { "add", 2, cmd_add, 0 }, + { "info", 1, cmd_info, 0 }, + { "rename", 2, cmd_rename, 0 }, + { "remove", 1, cmd_remove, 0 }, + { "block", 1, cmd_block, 0 }, + { "allow", 1, cmd_allow, 0 }, + { "save", 0, cmd_save, 0 }, + { "set", 0, cmd_set, 0 }, + { "yes", 0, cmd_yesno, 0 }, + { "no", 0, cmd_yesno, 0 }, + { "blist", 0, cmd_blist, 0 }, + { "nick", 1, cmd_nick, 0 }, + { "import_buddies", 1, cmd_import_buddies, 0 }, + { "qlist", 0, cmd_qlist, 0 }, + { NULL } +}; diff --git a/user.h b/user.h index 79b5ed0e..da657a4d 100644 --- a/user.h +++ b/user.h @@ -44,7 +44,7 @@ typedef struct __USER guint sendbuf_timer; int sendbuf_flags; - int (*send_handler) ( irc_t *irc, struct __USER *u, char *msg, int flags ); + void (*send_handler) ( irc_t *irc, struct __USER *u, char *msg, int flags ); struct __USER *next; } user_t; -- cgit v1.2.3 From f1d38f20f760376f43b90a105486cf3ff2fbf2c4 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 21 Jan 2006 23:23:58 +0100 Subject: Fixed counting of arguments in i[rp]c_exec(), made them a bit too simple. --- ipc.c | 10 ++++++++-- irc_commands.c | 7 +++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/ipc.c b/ipc.c index 8d44e4eb..3528988f 100644 --- a/ipc.c +++ b/ipc.c @@ -154,7 +154,7 @@ static const command_t ipc_child_commands[] = { static void ipc_command_exec( void *data, char **cmd, const command_t *commands ) { - int i; + int i, j; if( !cmd[0] ) return; @@ -162,12 +162,18 @@ static void ipc_command_exec( void *data, char **cmd, const command_t *commands for( i = 0; commands[i].command; i ++ ) if( g_strcasecmp( commands[i].command, cmd[0] ) == 0 ) { + /* There is no typo in this line: */ + for( j = 1; cmd[j]; j ++ ); j --; + + if( j < commands[i].required_parameters ) + break; + if( commands[i].flags & IPC_CMD_TO_CHILDREN ) ipc_to_children( cmd ); else commands[i].execute( data, cmd ); - return; + break; } } diff --git a/irc_commands.c b/irc_commands.c index e4dc4f3e..9e47b83b 100644 --- a/irc_commands.c +++ b/irc_commands.c @@ -578,7 +578,7 @@ static const command_t irc_commands[] = { void irc_exec( irc_t *irc, char *cmd[] ) { - int i; + int i, n_arg; if( !cmd[0] ) return; @@ -586,6 +586,9 @@ void irc_exec( irc_t *irc, char *cmd[] ) for( i = 0; irc_commands[i].command; i++ ) if( g_strcasecmp( irc_commands[i].command, cmd[0] ) == 0 ) { + /* There should be no typo in the next line: */ + for( n_arg = 0; cmd[n_arg]; n_arg ++ ); n_arg --; + if( irc_commands[i].flags & IRC_CMD_PRE_LOGIN && irc->status >= USTATUS_LOGGED_IN ) { irc_reply( irc, 462, ":Only allowed before logging in" ); @@ -598,7 +601,7 @@ void irc_exec( irc_t *irc, char *cmd[] ) { irc_reply( irc, 481, ":Permission denied - You're not an IRC operator" ); } - else if( !cmd[irc_commands[i].required_parameters] ) + else if( n_arg < irc_commands[i].required_parameters ) { irc_reply( irc, 461, "%s :Need more parameters", cmd[0] ); } -- cgit v1.2.3 From 87de505f3203054a2a0becbea5a064d24ab2cde3 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 22 Jan 2006 01:15:03 +0100 Subject: Quit message was invisible on /DIE. --- ipc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipc.c b/ipc.c index 3528988f..aba59bda 100644 --- a/ipc.c +++ b/ipc.c @@ -87,7 +87,7 @@ static const command_t ipc_master_commands[] = { static void ipc_child_cmd_die( irc_t *irc, char **cmd ) { - irc_abort( irc, 1, "Shutdown requested by operator" ); + irc_abort( irc, 0, "Shutdown requested by operator" ); } static void ipc_child_cmd_wallops( irc_t *irc, char **cmd ) -- cgit v1.2.3 From a49dcd5c3c6b79470ad71dc45ccf29f65ba2a7f9 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 22 Jan 2006 21:33:56 +0100 Subject: Fixed the bug that caused a fork() bomb last night. --- bitlbee.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/bitlbee.c b/bitlbee.c index 5da5d6e1..2f757f53 100644 --- a/bitlbee.c +++ b/bitlbee.c @@ -103,10 +103,14 @@ int bitlbee_daemon_init() } else if( i != 0 ) exit( 0 ); - close( 0 ); - close( 1 ); - close( 2 ); + chdir( "/" ); + + /* Sometimes std* are already closed (for example when we're in a RESTARTed + BitlBee process. So let's only close TTY-fds. */ + if( isatty( 0 ) ) close( 0 ); + if( isatty( 0 ) ) close( 1 ); + if( isatty( 0 ) ) close( 2 ); } #endif -- cgit v1.2.3 From a91ecee010fdbd8e62e874e23a443206a48308c0 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 23 Jan 2006 15:20:18 +0100 Subject: /AWAY now only sets the IM-protocols away that belong to the current IRC /connection (was an issue in single-process daemon mode). --- irc_commands.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/irc_commands.c b/irc_commands.c index 9e47b83b..66c39bc5 100644 --- a/irc_commands.c +++ b/irc_commands.c @@ -414,8 +414,8 @@ static void irc_cmd_topic( irc_t *irc, char **cmd ) static void irc_cmd_away( irc_t *irc, char **cmd ) { user_t *u = user_find( irc, irc->nick ); - GSList *c = get_connections(); char *away = cmd[1]; + account_t *a; if( !u ) return; @@ -442,12 +442,12 @@ static void irc_cmd_away( irc_t *irc, char **cmd ) irc_reply( irc, 305, ":Welcome back" ); } - while( c ) + for( a = irc->accounts; a; a = a->next ) { - if( ((struct gaim_connection *)c->data)->flags & OPT_LOGGED_IN ) - proto_away( c->data, u->away ); + struct gaim_connection *gc = a->gc; - c = c->next; + if( gc && gc->flags & OPT_LOGGED_IN ) + proto_away( gc, u->away ); } } -- cgit v1.2.3 From 68c7c145c281fe3ae734b345bf133d70d1ef8652 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 23 Jan 2006 15:20:36 +0100 Subject: Removed a bogus printf from the OSCAR code, grrrr. --- protocols/oscar/service.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/protocols/oscar/service.c b/protocols/oscar/service.c index 875a2eb0..573e1983 100644 --- a/protocols/oscar/service.c +++ b/protocols/oscar/service.c @@ -736,8 +736,6 @@ int aim_setextstatus(aim_session_t *sess, aim_conn_t *conn, guint32 status) tlvlen = aim_addtlvtochain32(&tl, 0x0006, data); - printf("%d\n", tlvlen); - if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 8))) return -ENOMEM; -- cgit v1.2.3 From 105383688a6605ca40ab4fa987d72809170a2e36 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 30 Jan 2006 14:30:59 +0100 Subject: When closing down MSN (sb) connections with unsent messages, the warning message now mentions the people those messages were meant for. --- protocols/msn/msn.c | 4 ++-- protocols/msn/sb.c | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c index b03c898e..3c7064f8 100644 --- a/protocols/msn/msn.c +++ b/protocols/msn/msn.c @@ -83,13 +83,13 @@ static void msn_close( struct gaim_connection *gc ) for( l = md->msgq; l; l = l->next ) { m = l->data; + + serv_got_crap( gc, "Warning: Closing down MSN connection with unsent message to %s, you'll have to resend it.", m->who ); g_free( m->who ); g_free( m->text ); g_free( m ); } g_slist_free( md->msgq ); - - serv_got_crap( gc, "Warning: Closing down MSN connection with unsent message(s), you'll have to resend them." ); } for( l = gc->permit; l; l = l->next ) diff --git a/protocols/msn/sb.c b/protocols/msn/sb.c index 9e7ef841..deaceba1 100644 --- a/protocols/msn/sb.c +++ b/protocols/msn/sb.c @@ -212,13 +212,16 @@ void msn_sb_destroy( struct msn_switchboard *sb ) for( l = sb->msgq; l; l = l->next ) { m = l->data; + g_free( m->who ); g_free( m->text ); g_free( m ); } g_slist_free( sb->msgq ); - serv_got_crap( gc, "Warning: Closing down MSN switchboard connection with unsent message(s), you'll have to resend them." ); + serv_got_crap( gc, "Warning: Closing down MSN switchboard connection with " + "unsent message to %s, you'll have to resend it.", + m->who ? m->who : "(unknown)" ); } if( sb->chat ) -- cgit v1.2.3 From 8365610bb2013d3478214511910daceabd29ad09 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 30 Jan 2006 17:07:07 +0100 Subject: Added a little warning message when people use a wrong set-command syntax. --- root_commands.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/root_commands.c b/root_commands.c index 426cf6e8..f69442d3 100644 --- a/root_commands.c +++ b/root_commands.c @@ -600,6 +600,9 @@ static void cmd_set( irc_t *irc, char **cmd ) if( cmd[1] && cmd[2] ) { set_setstr( irc, cmd[1], cmd[2] ); + + if( ( strcmp( cmd[2], "=" ) ) == 0 && cmd[3] ) + irc_usermsg( irc, "Warning: Correct syntax: \002set \002 (without =)" ); } if( cmd[1] ) /* else 'forgotten' on purpose.. Must show new value after changing */ { -- cgit v1.2.3 From 34b17d9b8901b72439167b99d780c481ce420e33 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Thu, 2 Feb 2006 14:21:44 +0100 Subject: Added PID-file code. --- bitlbee.c | 11 +++++++++++ conf.c | 13 ++++++++++++- conf.h | 1 + configure | 5 +++++ 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/bitlbee.c b/bitlbee.c index 9a4688d8..ac7823a4 100644 --- a/bitlbee.c +++ b/bitlbee.c @@ -44,6 +44,7 @@ int bitlbee_daemon_init() #endif int i; GIOChannel *ch; + FILE *fp; log_link( LOGLVL_ERROR, LOGOUTPUT_SYSLOG ); log_link( LOGLVL_WARNING, LOGOUTPUT_SYSLOG ); @@ -110,6 +111,16 @@ int bitlbee_daemon_init() } #endif + if( ( fp = fopen( global.conf->pidfile, "w" ) ) ) + { + fprintf( fp, "%d\n", (int) getpid() ); + fclose( fp ); + } + else + { + log_message( LOGLVL_WARNING, "Warning: Couldn't write PID to `%s'", global.conf->pidfile ); + } + return( 0 ); } diff --git a/conf.c b/conf.c index ae4b77a2..d38b7a68 100644 --- a/conf.c +++ b/conf.c @@ -60,6 +60,7 @@ conf_t *conf_load( int argc, char *argv[] ) conf->oper_pass = NULL; conf->configdir = g_strdup( CONFIG ); conf->plugindir = g_strdup( PLUGINDIR ); + conf->pidfile = g_strdup( "/var/run/bitlbee.pid" ); conf->motdfile = g_strdup( ETCDIR "/motd.txt" ); conf->ping_interval = 180; conf->ping_timeout = 300; @@ -76,7 +77,7 @@ conf_t *conf_load( int argc, char *argv[] ) fprintf( stderr, "Warning: Unable to read configuration file `%s'.\n", CONF_FILE ); } - while( argc > 0 && ( opt = getopt( argc, argv, "i:p:nvIDFc:d:h" ) ) >= 0 ) + while( argc > 0 && ( opt = getopt( argc, argv, "i:p:P:nvIDFc:d:h" ) ) >= 0 ) /* ^^^^ Just to make sure we skip this step from the REHASH handler. */ { if( opt == 'i' ) @@ -92,6 +93,11 @@ conf_t *conf_load( int argc, char *argv[] ) } conf->port = i; } + else if( opt == 'p' ) + { + g_free( conf->pidfile ); + conf->pidfile = g_strdup( optarg ); + } else if( opt == 'n' ) conf->nofork = 1; else if( opt == 'v' ) @@ -175,6 +181,11 @@ static int conf_loadini( conf_t *conf, char *file ) else conf->runmode = RUNMODE_INETD; } + else if( g_strcasecmp( ini->key, "pidfile" ) == 0 ) + { + g_free( conf->pidfile ); + conf->pidfile = g_strdup( ini->value ); + } else if( g_strcasecmp( ini->key, "daemoninterface" ) == 0 ) { conf->iface = g_strdup( ini->value ); diff --git a/conf.h b/conf.h index d6460901..e852dbef 100644 --- a/conf.h +++ b/conf.h @@ -42,6 +42,7 @@ typedef struct conf char *hostname; char *configdir; char *plugindir; + char *pidfile; char *motdfile; char *primary_storage; char **migrate_storage; diff --git a/configure b/configure index 7900967b..2731d5b1 100755 --- a/configure +++ b/configure @@ -13,6 +13,7 @@ etcdir='$prefix/etc/bitlbee/' mandir='$prefix/share/man/' datadir='$prefix/share/bitlbee/' config='/var/lib/bitlbee/' +pidfile='/var/run/bitlbee.pid' plugindir='$prefix/lib/bitlbee' msn=1 @@ -45,6 +46,7 @@ Option Description Default --mandir=... $mandir --datadir=... $datadir --plugindir=... $plugindir +--pidfile=... $pidfile --config=... $config --msn=0/1 Disable/enable MSN part $msn @@ -73,6 +75,7 @@ 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'` +pidfile=`eval echo "$pidfile/" | sed 's/\/\{1,\}/\//g'` cat<Makefile.settings ## BitlBee settings, generated by configure @@ -82,6 +85,7 @@ ETCDIR=$etcdir MANDIR=$mandir DATADIR=$datadir PLUGINDIR=$plugindir +PIDFILE=$pidfile CONFIG=$config ARCH=$arch @@ -103,6 +107,7 @@ cat<config.h #define ETCDIR "$etcdir" #define VARDIR "$datadir" #define PLUGINDIR "$plugindir" +#define PIDFILE "$pidfile" #define ARCH "$arch" #define CPU "$cpu" EOF -- cgit v1.2.3 From 58bc4e69967a8feec0a60dfab716985191c12817 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sun, 12 Feb 2006 20:24:38 +1300 Subject: Fix silly warning --- unix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unix.c b/unix.c index e59c341a..89bd65bf 100644 --- a/unix.c +++ b/unix.c @@ -41,7 +41,7 @@ static void sighandler( int signal ); int main( int argc, char *argv[], char **envp ) { int i = 0; - char *old_cwd; + char *old_cwd = NULL; struct sigaction sig, old; memset( &global, 0, sizeof( global_t ) ); -- cgit v1.2.3 From 7cf85e77cf36c2d582fad168996825aae82c9b85 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 12 Feb 2006 23:13:35 +0100 Subject: Fixed --help --- conf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/conf.c b/conf.c index dd99d741..0bd9cbc8 100644 --- a/conf.c +++ b/conf.c @@ -138,6 +138,7 @@ conf_t *conf_load( int argc, char *argv[] ) " -I Classic/InetD mode. (Default)\n" " -D Daemon mode. (Still EXPERIMENTAL!)\n" " -F Forking daemon. (one process per client)\n" + " -P Specify PID-file (not for inetd mode)\n" " -i Specify the interface (by IP address) to listen on.\n" " (Default: 0.0.0.0 (any interface))\n" " -p Port number to listen on. (Default: 6667)\n" -- cgit v1.2.3 From 6dff9d4ac2cbd279e25db60ae26086c830764682 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 1 Mar 2006 22:08:03 +0100 Subject: Also listen for admin connections on a unix domain socket at /var/run/bitlbee --- bitlbee.c | 4 ++++ configure | 8 ++++++-- ipc.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ ipc.h | 2 +- 4 files changed, 59 insertions(+), 3 deletions(-) diff --git a/bitlbee.c b/bitlbee.c index ddd8d2ea..47064382 100644 --- a/bitlbee.c +++ b/bitlbee.c @@ -117,6 +117,10 @@ int bitlbee_daemon_init() if( global.conf->runmode == RUNMODE_FORKDAEMON ) ipc_master_load_state(); + + if( global.conf->runmode == RUNMODE_DAEMON || + global.conf->runmode == RUNMODE_FORKDAEMON ) + ipc_master_listen_socket(); if( ( fp = fopen( global.conf->pidfile, "w" ) ) ) { diff --git a/configure b/configure index 2731d5b1..751e5b32 100755 --- a/configure +++ b/configure @@ -14,6 +14,7 @@ mandir='$prefix/share/man/' datadir='$prefix/share/bitlbee/' config='/var/lib/bitlbee/' pidfile='/var/run/bitlbee.pid' +ipcsocket='/var/run/bitlbee' plugindir='$prefix/lib/bitlbee' msn=1 @@ -48,6 +49,7 @@ Option Description Default --plugindir=... $plugindir --pidfile=... $pidfile --config=... $config +--ipcsocket=... $ipcsocket --msn=0/1 Disable/enable MSN part $msn --jabber=0/1 Disable/enable Jabber part $jabber @@ -75,7 +77,8 @@ 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'` -pidfile=`eval echo "$pidfile/" | sed 's/\/\{1,\}/\//g'` +pidfile=`eval echo "$pidfile" | sed 's/\/\{1,\}/\//g'` +ipcsocket=`eval echo "$ipcsocket" | sed 's/\/\{1,\}/\//g'` cat<Makefile.settings ## BitlBee settings, generated by configure @@ -85,8 +88,8 @@ ETCDIR=$etcdir MANDIR=$mandir DATADIR=$datadir PLUGINDIR=$plugindir -PIDFILE=$pidfile CONFIG=$config +IPCSOCKET=$ipcsocket ARCH=$arch CPU=$cpu @@ -108,6 +111,7 @@ cat<config.h #define VARDIR "$datadir" #define PLUGINDIR "$plugindir" #define PIDFILE "$pidfile" +#define IPCSOCKET "$ipcsocket" #define ARCH "$arch" #define CPU "$cpu" EOF diff --git a/ipc.c b/ipc.c index 778f74c8..b05958ae 100644 --- a/ipc.c +++ b/ipc.c @@ -27,6 +27,9 @@ #include "bitlbee.h" #include "ipc.h" #include "commands.h" +#ifndef _WIN32 +#include +#endif GSList *child_list = NULL; static char *statefile = NULL; @@ -456,6 +459,51 @@ void ipc_master_set_statefile( char *fn ) statefile = g_strdup( fn ); } + +static gboolean new_ipc_client (GIOChannel *gio, GIOCondition cond, gpointer data) +{ + 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); + + child->ipc_inpa = gaim_input_add( child->ipc_fd, GAIM_INPUT_READ, ipc_master_read, child ); + + child_list = g_slist_append( child_list, child ); + + return TRUE; +} + +#ifndef _WIN32 +int ipc_master_listen_socket() +{ + struct sockaddr_un un_addr; + int serversock; + GIOChannel *gio; + + /* Clean up old socket files that were hanging around.. */ + unlink(IPCSOCKET); + + un_addr.sun_family = AF_UNIX; + strcpy(un_addr.sun_path, IPCSOCKET); + + serversock = socket(AF_UNIX, SOCK_STREAM, PF_UNIX); + + bind(serversock, &un_addr, sizeof(un_addr)); + + listen(serversock, 5); + + gio = g_io_channel_unix_new(serversock); + + g_io_add_watch(gio, G_IO_IN, new_ipc_client, NULL); + return 1; +} +#else + /* FIXME: Open named pipe \\.\BITLBEE */ +#endif + int ipc_master_load_state() { struct bitlbee_child *child; diff --git a/ipc.h b/ipc.h index e8ad2a0d..7ff74a15 100644 --- a/ipc.h +++ b/ipc.h @@ -56,6 +56,6 @@ void ipc_master_cmd_rehash( irc_t *data, char **cmd ); char *ipc_master_save_state(); void ipc_master_set_statefile( char *fn ); int ipc_master_load_state(); - +int ipc_master_listen_socket(); extern GSList *child_list; -- cgit v1.2.3 From 5e713f695f93f7dc88f225bf6a8cd16e228eff11 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 1 Mar 2006 23:17:57 +0100 Subject: Added a little comment for this scary cast. (-: --- ipc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ipc.c b/ipc.c index 778f74c8..60caba3e 100644 --- a/ipc.c +++ b/ipc.c @@ -33,6 +33,10 @@ static char *statefile = NULL; static void ipc_master_cmd_client( irc_t *data, char **cmd ) { + /* Normally data points at an irc_t block, but for the IPC master + this is different. We think this scary cast is better than + creating a new command_t structure, just to make the compiler + happy. */ struct bitlbee_child *child = (void*) data; if( child && cmd[1] ) -- cgit v1.2.3 From 8a56e52a518855150525eab9e0fcdbe776223ffc Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 1 Mar 2006 23:30:10 +0100 Subject: Improve error handling --- ipc.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/ipc.c b/ipc.c index b05958ae..366b1119 100644 --- a/ipc.c +++ b/ipc.c @@ -468,6 +468,11 @@ static gboolean new_ipc_client (GIOChannel *gio, GIOCondition cond, gpointer dat serversock = g_io_channel_unix_get_fd(gio); 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 ); @@ -484,18 +489,37 @@ int ipc_master_listen_socket() GIOChannel *gio; /* Clean up old socket files that were hanging around.. */ - unlink(IPCSOCKET); + if (unlink(IPCSOCKET) == -1 && errno != ENOENT) { + log_message( LOGLVL_ERROR, "Could not remove old IPC socket at %s: %s", IPCSOCKET, strerror(errno) ); + return 0; + } un_addr.sun_family = AF_UNIX; strcpy(un_addr.sun_path, IPCSOCKET); serversock = socket(AF_UNIX, SOCK_STREAM, PF_UNIX); - bind(serversock, &un_addr, sizeof(un_addr)); + if (serversock == -1) { + log_message( LOGLVL_WARNING, "Unable to create UNIX socket: %s", strerror(errno) ); + return 0; + } + + if (bind(serversock, &un_addr, sizeof(un_addr)) == -1) { + log_message( LOGLVL_WARNING, "Unable to bind UNIX socket to %s: %s", IPCSOCKET, strerror(errno) ); + return 0; + } - listen(serversock, 5); + if (listen(serversock, 5) == -1) { + log_message( LOGLVL_WARNING, "Unable to listen on UNIX socket: %s", strerror(errno) ); + return 0; + } gio = g_io_channel_unix_new(serversock); + + 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; -- cgit v1.2.3 From 5fe0207972bb2466a40dcbbc39dd1e93545f4913 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 1 Mar 2006 23:31:43 +0100 Subject: Add simple bitlbee control script --- utils/bitlbee-ctl.pl | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100755 utils/bitlbee-ctl.pl diff --git a/utils/bitlbee-ctl.pl b/utils/bitlbee-ctl.pl new file mode 100755 index 00000000..32f0a81e --- /dev/null +++ b/utils/bitlbee-ctl.pl @@ -0,0 +1,59 @@ +#!/usr/bin/perl +# Simple front-end to BitlBee's administration commands +# Copyright (C) 2006 Jelmer Vernooij + +use IO::Socket; +use Getopt::Long; +use strict; +use warnings; + +my $opt_help; +my $opt_socketfile = "/var/run/bitlbee"; + +sub ShowHelp +{ + print +"bitlbee-ctl.pl [options] command ... + +Available options: + + --ipc-socket=SOCKET Override path to IPC socket [$opt_socketfile] + --help Show this help message + +Available commands: + + die + +"; + exit (0); +} + +GetOptions ( + 'help|h|?' => \&ShowHelp, + 'ipc-socket=s' => \$opt_socketfile + ) or exit(1); + +my $client = IO::Socket::UNIX->new(Peer => $opt_socketfile, + Type => SOCK_STREAM, + Timeout => 10); + +if (not $client) { + print "Error connecting to $opt_socketfile: $@\n"; + exit(1); +} + +my $cmd = shift @ARGV; + +if (not defined($cmd)) { + print "Usage: bitlbee-ctl.pl [options] command ...\n"; + exit(1); +} + +if ($cmd eq "die") { + $client->send("DIE\r\n"); +} else { + print "No such command: $cmd\n"; + exit(1); +} + +$client->close(); -- cgit v1.2.3