/********************************************************************\ * BitlBee -- An IRC to other IM-networks gateway * * * * Copyright 2002-2004 Wilmer van der Gaast and others * \********************************************************************/ /* The IRC-based UI (for now the only one) */ /* 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 */ #include "bitlbee.h" #include "ipc.h" #include "dcc.h" GSList *irc_connection_list; GSList *irc_plugins; static gboolean irc_userping( gpointer _irc, gint fd, b_input_condition cond ); static char *set_eval_charset( set_t *set, char *value ); static char *set_eval_password( set_t *set, char *value ); static char *set_eval_bw_compat( set_t *set, char *value ); irc_t *irc_new( int fd ) { irc_t *irc; struct sockaddr_storage sock; socklen_t socklen = sizeof( sock ); char *host = NULL, *myhost = NULL; irc_user_t *iu; GSList *l; set_t *s; bee_t *b; irc = g_new0( irc_t, 1 ); irc->fd = fd; sock_make_nonblocking( irc->fd ); irc->r_watch_source_id = b_input_add( irc->fd, B_EV_IO_READ, bitlbee_io_current_client_read, irc ); irc->status = USTATUS_OFFLINE; irc->last_pong = gettime(); irc->nick_user_hash = g_hash_table_new( g_str_hash, g_str_equal ); irc->watches = g_hash_table_new( g_str_hash, g_str_equal ); irc->iconv = (GIConv) -1; irc->oconv = (GIConv) -1; if( global.conf->hostname ) { myhost = g_strdup( global.conf->hostname ); } else if( getsockname( irc->fd, (struct sockaddr*) &sock, &socklen ) == 0 ) { char buf[NI_MAXHOST+1]; if( getnameinfo( (struct sockaddr *) &sock, socklen, buf, NI_MAXHOST, NULL, 0, 0 ) == 0 ) { myhost = g_strdup( ipv6_unwrap( buf ) ); } } if( getpeername( irc->fd, (struct sockaddr*) &sock, &socklen ) == 0 ) { char buf[NI_MAXHOST+1]; if( getnameinfo( (struct sockaddr *)&sock, socklen, buf, NI_MAXHOST, NULL, 0, 0 ) == 0 ) { host = g_strdup( ipv6_unwrap( buf ) ); } } if( host == NULL ) host = g_strdup( "localhost.localdomain" ); if( myhost == NULL ) myhost = g_strdup( "localhost.localdomain" ); if( global.conf->ping_interval > 0 && global.conf->ping_timeout > 0 ) irc->ping_source_id = b_timeout_add( global.conf->ping_interval * 1000, irc_userping, irc ); irc_connection_list = g_slist_append( irc_connection_list, irc ); b = irc->b = bee_new(); b->ui_data = irc; b->ui = &irc_ui_funcs; s = set_add( &b->set, "allow_takeover", "true", set_eval_bool, irc ); s = set_add( &b->set, "away_devoice", "true", set_eval_bw_compat, irc ); s->flags |= SET_HIDDEN; s = set_add( &b->set, "away_reply_timeout", "3600", set_eval_int, irc ); s = set_add( &b->set, "charset", "utf-8", set_eval_charset, irc ); s = set_add( &b->set, "default_target", "root", NULL, irc ); s = set_add( &b->set, "display_namechanges", "false", set_eval_bool, irc ); s = set_add( &b->set, "display_timestamps", "true", set_eval_bool, irc ); s = set_add( &b->set, "handle_unknown", "add_channel", NULL, irc ); s = set_add( &b->set, "last_version", "0", NULL, irc ); s->flags |= SET_HIDDEN; s = set_add( &b->set, "lcnicks", "true", set_eval_bool, irc ); s = set_add( &b->set, "nick_format", "%-@nick", NULL, irc ); s = set_add( &b->set, "offline_user_quits", "true", set_eval_bool, irc ); s = set_add( &b->set, "ops", "both", set_eval_irc_channel_ops, irc ); s = set_add( &b->set, "paste_buffer", "false", set_eval_bool, irc ); s->old_key = g_strdup( "buddy_sendbuffer" ); s = set_add( &b->set, "paste_buffer_delay", "200", set_eval_int, irc ); s->old_key = g_strdup( "buddy_sendbuffer_delay" ); s = set_add( &b->set, "password", NULL, set_eval_password, irc ); s->flags |= SET_NULL_OK | SET_PASSWORD; s = set_add( &b->set, "private", "true", set_eval_bool, irc ); s = set_add( &b->set, "query_order", "lifo", NULL, irc ); s = set_add( &b->set, "root_nick", ROOT_NICK, set_eval_root_nick, irc ); s->flags |= SET_HIDDEN; s = set_add( &b->set, "show_offline", "false", set_eval_bw_compat, irc ); s->flags |= SET_HIDDEN; s = set_add( &b->set, "simulate_netsplit", "true", set_eval_bool, irc ); s = set_add( &b->set, "timezone", "local", set_eval_timezone, irc ); s = set_add( &b->set, "to_char", ": ", set_eval_to_char, irc ); s = set_add( &b->set, "typing_notice", "false", set_eval_bool, irc ); irc->root = iu = irc_user_new( irc, ROOT_NICK ); iu->host = g_strdup( myhost ); iu->fullname = g_strdup( ROOT_FN ); iu->f = &irc_user_root_funcs; iu = irc_user_new( irc, NS_NICK ); iu->host = g_strdup( myhost ); iu->fullname = g_strdup( ROOT_FN ); iu->f = &irc_user_root_funcs; irc->user = g_new0( irc_user_t, 1 ); irc->user->host = g_strdup( host ); conf_loaddefaults( irc ); /* Evaluator sets the iconv/oconv structures. */ set_eval_charset( set_find( &b->set, "charset" ), set_getstr( &b->set, "charset" ) ); irc_write( irc, ":%s NOTICE AUTH :%s", irc->root->host, "BitlBee-IRCd initialized, please go on" ); if( isatty( irc->fd ) ) irc_write( irc, ":%s NOTICE AUTH :%s", irc->root->host, "If you read this, you most likely accidentally " "started BitlBee in inetd mode on the command line. " "You probably want to run it in (Fork)Daemon mode. " "See doc/README for more information." ); g_free( myhost ); g_free( host ); /* libpurple doesn't like fork()s after initializing itself, so this is the right moment to initialize it. */ #ifdef WITH_PURPLE nogaim_init(); #endif for( l = irc_plugins; l; l = l->next ) { irc_plugin_t *p = l->data; if( p->irc_new ) p->irc_new( irc ); } 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, ... ) { char *reason = NULL; if( format != NULL ) { va_list params; va_start( params, format ); reason = g_strdup_vprintf( format, params ); va_end( params ); } if( reason ) irc_write( irc, "ERROR :Closing link: %s", reason ); ipc_to_master_str( "OPERMSG :Client exiting: %s@%s [%s]\r\n", irc->user->nick ? irc->user->nick : "(NONE)", irc->user->host, reason ? : "" ); g_free( reason ); irc_flush( irc ); if( immed ) { irc_free( irc ); } else { b_event_remove( irc->ping_source_id ); irc->ping_source_id = b_timeout_add( 1, (b_event_handler) irc_free, irc ); } } static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data ); void irc_free( irc_t * irc ) { GSList *l; irc->status |= USTATUS_SHUTDOWN; log_message( LOGLVL_INFO, "Destroying connection with fd %d", irc->fd ); if( irc->status & USTATUS_IDENTIFIED && set_getbool( &irc->b->set, "save_on_quit" ) ) if( storage_save( irc, NULL, TRUE ) != STORAGE_OK ) log_message( LOGLVL_WARNING, "Error while saving settings for user %s", irc->user->nick ); for( l = irc_plugins; l; l = l->next ) { irc_plugin_t *p = l->data; if( p->irc_free ) p->irc_free( irc ); } irc_connection_list = g_slist_remove( irc_connection_list, irc ); while( irc->queries != NULL ) query_del( irc, irc->queries ); /* This is a little bit messy: bee_free() frees all b->users which calls us back to free the corresponding irc->users. So do this before we clear the remaining ones ourselves. */ bee_free( irc->b ); while( irc->users ) irc_user_free( irc, (irc_user_t *) irc->users->data ); while( irc->channels ) irc_channel_free( irc->channels->data ); if( irc->ping_source_id > 0 ) b_event_remove( irc->ping_source_id ); if( irc->r_watch_source_id > 0 ) b_event_remove( irc->r_watch_source_id ); if( irc->w_watch_source_id > 0 ) b_event_remove( irc->w_watch_source_id ); closesocket( irc->fd ); irc->fd = -1; g_hash_table_foreach_remove( irc->nick_user_hash, irc_free_hashkey, NULL ); g_hash_table_destroy( irc->nick_user_hash ); g_hash_table_foreach_remove( irc->watches, irc_free_hashkey, NULL ); g_hash_table_destroy( irc->watches ); if( irc->iconv != (GIConv) -1 ) g_iconv_close( irc->iconv ); if( irc->oconv != (GIConv) -1 ) g_iconv_close( irc->oconv ); g_free( irc->sendbuffer ); g_free( irc->readbuffer ); g_free( irc->password ); g_free( irc ); if( global.conf->runmode == RUNMODE_INETD || global.conf->runmode == RUNMODE_FORKDAEMON || ( global.conf->runmode == RUNMODE_DAEMON && global.listen_socket == -1 && irc_connection_list == NULL ) ) b_main_quit(); } static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data ) { g_free( key ); return( TRUE ); } /* USE WITH CAUTION! Sets pass without checking */ void irc_setpass (irc_t *irc, const char *pass) { g_free (irc->password); if (pass) { irc->password = g_strdup (pass); } else { irc->password = NULL; } } static char *set_eval_password( set_t *set, char *value ) { irc_t *irc = set->data; if( irc->status & USTATUS_IDENTIFIED && value ) { irc_setpas
#include <aim.h>
#include "admin.h"
/* called for both reply and change-reply */
static int infochange(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
{
/*
* struct {
* guint16 perms;
* guint16 tlvcount;
* aim_tlv_t tlvs[tlvcount];
* } admin_info[n];
*/
while (aim_bstream_empty(bs)) {
guint16 perms, tlvcount;
perms = aimbs_get16(bs);
tlvcount = aimbs_get16(bs);
while (tlvcount && aim_bstream_empty(bs)) {
aim_rxcallback_t userfunc;
guint16 type, len;
guint8 *val;
int str = 0;
type = aimbs_get16(bs);
len = aimbs_get16(bs);
if ((type == 0x0011) || (type == 0x0004))
str = 1;
if (str)
val = (guint8 *)aimbs_getstr(bs, len);
else
val = aimbs_getraw(bs, len);
/* XXX fix so its only called once for the entire packet */
if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
userfunc(sess, rx, (snac->subtype == 0x0005) ? 1 : 0, perms, type, len, val, str);
g_free(val);
tlvcount--;
}
}
return 1;
}
static int accountconfirm(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
{
aim_rxcallback_t userfunc;
guint16 status;
status = aimbs_get16(bs);
if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
return userfunc(sess, rx, status);
return 0;
}
static int s