diff options
Diffstat (limited to 'protocols/nogaim.c')
| -rw-r--r-- | protocols/nogaim.c | 831 | 
1 files changed, 447 insertions, 384 deletions
| diff --git a/protocols/nogaim.c b/protocols/nogaim.c index 04d48236..3ce15166 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -1,7 +1,7 @@    /********************************************************************\    * BitlBee -- An IRC to other IM-networks gateway                     *    *                                                                    * -  * Copyright 2002-2004 Wilmer van der Gaast and others                * +  * Copyright 2002-2006 Wilmer van der Gaast and others                *    \********************************************************************/  /* @@ -12,8 +12,6 @@   * This file contains functions called by the Gaim IM-modules. It's written   * from scratch for BitlBee and doesn't contain any code from Gaim anymore   * (except for the function names). - * - * Copyright 2002-2006 Wilmer van der Gaast <wilmer@gaast.net> and others   */  /* @@ -37,7 +35,7 @@  #include "nogaim.h"  #include <ctype.h> -static int remove_chat_buddy_silent( struct conversation *b, char *handle ); +static int remove_chat_buddy_silent( struct groupchat *b, const char *handle );  GSList *connections; @@ -49,7 +47,7 @@ gboolean load_plugin(char *path)  	GModule *mod = g_module_open(path, G_MODULE_BIND_LAZY);  	if(!mod) { -		log_message(LOGLVL_ERROR, "Can't find `%s', not loading", path); +		log_message(LOGLVL_ERROR, "Can't find `%s', not loading (%s)\n", path, g_module_error());  		return FALSE;  	} @@ -100,7 +98,6 @@ void register_protocol (struct prpl *p)  	protocols = g_list_append(protocols, p);  } -   struct prpl *find_protocol(const char *name)  {  	GList *gl; @@ -116,25 +113,25 @@ struct prpl *find_protocol(const char *name)  /* nogaim.c */  void nogaim_init()  { -	extern void msn_init(); -	extern void oscar_init(); -	extern void byahoo_init(); -	extern void jabber_init(); +	extern void msn_initmodule(); +	extern void oscar_initmodule(); +	extern void byahoo_initmodule(); +	extern void jabber_initmodule();  #ifdef WITH_MSN -	msn_init(); +	msn_initmodule();  #endif  #ifdef WITH_OSCAR -	oscar_init(); +	oscar_initmodule();  #endif  #ifdef WITH_YAHOO -	byahoo_init(); +	byahoo_initmodule();  #endif  #ifdef WITH_JABBER -	jabber_init(); +	jabber_initmodule();  #endif  #ifdef WITH_PLUGINS @@ -146,72 +143,38 @@ GSList *get_connections() { return connections; }  /* multi.c */ -struct gaim_connection *new_gaim_conn( struct aim_user *user ) +struct im_connection *imcb_new( account_t *acc )  { -	struct gaim_connection *gc; -	account_t *a; -	 -	gc = g_new0( struct gaim_connection, 1 ); +	struct im_connection *ic; -	gc->prpl = user->prpl; -	g_snprintf( gc->username, sizeof( gc->username ), "%s", user->username ); -	g_snprintf( gc->password, sizeof( gc->password ), "%s", user->password ); -	/* [MD]	BUGFIX: don't set gc->irc to the global IRC, but use the one from the struct aim_user. -	 * This fixes daemon mode breakage where IRC doesn't point to the currently active connection. -	 */ -	gc->irc=user->irc; +	ic = g_new0( struct im_connection, 1 ); -	connections = g_slist_append( connections, gc ); +	ic->irc = acc->irc; +	ic->acc = acc; +	acc->ic = ic; -	user->gc = gc; -	gc->user = user; +	connections = g_slist_append( connections, ic ); -	// Find the account_t so we can set its gc pointer -	for( a = gc->irc->accounts; a; a = a->next ) -		if( ( struct aim_user * ) a->gc == user ) -		{ -			a->gc = gc; -			break; -		} -	 -	return( gc ); +	return( ic );  } -void destroy_gaim_conn( struct gaim_connection *gc ) +void imc_free( struct im_connection *ic )  {  	account_t *a;  	/* Destroy the pointer to this connection from the account list */ -	for( a = gc->irc->accounts; a; a = a->next ) -		if( a->gc == gc ) +	for( a = ic->irc->accounts; a; a = a->next ) +		if( a->ic == ic )  		{ -			a->gc = NULL; +			a->ic = NULL;  			break;  		} -	connections = g_slist_remove( connections, gc ); -	g_free( gc->user ); -	g_free( gc ); -} - -void set_login_progress( struct gaim_connection *gc, int step, char *msg ) -{ -	serv_got_crap( gc, "Logging in: %s", msg ); -} - -/* Errors *while* logging in */ -void hide_login_progress( struct gaim_connection *gc, char *msg ) -{ -	serv_got_crap( gc, "Login error: %s", msg ); -} - -/* Errors *after* logging in */ -void hide_login_progress_error( struct gaim_connection *gc, char *msg ) -{ -	serv_got_crap( gc, "Logged out: %s", msg ); +	connections = g_slist_remove( connections, ic ); +	g_free( ic );  } -void serv_got_crap( struct gaim_connection *gc, char *format, ... ) +static void serv_got_crap( struct im_connection *ic, char *format, ... )  {  	va_list params;  	char *text; @@ -221,57 +184,91 @@ void serv_got_crap( struct gaim_connection *gc, char *format, ... )  	text = g_strdup_vprintf( format, params );  	va_end( params ); -	if( ( g_strcasecmp( set_getstr( gc->irc, "strip_html" ), "always" ) == 0 ) || -	    ( ( gc->flags & OPT_CONN_HTML ) && set_getint( gc->irc, "strip_html" ) ) ) +	if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) || +	    ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )  		strip_html( text );  	/* Try to find a different connection on the same protocol. */ -	for( a = gc->irc->accounts; a; a = a->next ) -		if( a->prpl == gc->prpl && a->gc != gc ) +	for( a = ic->irc->accounts; a; a = a->next ) +		if( a->prpl == ic->acc->prpl && a->ic != ic )  			break;  	/* If we found one, include the screenname in the message. */  	if( a ) -		irc_usermsg( gc->irc, "%s(%s) - %s", gc->prpl->name, gc->username, text ); +		irc_usermsg( ic->irc, "%s(%s) - %s", ic->acc->prpl->name, ic->acc->user, text ); +	else +		irc_usermsg( ic->irc, "%s - %s", ic->acc->prpl->name, text ); +	 +	g_free( text ); +} + +void imcb_log( struct im_connection *ic, char *format, ... ) +{ +	va_list params; +	char *text; +	 +	va_start( params, format ); +	text = g_strdup_vprintf( format, params ); +	va_end( params ); +	 +	if( ic->flags & OPT_LOGGED_IN ) +		serv_got_crap( ic, "%s", text ); +	else +		serv_got_crap( ic, "Logging in: %s", text ); +	 +	g_free( text ); +} + +void imcb_error( struct im_connection *ic, char *format, ... ) +{ +	va_list params; +	char *text; +	 +	va_start( params, format ); +	text = g_strdup_vprintf( format, params ); +	va_end( params ); +	 +	if( ic->flags & OPT_LOGGED_IN ) +		serv_got_crap( ic, "Error: %s", text );  	else -		irc_usermsg( gc->irc, "%s - %s", gc->prpl->name, text ); +		serv_got_crap( ic, "Couldn't log in: %s", text );  	g_free( text );  } -static gboolean send_keepalive( gpointer d ) +static gboolean send_keepalive( gpointer d, gint fd, b_input_condition cond )  { -	struct gaim_connection *gc = d; +	struct im_connection *ic = d; -	if( gc->prpl && gc->prpl->keepalive ) -		gc->prpl->keepalive( gc ); +	if( ic->acc->prpl->keepalive ) +		ic->acc->prpl->keepalive( ic );  	return TRUE;  } -void account_online( struct gaim_connection *gc ) +void imcb_connected( struct im_connection *ic )  {  	user_t *u;  	/* MSN servers sometimes redirect you to a different server and do  	   the whole login sequence again, so these "late" calls to this  	   function should be handled correctly. (IOW, ignored) */ -	if( gc->flags & OPT_LOGGED_IN ) +	if( ic->flags & OPT_LOGGED_IN )  		return; -	u = user_find( gc->irc, gc->irc->nick ); +	u = user_find( ic->irc, ic->irc->nick ); -	serv_got_crap( gc, "Logged in" ); +	imcb_log( ic, "Logged in" ); -	gc->keepalive = g_timeout_add( 60000, send_keepalive, gc ); -	gc->flags |= OPT_LOGGED_IN; +	ic->keepalive = b_timeout_add( 60000, send_keepalive, ic ); +	ic->flags |= OPT_LOGGED_IN;  	/* Also necessary when we're not away, at least for some of the  	   protocols. */ -	bim_set_away( gc, u->away ); +	imc_set_away( ic, u->away );  } -gboolean auto_reconnect( gpointer data ) +gboolean auto_reconnect( gpointer data, gint fd, b_input_condition cond )  {  	account_t *a = data; @@ -283,26 +280,34 @@ gboolean auto_reconnect( gpointer data )  void cancel_auto_reconnect( account_t *a )  { -	while( g_source_remove_by_user_data( (gpointer) a ) ); +	b_event_remove( a->reconnect );  	a->reconnect = 0;  } -void signoff( struct gaim_connection *gc ) +void imc_logout( struct im_connection *ic, int allow_reconnect )  { -	irc_t *irc = gc->irc; -	user_t *t, *u = irc->users; +	irc_t *irc = ic->irc; +	user_t *t, *u;  	account_t *a; -	serv_got_crap( gc, "Signing off.." ); - -	gaim_input_remove( gc->keepalive ); -	gc->keepalive = 0; -	gc->prpl->close( gc ); -	gaim_input_remove( gc->inpa ); +	/* Nested calls might happen sometimes, this is probably the best +	   place to catch them. */ +	if( ic->flags & OPT_LOGGING_OUT ) +		return; +	else +		ic->flags |= OPT_LOGGING_OUT; +	 +	imcb_log( ic, "Signing off.." ); +	 +	b_event_remove( ic->keepalive ); +	ic->keepalive = 0; +	ic->acc->prpl->logout( ic ); +	b_event_remove( ic->inpa ); +	u = irc->users;  	while( u )  	{ -		if( u->gc == gc ) +		if( u->ic == ic )  		{  			t = u->next;  			user_del( irc, u->nick ); @@ -312,94 +317,74 @@ void signoff( struct gaim_connection *gc )  			u = u->next;  	} -	query_del_by_gc( gc->irc, gc ); +	query_del_by_conn( ic->irc, ic );  	for( a = irc->accounts; a; a = a->next ) -		if( a->gc == gc ) +		if( a->ic == ic )  			break;  	if( !a )  	{  		/* Uhm... This is very sick. */  	} -	else if( !gc->wants_to_die && set_getint( irc, "auto_reconnect" ) ) +	else if( allow_reconnect && set_getbool( &irc->set, "auto_reconnect" ) && +	         set_getbool( &a->set, "auto_reconnect" ) )  	{ -		int delay = set_getint( irc, "auto_reconnect_delay" ); -		serv_got_crap( gc, "Reconnecting in %d seconds..", delay ); +		int delay = set_getint( &irc->set, "auto_reconnect_delay" ); -		a->reconnect = 1; -		g_timeout_add( delay * 1000, auto_reconnect, a ); +		imcb_log( ic, "Reconnecting in %d seconds..", delay ); +		a->reconnect = b_timeout_add( delay * 1000, auto_reconnect, a );  	} -	destroy_gaim_conn( gc ); +	imc_free( ic );  }  /* dialogs.c */ -void do_error_dialog( struct gaim_connection *gc, char *msg, char *title ) +void imcb_ask( struct im_connection *ic, char *msg, void *data, void *doit, void *dont )  { -	if( msg && title ) -		serv_got_crap( gc, "Error: %s: %s", title, msg ); -	else if( msg ) -		serv_got_crap( gc, "Error: %s", msg ); -	else if( title ) -		serv_got_crap( gc, "Error: %s", title ); -	else -		serv_got_crap( gc, "Error" ); -} - -void do_ask_dialog( struct gaim_connection *gc, char *msg, void *data, void *doit, void *dont ) -{ -	query_add( gc->irc, gc, msg, doit, dont, data ); +	query_add( ic->irc, ic, msg, doit, dont, data );  }  /* list.c */ -void add_buddy( struct gaim_connection *gc, char *group, char *handle, char *realname ) +void imcb_add_buddy( struct im_connection *ic, char *handle, char *group )  {  	user_t *u; -	char nick[MAX_NICK_LENGTH+1]; -	char *s; -	irc_t *irc = gc->irc; -	 -	if( set_getint( irc, "debug" ) && 0 ) /* This message is too useless */ -		serv_got_crap( gc, "Receiving user add from handle: %s", handle ); +	char nick[MAX_NICK_LENGTH+1], *s; +	irc_t *irc = ic->irc; -	if( user_findhandle( gc, handle ) ) +	if( user_findhandle( ic, handle ) )  	{ -		if( set_getint( irc, "debug" ) ) -			serv_got_crap( gc, "User already exists, ignoring add request: %s", handle ); +		if( set_getbool( &irc->set, "debug" ) ) +			imcb_log( ic, "User already exists, ignoring add request: %s", handle );  		return; -		/* Buddy seems to exist already. Let's ignore this request then... */ +		/* Buddy seems to exist already. Let's ignore this request then... +		   Eventually subsequent calls to this function *should* be possible +		   when a buddy is in multiple groups. But for now BitlBee doesn't +		   even support groups so let's silently ignore this for now. */  	}  	memset( nick, 0, MAX_NICK_LENGTH + 1 ); -	strcpy( nick, nick_get( gc->irc, handle, gc->prpl, realname ) ); +	strcpy( nick, nick_get( ic->acc, handle ) ); -	u = user_add( gc->irc, nick ); +	u = user_add( ic->irc, nick ); -	if( !realname || !*realname ) realname = nick; -	u->realname = g_strdup( realname ); +//	if( !realname || !*realname ) realname = nick; +//	u->realname = g_strdup( realname );  	if( ( s = strchr( handle, '@' ) ) )  	{  		u->host = g_strdup( s + 1 );  		u->user = g_strndup( handle, s - handle );  	} -	else if( gc->user->proto_opt[0] && *gc->user->proto_opt[0] ) +	else if( ic->acc->server )  	{ -		char *colon; -		 -		if( ( colon = strchr( gc->user->proto_opt[0], ':' ) ) ) -			u->host = g_strndup( gc->user->proto_opt[0], -			                     colon - gc->user->proto_opt[0] ); -		else -			u->host = g_strdup( gc->user->proto_opt[0] ); -		 +		u->host = g_strdup( ic->acc->server );  		u->user = g_strdup( handle );  		/* s/ /_/ ... important for AOL screennames */ @@ -409,47 +394,41 @@ void add_buddy( struct gaim_connection *gc, char *group, char *handle, char *rea  	}  	else  	{ -		u->host = g_strdup( gc->user->prpl->name ); +		u->host = g_strdup( ic->acc->prpl->name );  		u->user = g_strdup( handle );  	} -	u->gc = gc; +	u->ic = ic;  	u->handle = g_strdup( handle );  	if( group ) u->group = g_strdup( group );  	u->send_handler = buddy_send_handler;  	u->last_typing_notice = 0;  } -struct buddy *find_buddy( struct gaim_connection *gc, char *handle ) +struct buddy *imcb_find_buddy( struct im_connection *ic, char *handle )  {  	static struct buddy b[1];  	user_t *u; -	u = user_findhandle( gc, handle ); +	u = user_findhandle( ic, handle );  	if( !u )  		return( NULL ); - +	  	memset( b, 0, sizeof( b ) );  	strncpy( b->name, handle, 80 );  	strncpy( b->show, u->realname, BUDDY_ALIAS_MAXLEN );  	b->present = u->online; -	b->gc = u->gc; +	b->ic = u->ic;  	return( b );  } -void signoff_blocked( struct gaim_connection *gc ) +void imcb_rename_buddy( struct im_connection *ic, char *handle, char *realname )  { -	return; /* Make all blocked users look invisible (TODO?) */ -} - - -void serv_buddy_rename( struct gaim_connection *gc, char *handle, char *realname ) -{ -	user_t *u = user_findhandle( gc, handle ); +	user_t *u = user_findhandle( ic, handle ); -	if( !u ) return; +	if( !u || !realname ) return;  	if( g_strcasecmp( u->realname, realname ) != 0 )  	{ @@ -457,17 +436,61 @@ void serv_buddy_rename( struct gaim_connection *gc, char *handle, char *realname  		u->realname = g_strdup( realname ); -		if( ( gc->flags & OPT_LOGGED_IN ) && set_getint( gc->irc, "display_namechanges" ) ) -			serv_got_crap( gc, "User `%s' changed name to `%s'", u->nick, u->realname ); +		if( ( ic->flags & OPT_LOGGED_IN ) && set_getbool( &ic->irc->set, "display_namechanges" ) ) +			imcb_log( ic, "User `%s' changed name to `%s'", u->nick, u->realname );  	}  } +void imcb_remove_buddy( struct im_connection *ic, char *handle, char *group ) +{ +	user_t *u; +	 +	if( ( u = user_findhandle( ic, handle ) ) ) +		user_del( ic->irc, u->nick ); +} + +/* Mainly meant for ICQ (and now also for Jabber conferences) to allow IM +   modules to suggest a nickname for a handle. */ +void imcb_buddy_nick_hint( struct im_connection *ic, char *handle, char *nick ) +{ +	user_t *u = user_findhandle( ic, handle ); +	char newnick[MAX_NICK_LENGTH+1], *orig_nick; +	 +	if( u && !u->online && !nick_saved( ic->acc, handle ) ) +	{ +		/* Only do this if the person isn't online yet (which should +		   be the case if we just added it) and if the user hasn't +		   assigned a nickname to this buddy already. */ +		 +		strncpy( newnick, nick, MAX_NICK_LENGTH ); +		newnick[MAX_NICK_LENGTH] = 0; +		 +		/* Some processing to make sure this string is a valid IRC nickname. */ +		nick_strip( newnick ); +		if( set_getbool( &ic->irc->set, "lcnicks" ) ) +			nick_lc( newnick ); +		 +		if( strcmp( u->nick, newnick ) != 0 ) +		{ +			/* Only do this if newnick is different from the current one. +			   If rejoining a channel, maybe we got this nick already +			   (and dedupe would only add an underscore. */ +			nick_dedupe( ic->acc, handle, newnick ); +			 +			/* u->nick will be freed halfway the process, so it can't be +			   passed as an argument. */ +			orig_nick = g_strdup( u->nick ); +			user_rename( ic->irc, orig_nick, newnick ); +			g_free( orig_nick ); +		} +	} +}  /* prpl.c */  struct show_got_added_data  { -	struct gaim_connection *gc; +	struct im_connection *ic;  	char *handle;  }; @@ -479,57 +502,56 @@ void show_got_added_no( gpointer w, struct show_got_added_data *data )  void show_got_added_yes( gpointer w, struct show_got_added_data *data )  { -	data->gc->prpl->add_buddy( data->gc, data->handle ); -	add_buddy( data->gc, NULL, data->handle, data->handle ); +	data->ic->acc->prpl->add_buddy( data->ic, data->handle, NULL ); +	/* imcb_add_buddy( data->ic, NULL, data->handle, data->handle ); */  	return show_got_added_no( w, data );  } -void show_got_added( struct gaim_connection *gc, char *handle, const char *realname ) +void imcb_ask_add( struct im_connection *ic, char *handle, const char *realname )  {  	struct show_got_added_data *data = g_new0( struct show_got_added_data, 1 );  	char *s;  	/* TODO: Make a setting for this! */ -	if( user_findhandle( gc, handle ) != NULL ) +	if( user_findhandle( ic, handle ) != NULL )  		return;  	s = g_strdup_printf( "The user %s is not in your buddy list yet. Do you want to add him/her now?", handle ); -	data->gc = gc; +	data->ic = ic;  	data->handle = g_strdup( handle ); -	query_add( gc->irc, gc, s, show_got_added_yes, show_got_added_no, data ); +	query_add( ic->irc, ic, s, show_got_added_yes, show_got_added_no, data );  }  /* server.c */                     -void serv_got_update( struct gaim_connection *gc, char *handle, int loggedin, int evil, time_t signon, time_t idle, int type, guint caps ) +void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, const char *state, const char *message )  {  	user_t *u;  	int oa, oo; -	u = user_findhandle( gc, handle ); +	u = user_findhandle( ic, (char*) handle );  	if( !u )  	{ -		if( g_strcasecmp( set_getstr( gc->irc, "handle_unknown" ), "add" ) == 0 ) +		if( g_strcasecmp( set_getstr( &ic->irc->set, "handle_unknown" ), "add" ) == 0 )  		{ -			add_buddy( gc, NULL, handle, NULL ); -			u = user_findhandle( gc, handle ); +			imcb_add_buddy( ic, (char*) handle, NULL ); +			u = user_findhandle( ic, (char*) handle );  		}  		else  		{ -			if( set_getint( gc->irc, "debug" ) || g_strcasecmp( set_getstr( gc->irc, "handle_unknown" ), "ignore" ) != 0 ) +			if( set_getbool( &ic->irc->set, "debug" ) || g_strcasecmp( set_getstr( &ic->irc->set, "handle_unknown" ), "ignore" ) != 0 )  			{ -				serv_got_crap( gc, "serv_got_update() for handle %s:", handle ); -				serv_got_crap( gc, "loggedin = %d, type = %d", loggedin, type ); +				imcb_log( ic, "imcb_buddy_status() for unknown handle %s:", handle ); +				imcb_log( ic, "flags = %d, state = %s, message = %s", flags, +				          state ? state : "NULL", message ? message : "NULL" );  			}  			return;  		} -		/* Why did we have this here.... -		return; */  	}  	oa = u->away != NULL; @@ -541,75 +563,89 @@ void serv_got_update( struct gaim_connection *gc, char *handle, int loggedin, in  		u->away = NULL;  	} -	if( loggedin && !u->online ) +	if( ( flags & OPT_LOGGED_IN ) && !u->online )  	{ -		irc_spawn( gc->irc, u ); +		irc_spawn( ic->irc, u );  		u->online = 1;  	} -	else if( !loggedin && u->online ) +	else if( !( flags & OPT_LOGGED_IN ) && u->online )  	{ -		struct conversation *c; +		struct groupchat *c; -		irc_kill( gc->irc, u ); +		irc_kill( ic->irc, u );  		u->online = 0; -		/* Remove him/her from the conversations to prevent PART messages after he/she QUIT already */ -		for( c = gc->conversations; c; c = c->next ) +		/* Remove him/her from the groupchats to prevent PART messages after he/she QUIT already */ +		for( c = ic->groupchats; c; c = c->next )  			remove_chat_buddy_silent( c, handle );  	} -	if( ( type & UC_UNAVAILABLE ) && ( !strcmp(gc->prpl->name, "oscar") || !strcmp(gc->prpl->name, "icq")) ) -	{ -		u->away = g_strdup( "Away" ); -	} -	else if( ( type & UC_UNAVAILABLE ) && ( !strcmp(gc->prpl->name, "jabber") ) ) +	if( flags & OPT_AWAY )  	{ -		if( type & UC_DND ) -			u->away = g_strdup( "Do Not Disturb" ); -		else if( type & UC_XA ) -			u->away = g_strdup( "Extended Away" ); -		else // if( type & UC_AWAY ) +		if( state && message ) +		{ +			u->away = g_strdup_printf( "%s (%s)", state, message ); +		} +		else if( state ) +		{ +			u->away = g_strdup( state ); +		} +		else if( message ) +		{ +			u->away = g_strdup( message ); +		} +		else +		{  			u->away = g_strdup( "Away" ); +		}  	} -	else if( ( type & UC_UNAVAILABLE ) && gc->prpl->get_status_string ) -	{ -		u->away = g_strdup( gc->prpl->get_status_string( gc, type ) ); -	} -	else -		u->away = NULL; +	/* else waste_any_state_information_for_now(); */  	/* LISPy... */ -	if( ( set_getint( gc->irc, "away_devoice" ) ) &&		/* Don't do a thing when user doesn't want it */ +	if( ( set_getbool( &ic->irc->set, "away_devoice" ) ) &&		/* Don't do a thing when user doesn't want it */  	    ( u->online ) &&						/* Don't touch offline people */  	    ( ( ( u->online != oo ) && !u->away ) ||			/* Voice joining people */  	      ( ( u->online == oo ) && ( oa == !u->away ) ) ) )		/* (De)voice people changing state */  	{ -		irc_write( gc->irc, ":%s!%s@%s MODE %s %cv %s", gc->irc->mynick, gc->irc->mynick, gc->irc->myhost, -		                                                gc->irc->channel, u->away?'-':'+', u->nick ); +		char *from; +		 +		if( set_getbool( &ic->irc->set, "simulate_netsplit" ) ) +		{ +			from = g_strdup( ic->irc->myhost ); +		} +		else +		{ +			from = g_strdup_printf( "%s!%s@%s", ic->irc->mynick, ic->irc->mynick, +			                                    ic->irc->myhost ); +		} +		irc_write( ic->irc, ":%s MODE %s %cv %s", from, ic->irc->channel, +		                                          u->away?'-':'+', u->nick ); +		g_free( from );  	}  } -void serv_got_im( struct gaim_connection *gc, char *handle, char *msg, guint32 flags, time_t mtime, gint len ) +void imcb_buddy_msg( struct im_connection *ic, char *handle, char *msg, uint32_t flags, time_t sent_at )  { -	irc_t *irc = gc->irc; +	irc_t *irc = ic->irc; +	char *wrapped;  	user_t *u; -	u = user_findhandle( gc, handle ); +	u = user_findhandle( ic, handle );  	if( !u )  	{ -		char *h = set_getstr( irc, "handle_unknown" ); +		char *h = set_getstr( &irc->set, "handle_unknown" );  		if( g_strcasecmp( h, "ignore" ) == 0 )  		{ -			if( set_getint( irc, "debug" ) ) -				serv_got_crap( gc, "Ignoring message from unknown handle %s", handle ); +			if( set_getbool( &irc->set, "debug" ) ) +				imcb_log( ic, "Ignoring message from unknown handle %s", handle );  			return;  		}  		else if( g_strncasecmp( h, "add", 3 ) == 0 )  		{ -			int private = set_getint( irc, "private" ); +			int private = set_getbool( &irc->set, "private" );  			if( h[3] )  			{ @@ -619,84 +655,75 @@ void serv_got_im( struct gaim_connection *gc, char *handle, char *msg, guint32 f  					private = 0;  			} -			add_buddy( gc, NULL, handle, NULL ); -			u = user_findhandle( gc, handle ); +			imcb_add_buddy( ic, handle, NULL ); +			u = user_findhandle( ic, handle );  			u->is_private = private;  		}  		else  		{ -			serv_got_crap( gc, "Message from unknown handle %s:", handle ); +			imcb_log( ic, "Message from unknown handle %s:", handle );  			u = user_find( irc, irc->mynick );  		}  	} -	if( ( g_strcasecmp( set_getstr( gc->irc, "strip_html" ), "always" ) == 0 ) || -	    ( ( gc->flags & OPT_CONN_HTML ) && set_getint( gc->irc, "strip_html" ) ) ) +	if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) || +	    ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )  		strip_html( msg ); -	while( strlen( msg ) > 425 ) +	wrapped = word_wrap( msg, 425 ); +	irc_msgfrom( irc, u->nick, wrapped ); +	g_free( wrapped ); +} + +void imcb_buddy_typing( struct im_connection *ic, char *handle, uint32_t flags ) +{ +	user_t *u; +	 +	if( !set_getbool( &ic->irc->set, "typing_notice" ) ) +		return; +	 +	if( ( u = user_findhandle( ic, handle ) ) )  	{ -		char tmp, *nl; -		 -		tmp = msg[425]; -		msg[425] = 0; -		 -		/* If there's a newline/space in this string, split up there, -		   looks a bit prettier. */ -		if( ( nl = strrchr( msg, '\n' ) ) || ( nl = strrchr( msg, ' ' ) ) ) -		{ -			msg[425] = tmp; -			tmp = *nl; -			*nl = 0; -		} +		char buf[256];  -		irc_msgfrom( irc, u->nick, msg ); -		 -		/* Move on. */ -		if( nl ) -		{ -			*nl = tmp; -			msg = nl + 1; -		} -		else -		{ -			msg[425] = tmp; -			msg += 425; -		} +		g_snprintf( buf, 256, "\1TYPING %d\1", ( flags >> 8 ) & 3 ); +		irc_privmsg( ic->irc, u, "PRIVMSG", ic->irc->nick, NULL, buf );  	} -	irc_msgfrom( irc, u->nick, msg );  } -void serv_got_typing( struct gaim_connection *gc, char *handle, int timeout, int type ) +struct groupchat *imcb_chat_new( struct im_connection *ic, char *handle )  { -	user_t *u; +	struct groupchat *c; -	if( !set_getint( gc->irc, "typing_notice" ) ) -		return; +	/* This one just creates the conversation structure, user won't see anything yet */ -	if( ( u = user_findhandle( gc, handle ) ) ) { -		/* If type is: -		 * 0: user has stopped typing -		 * 1: user is actively typing -		 * 2: user has entered text, but is not actively typing -		 */ -		if (type == 0 || type == 1 || type == 2) { -			char buf[256];  -			g_snprintf(buf, 256, "\1TYPING %d\1", type);  -			irc_privmsg( gc->irc, u, "PRIVMSG", gc->irc->nick, NULL, buf ); -		} +	if( ic->groupchats ) +	{ +		for( c = ic->groupchats; c->next; c = c->next ); +		c = c->next = g_new0( struct groupchat, 1 );  	} +	else +		ic->groupchats = c = g_new0( struct groupchat, 1 ); +	 +	c->ic = ic; +	c->title = g_strdup( handle ); +	c->channel = g_strdup_printf( "&chat_%03d", ic->irc->c_id++ ); +	c->topic = g_strdup_printf( "BitlBee groupchat: \"%s\". Please keep in mind that root-commands won't work here. Have fun!", c->title ); +	 +	if( set_getbool( &ic->irc->set, "debug" ) ) +		imcb_log( ic, "Creating new conversation: (id=%p,handle=%s)", c, handle ); +	 +	return c;  } -void serv_got_chat_left( struct gaim_connection *gc, int id ) +void imcb_chat_free( struct groupchat *c )  { -	struct conversation *c, *l = NULL; +	struct im_connection *ic = c->ic; +	struct groupchat *l;  	GList *ir; -	if( set_getint( gc->irc, "debug" ) ) -		serv_got_crap( gc, "You were removed from conversation %d", (int) id ); -	 -	for( c = gc->conversations; c && c->id != id; c = (l=c)->next ); +	if( set_getbool( &ic->irc->set, "debug" ) ) +		imcb_log( ic, "You were removed from conversation %p", c );  	if( c )  	{ @@ -704,97 +731,118 @@ void serv_got_chat_left( struct gaim_connection *gc, int id )  		{  			user_t *u, *r; -			r = user_find( gc->irc, gc->irc->mynick ); -			irc_privmsg( gc->irc, r, "PRIVMSG", c->channel, "", "Cleaning up channel, bye!" ); +			r = user_find( ic->irc, ic->irc->mynick ); +			irc_privmsg( ic->irc, r, "PRIVMSG", c->channel, "", "Cleaning up channel, bye!" ); -			u = user_find( gc->irc, gc->irc->nick ); -			irc_kick( gc->irc, u, c->channel, r ); -			/* irc_part( gc->irc, u, c->channel ); */ +			u = user_find( ic->irc, ic->irc->nick ); +			irc_kick( ic->irc, u, c->channel, r ); +			/* irc_part( ic->irc, u, c->channel ); */  		} +		/* Find the previous chat in the linked list. */ +		for( l = ic->groupchats; l && l->next != c; l = l->next ); +		  		if( l )  			l->next = c->next;  		else -			gc->conversations = c->next; +			ic->groupchats = c->next;  		for( ir = c->in_room; ir; ir = ir->next )  			g_free( ir->data );  		g_list_free( c->in_room );  		g_free( c->channel );  		g_free( c->title ); +		g_free( c->topic );  		g_free( c );  	}  } -void serv_got_chat_in( struct gaim_connection *gc, int id, char *who, int whisper, char *msg, time_t mtime ) +void imcb_chat_msg( struct groupchat *c, char *who, char *msg, uint32_t flags, time_t sent_at )  { -	struct conversation *c; +	struct im_connection *ic = c->ic; +	char *wrapped;  	user_t *u;  	/* Gaim sends own messages through this too. IRC doesn't want this, so kill them */ -	if( g_strcasecmp( who, gc->user->username ) == 0 ) +	if( g_strcasecmp( who, ic->acc->user ) == 0 )  		return; -	u = user_findhandle( gc, who ); -	for( c = gc->conversations; c && c->id != id; c = c->next ); +	u = user_findhandle( ic, who ); -	if( ( g_strcasecmp( set_getstr( gc->irc, "strip_html" ), "always" ) == 0 ) || -	    ( ( gc->flags & OPT_CONN_HTML ) && set_getint( gc->irc, "strip_html" ) ) ) +	if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) || +	    ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )  		strip_html( msg ); +	wrapped = word_wrap( msg, 425 );  	if( c && u ) -		irc_privmsg( gc->irc, u, "PRIVMSG", c->channel, "", msg ); +	{ +		irc_privmsg( ic->irc, u, "PRIVMSG", c->channel, "", wrapped ); +	}  	else -		serv_got_crap( gc, "Message from/to conversation %s@%d (unknown conv/user): %s", who, id, msg ); +	{ +		imcb_log( ic, "Message from/to conversation %s@%p (unknown conv/user): %s", who, c, wrapped ); +	} +	g_free( wrapped );  } -struct conversation *serv_got_joined_chat( struct gaim_connection *gc, int id, char *handle ) +void imcb_chat_log( struct groupchat *c, char *format, ... )  { -	struct conversation *c; -	char *s; +	irc_t *irc = c->ic->irc; +	va_list params; +	char *text; +	user_t *u; -	/* This one just creates the conversation structure, user won't see anything yet */ +	va_start( params, format ); +	text = g_strdup_vprintf( format, params ); +	va_end( params ); -	if( gc->conversations ) -	{ -		for( c = gc->conversations; c->next; c = c->next ); -		c = c->next = g_new0( struct conversation, 1 ); -	} -	else -		gc->conversations = c = g_new0( struct conversation, 1); +	u = user_find( irc, irc->mynick ); -	c->id = id; -	c->gc = gc; -	c->title = g_strdup( handle ); +	irc_privmsg( irc, u, "PRIVMSG", c->channel, "System message: ", text ); -	s = g_new( char, 16 ); -	sprintf( s, "&chat_%03d", gc->irc->c_id++ ); -	c->channel = g_strdup( s ); -	g_free( s ); +	g_free( text ); +} + +void imcb_chat_topic( struct groupchat *c, char *who, char *topic, time_t set_at ) +{ +	struct im_connection *ic = c->ic; +	user_t *u = NULL; -	if( set_getint( gc->irc, "debug" ) ) -		serv_got_crap( gc, "Creating new conversation: (id=%d,handle=%s)", id, handle ); +	if( who == NULL) +		u = user_find( ic->irc, ic->irc->mynick ); +	else if( g_strcasecmp( who, ic->acc->user ) == 0 ) +		u = user_find( ic->irc, ic->irc->nick ); +	else +		u = user_findhandle( ic, who ); -	return( c ); +	if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) || +	    ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) ) +		strip_html( topic ); +	 +	g_free( c->topic ); +	c->topic = g_strdup( topic ); +	 +	if( c->joined && u ) +		irc_write( ic->irc, ":%s!%s@%s TOPIC %s :%s", u->nick, u->user, u->host, c->channel, topic );  }  /* buddy_chat.c */ -void add_chat_buddy( struct conversation *b, char *handle ) +void imcb_chat_add_buddy( struct groupchat *b, char *handle )  { -	user_t *u = user_findhandle( b->gc, handle ); +	user_t *u = user_findhandle( b->ic, handle );  	int me = 0; -	if( set_getint( b->gc->irc, "debug" ) ) -		serv_got_crap( b->gc, "User %s added to conversation %d", handle, b->id ); +	if( set_getbool( &b->ic->irc->set, "debug" ) ) +		imcb_log( b->ic, "User %s added to conversation %p", handle, b );  	/* It might be yourself! */ -	if( b->gc->prpl->cmp_buddynames( handle, b->gc->user->username ) == 0 ) +	if( b->ic->acc->prpl->handle_cmp( handle, b->ic->acc->user ) == 0 )  	{ -		u = user_find( b->gc->irc, b->gc->irc->nick ); +		u = user_find( b->ic->irc, b->ic->irc->nick );  		if( !b->joined ) -			irc_join( b->gc->irc, u, b->channel ); +			irc_join( b->ic->irc, u, b->channel );  		b->joined = me = 1;  	} @@ -802,45 +850,48 @@ void add_chat_buddy( struct conversation *b, char *handle )  	   your contact list. Try to handle that here */  	if( !u )  	{ -		add_buddy( b->gc, NULL, handle, NULL ); -		u = user_findhandle( b->gc, handle ); +		imcb_add_buddy( b->ic, handle, NULL ); +		u = user_findhandle( b->ic, handle );  	}  	/* Add the handle to the room userlist, if it's not 'me' */  	if( !me )  	{  		if( b->joined ) -			irc_join( b->gc->irc, u, b->channel ); +			irc_join( b->ic->irc, u, b->channel );  		b->in_room = g_list_append( b->in_room, g_strdup( handle ) );  	}  } -void remove_chat_buddy( struct conversation *b, char *handle, char *reason ) +/* This function is one BIG hack... :-( EREWRITE */ +void imcb_chat_remove_buddy( struct groupchat *b, char *handle, char *reason )  {  	user_t *u;  	int me = 0; -	if( set_getint( b->gc->irc, "debug" ) ) -		serv_got_crap( b->gc, "User %s removed from conversation %d (%s)", handle, b->id, reason ? reason : "" ); +	if( set_getbool( &b->ic->irc->set, "debug" ) ) +		imcb_log( b->ic, "User %s removed from conversation %p (%s)", handle, b, reason ? reason : "" );  	/* It might be yourself! */ -	if( g_strcasecmp( handle, b->gc->user->username ) == 0 ) +	if( g_strcasecmp( handle, b->ic->acc->user ) == 0 )  	{ -		u = user_find( b->gc->irc, b->gc->irc->nick ); +		if( b->joined == 0 ) +			return; +		 +		u = user_find( b->ic->irc, b->ic->irc->nick );  		b->joined = 0;  		me = 1;  	}  	else  	{ -		u = user_findhandle( b->gc, handle ); +		u = user_findhandle( b->ic, handle );  	} -	if( remove_chat_buddy_silent( b, handle ) ) -		if( ( b->joined || me ) && u ) -			irc_part( b->gc->irc, u, b->channel ); +	if( me || ( remove_chat_buddy_silent( b, handle ) && b->joined && u ) ) +		irc_part( b->ic->irc, u, b->channel );  } -static int remove_chat_buddy_silent( struct conversation *b, char *handle ) +static int remove_chat_buddy_silent( struct groupchat *b, const char *handle )  {  	GList *i; @@ -864,26 +915,9 @@ static int remove_chat_buddy_silent( struct conversation *b, char *handle )  /* Misc. BitlBee stuff which shouldn't really be here */ -struct conversation *conv_findchannel( char *channel ) -{ -	struct gaim_connection *gc; -	struct conversation *c; -	GSList *l; -	 -	/* This finds the connection which has a conversation which belongs to this channel */ -	for( l = connections; l; l = l->next ) -	{ -		gc = l->data; -		for( c = gc->conversations; c && g_strcasecmp( c->channel, channel ) != 0; c = c->next ); -		if( c ) -			return( c ); -	} -	 -	return( NULL ); -} - -char *set_eval_away_devoice( irc_t *irc, set_t *set, char *value ) +char *set_eval_away_devoice( set_t *set, char *value )  { +	irc_t *irc = set->data;  	int st;  	if( ( g_strcasecmp( value, "true" ) == 0 ) || ( g_strcasecmp( value, "yes" ) == 0 ) || ( g_strcasecmp( value, "on" ) == 0 ) ) @@ -897,7 +931,7 @@ char *set_eval_away_devoice( irc_t *irc, set_t *set, char *value )  	/* Horror.... */ -	if( st != set_getint( irc, "away_devoice" ) ) +	if( st != set_getbool( &irc->set, "away_devoice" ) )  	{  		char list[80] = "";  		user_t *u = irc->users; @@ -912,13 +946,13 @@ char *set_eval_away_devoice( irc_t *irc, set_t *set, char *value )  		while( u )  		{ -			if( u->gc && u->online && !u->away ) +			if( u->ic && u->online && !u->away )  			{  				if( ( strlen( list ) + strlen( u->nick ) ) >= 79 )  				{  					for( i = 0; i < count; v[i++] = 'v' ); v[i] = 0; -					irc_write( irc, ":%s!%s@%s MODE %s %c%s%s", -					           irc->mynick, irc->mynick, irc->myhost, +					irc_write( irc, ":%s MODE %s %c%s%s", +					           irc->myhost,  		        			   irc->channel, pm, v, list );  					*list = 0; @@ -933,11 +967,11 @@ char *set_eval_away_devoice( irc_t *irc, set_t *set, char *value )  		/* $v = 'v' x $i */  		for( i = 0; i < count; v[i++] = 'v' ); v[i] = 0; -		irc_write( irc, ":%s!%s@%s MODE %s %c%s%s", irc->mynick, irc->mynick, irc->myhost, +		irc_write( irc, ":%s MODE %s %c%s%s", irc->myhost,  		                                            irc->channel, pm, v, list );  	} -	return( set_eval_bool( irc, set, value ) ); +	return( set_eval_bool( set, value ) );  } @@ -946,49 +980,48 @@ char *set_eval_away_devoice( irc_t *irc, set_t *set, char *value )  /* The plan is to not allow straight calls to prpl functions anymore, but do     them all from some wrappers. We'll start to define some down here: */ -int bim_buddy_msg( struct gaim_connection *gc, char *handle, char *msg, int flags ) +int imc_buddy_msg( struct im_connection *ic, char *handle, char *msg, int flags )  {  	char *buf = NULL;  	int st; -	if( ( gc->flags & OPT_CONN_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) ) +	if( ( ic->flags & OPT_DOES_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) )  	{  		buf = escape_html( msg );  		msg = buf;  	} -	st = gc->prpl->send_im( gc, handle, msg, strlen( msg ), flags ); +	st = ic->acc->prpl->buddy_msg( ic, handle, msg, flags );  	g_free( buf );  	return st;  } -int bim_chat_msg( struct gaim_connection *gc, int id, char *msg ) +int imc_chat_msg( struct groupchat *c, char *msg, int flags )  {  	char *buf = NULL; -	int st; -	if( ( gc->flags & OPT_CONN_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) ) +	if( ( c->ic->flags & OPT_DOES_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) )  	{  		buf = escape_html( msg );  		msg = buf;  	} -	st = gc->prpl->chat_send( gc, id, msg ); +	c->ic->acc->prpl->chat_msg( c, msg, flags );  	g_free( buf ); -	return st; +	return 1;  } -static char *bim_away_alias_find( GList *gcm, char *away ); +static char *imc_away_alias_find( GList *gcm, char *away ); -int bim_set_away( struct gaim_connection *gc, char *away ) +int imc_set_away( struct im_connection *ic, char *away )  {  	GList *m, *ms;  	char *s;  	if( !away ) away = ""; -	ms = m = gc->prpl->away_states( gc ); +	ms = m = ic->acc->prpl->away_states( ic );  	while( m )  	{ @@ -1009,27 +1042,25 @@ int bim_set_away( struct gaim_connection *gc, char *away )  	if( m )  	{ -		gc->prpl->set_away( gc, m->data, *away ? away : NULL ); +		ic->acc->prpl->set_away( ic, m->data, *away ? away : NULL );  	}  	else  	{ -		s = bim_away_alias_find( ms, away ); +		s = imc_away_alias_find( ms, away );  		if( s )  		{ -			gc->prpl->set_away( gc, s, away ); -			if( set_getint( gc->irc, "debug" ) ) -				serv_got_crap( gc, "Setting away state to %s", s ); +			ic->acc->prpl->set_away( ic, s, away ); +			if( set_getbool( &ic->irc->set, "debug" ) ) +				imcb_log( ic, "Setting away state to %s", s );  		}  		else -			gc->prpl->set_away( gc, GAIM_AWAY_CUSTOM, away ); +			ic->acc->prpl->set_away( ic, GAIM_AWAY_CUSTOM, away );  	} -	g_list_free( ms ); -	  	return( 1 );  } -static char *bim_away_alias_list[8][5] = +static char *imc_away_alias_list[8][5] =  {  	{ "Away from computer", "Away", "Extended away", NULL },  	{ "NA", "N/A", "Not available", NULL }, @@ -1041,28 +1072,28 @@ static char *bim_away_alias_list[8][5] =  	{ NULL }  }; -static char *bim_away_alias_find( GList *gcm, char *away ) +static char *imc_away_alias_find( GList *gcm, char *away )  {  	GList *m;  	int i, j; -	for( i = 0; *bim_away_alias_list[i]; i ++ ) +	for( i = 0; *imc_away_alias_list[i]; i ++ )  	{ -		for( j = 0; bim_away_alias_list[i][j]; j ++ ) -			if( g_strncasecmp( away, bim_away_alias_list[i][j], strlen( bim_away_alias_list[i][j] ) ) == 0 ) +		for( j = 0; imc_away_alias_list[i][j]; j ++ ) +			if( g_strncasecmp( away, imc_away_alias_list[i][j], strlen( imc_away_alias_list[i][j] ) ) == 0 )  				break; -		if( !bim_away_alias_list[i][j] )	/* If we reach the end, this row */ +		if( !imc_away_alias_list[i][j] )	/* If we reach the end, this row */  			continue;			/* is not what we want. Next!    */  		/* Now find an entry in this row which exists in gcm */ -		for( j = 0; bim_away_alias_list[i][j]; j ++ ) +		for( j = 0; imc_away_alias_list[i][j]; j ++ )  		{  			m = gcm;  			while( m )  			{ -				if( g_strcasecmp( bim_away_alias_list[i][j], m->data ) == 0 ) -					return( bim_away_alias_list[i][j] ); +				if( g_strcasecmp( imc_away_alias_list[i][j], m->data ) == 0 ) +					return( imc_away_alias_list[i][j] );  				m = m->next;  			}  		} @@ -1071,48 +1102,80 @@ static char *bim_away_alias_find( GList *gcm, char *away )  	return( NULL );  } -void bim_add_allow( struct gaim_connection *gc, char *handle ) +void imc_add_allow( struct im_connection *ic, char *handle )  { -	if( g_slist_find_custom( gc->permit, handle, (GCompareFunc) gc->prpl->cmp_buddynames ) == NULL ) +	if( g_slist_find_custom( ic->permit, handle, (GCompareFunc) ic->acc->prpl->handle_cmp ) == NULL )  	{ -		gc->permit = g_slist_prepend( gc->permit, g_strdup( handle ) ); +		ic->permit = g_slist_prepend( ic->permit, g_strdup( handle ) );  	} -	gc->prpl->add_permit( gc, handle ); +	ic->acc->prpl->add_permit( ic, handle );  } -void bim_rem_allow( struct gaim_connection *gc, char *handle ) +void imc_rem_allow( struct im_connection *ic, char *handle )  {  	GSList *l; -	if( ( l = g_slist_find_custom( gc->permit, handle, (GCompareFunc) gc->prpl->cmp_buddynames ) ) ) +	if( ( l = g_slist_find_custom( ic->permit, handle, (GCompareFunc) ic->acc->prpl->handle_cmp ) ) )  	{  		g_free( l->data ); -		gc->permit = g_slist_delete_link( gc->permit, l ); +		ic->permit = g_slist_delete_link( ic->permit, l );  	} -	gc->prpl->rem_permit( gc, handle ); +	ic->acc->prpl->rem_permit( ic, handle );  } -void bim_add_block( struct gaim_connection *gc, char *handle ) +void imc_add_block( struct im_connection *ic, char *handle )  { -	if( g_slist_find_custom( gc->deny, handle, (GCompareFunc) gc->prpl->cmp_buddynames ) == NULL ) +	if( g_slist_find_custom( ic->deny, handle, (GCompareFunc) ic->acc->prpl->handle_cmp ) == NULL )  	{ -		gc->deny = g_slist_prepend( gc->deny, g_strdup( handle ) ); +		ic->deny = g_slist_prepend( ic->deny, g_strdup( handle ) );  	} -	gc->prpl->add_deny( gc, handle ); +	ic->acc->prpl->add_deny( ic, handle );  } -void bim_rem_block( struct gaim_connection *gc, char *handle ) +void imc_rem_block( struct im_connection *ic, char *handle )  {  	GSList *l; -	if( ( l = g_slist_find_custom( gc->deny, handle, (GCompareFunc) gc->prpl->cmp_buddynames ) ) ) +	if( ( l = g_slist_find_custom( ic->deny, handle, (GCompareFunc) ic->acc->prpl->handle_cmp ) ) )  	{  		g_free( l->data ); -		gc->deny = g_slist_delete_link( gc->deny, l ); +		ic->deny = g_slist_delete_link( ic->deny, l ); +	} +	 +	ic->acc->prpl->rem_deny( ic, handle ); +} + +void imcb_clean_handle( struct im_connection *ic, char *handle ) +{ +	/* Accepts a handle and does whatever is necessary to make it +	   BitlBee-friendly. Currently this means removing everything +	   outside 33-127 (ASCII printable excl spaces), @ (only one +	   is allowed) and ! and : */ +	char out[strlen(handle)+1]; +	int s, d; +	 +	s = d = 0; +	while( handle[s] ) +	{ +		if( handle[s] > ' ' && handle[s] != '!' && handle[s] != ':' && +		    ( handle[s] & 0x80 ) == 0 ) +		{ +			if( handle[s] == '@' ) +			{ +				/* See if we got an @ already? */ +				out[d] = 0; +				if( strchr( out, '@' ) ) +					continue; +			} +			 +			out[d++] = handle[s]; +		} +		s ++;  	} +	out[d] = handle[s]; -	gc->prpl->rem_deny( gc, handle ); +	strcpy( handle, out );  } | 
