diff options
44 files changed, 885 insertions, 585 deletions
| @@ -18,3 +18,5 @@ build-arch-stamp  tags  decode  encode +bitlbee.pc +.gdb_history @@ -10,6 +10,7 @@  # Program variables  objects = account.o bitlbee.o crypting.o help.o ini.o ipc.o irc.o irc_commands.o nick.o query.o root_commands.o set.o storage.o storage_text.o url.o user.o util.o +headers = account.h bitlbee.h commands.h conf.h config.h crypting.h help.h ini.h ipc.h irc.h log.h nick.h query.h set.h sock.h storage.h url.h user.h protocols/http_client.h protocols/md5.h protocols/nogaim.h protocols/proxy.h protocols/sha.h protocols/ssl_client.h  subdirs = protocols  ifeq ($(ARCH),Windows) @@ -25,7 +26,7 @@ CFLAGS += -Wall  all: $(OUTFILE)  	$(MAKE) -C doc -uninstall: uninstall-bin uninstall-doc +uninstall: uninstall-bin uninstall-doc   	@echo -e '\nmake uninstall does not remove files in '$(DESTDIR)$(ETCDIR)', you can use make uninstall-etc to do that.\n'  install: install-bin install-doc @@ -62,6 +63,17 @@ install-bin:  uninstall-bin:  	rm -f $(DESTDIR)$(BINDIR)/$(OUTFILE) +install-dev: +	mkdir -p $(DESTDIR)$(INCLUDEDIR) +	install -m 0644 $(headers) $(DESTDIR)$(INCLUDEDIR) +	mkdir -p $(DESTDIR)$(PCDIR) +	install -m 0644 bitlbee.pc $(DESTDIR)$(PCDIR) + +uninstall-dev: +	rm -f $(foreach hdr,$(headers),$(DESTDIR)$(INCLUDEDIR)/$(hdr)) +	-rmdir $(DESTDIR)$(INCLUDEDIR) +	rm -f $(DESTDIR)$(PCDIR)/bitlbee.pc +  install-etc:  	mkdir -p $(DESTDIR)$(ETCDIR)  	install -m 0644 motd.txt $(DESTDIR)$(ETCDIR)/motd.txt @@ -52,8 +52,34 @@ account_t *account_add( irc_t *irc, struct prpl *prpl, char *user, char *pass )  account_t *account_get( irc_t *irc, char *id )  {  	account_t *a, *ret = NULL; +	char *handle, *s;  	int nr; +	/* This checks if the id string ends with (...) */ +	if( ( handle = strchr( id, '(' ) ) && ( s = strchr( handle, ')' ) ) && s[1] == 0 ) +	{ +		struct prpl *proto; +		 +		*s = *handle = 0; +		handle ++; +		 +		if( ( proto = find_protocol( id ) ) ) +		{ +			for( a = irc->accounts; a; a = a->next ) +				if( a->prpl == proto && +				    a->prpl->cmp_buddynames( handle, a->user ) == 0 ) +					ret = a; +		} +		 +		/* Restore the string. */ +		handle --; +		*handle = '('; +		*s = ')'; +		 +		if( ret ) +			return ret; +	} +	  	if( sscanf( id, "%d", &nr ) == 1 && nr < 1000 )  	{  		for( a = irc->accounts; a; a = a->next ) @@ -140,7 +166,8 @@ void account_on( irc_t *irc, account_t *a )  void account_off( irc_t *irc, account_t *a )  { -	account_offline( a->gc ); +	a->gc->wants_to_die = TRUE; +	signoff( a->gc );  	a->gc = NULL;  	if( a->reconnect )  	{ @@ -110,8 +110,8 @@ int bitlbee_daemon_init()  		/* 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 ); +		if( isatty( 1 ) ) close( 1 ); +		if( isatty( 2 ) ) close( 2 );  	}  #endif @@ -98,7 +98,7 @@ extern char *CONF_FILE;  #include "irc.h"  #include "storage.h"  #include "set.h" -#include "protocols/nogaim.h" +#include "nogaim.h"  #include "commands.h"  #include "account.h"  #include "conf.h" @@ -107,6 +107,7 @@ extern char *CONF_FILE;  #include "help.h"  #include "query.h"  #include "sock.h" +#include "util.h"  typedef struct global {  	/* In forked mode, child processes store the fd of the IPC socket here. */ @@ -129,10 +130,6 @@ gboolean bitlbee_io_current_client_write( GIOChannel *source, GIOCondition condi  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 ); -G_MODULE_EXPORT void http_decode( char *s ); -G_MODULE_EXPORT char *strip_newlines(char *source);  extern global_t global; @@ -94,7 +94,7 @@ conf_t *conf_load( int argc, char *argv[] )  			}  			conf->port = i;  		} -		else if( opt == 'p' ) +		else if( opt == 'P' )  		{  			g_free( conf->pidfile );  			conf->pidfile = g_strdup( optarg ); @@ -16,6 +16,8 @@ config='/var/lib/bitlbee/'  pidfile='/var/run/bitlbee.pid'  ipcsocket='/var/run/bitlbee'  plugindir='$prefix/lib/bitlbee' +pcdir='$prefix/lib/pkgconfig' +includedir='$prefix/include/bitlbee'  msn=1  jabber=1 @@ -79,6 +81,8 @@ config=`eval echo "$config/" | sed 's/\/\{1,\}/\//g'`  plugindir=`eval echo "$plugindir/" | sed 's/\/\{1,\}/\//g'`  pidfile=`eval echo "$pidfile" | sed 's/\/\{1,\}/\//g'`  ipcsocket=`eval echo "$ipcsocket" | sed 's/\/\{1,\}/\//g'` +includedir=`eval echo "$includedir" | sed 's/\/\{1,\}/\//g'` +pcdir=`eval echo "$pcdir" | sed 's/\/\{1,\}/\//g'`  cat<<EOF>Makefile.settings  ## BitlBee settings, generated by configure @@ -90,6 +94,8 @@ DATADIR=$datadir  PLUGINDIR=$plugindir  CONFIG=$config  IPCSOCKET=$ipcsocket +INCLUDEDIR=$includedir +PCDIR=$pcdir  ARCH=$arch  CPU=$cpu @@ -299,10 +305,16 @@ else  fi  echo -if [ -z "$BITLBEE_VERSION" -a -d .bzr -a -x "`which bzr`" ]; then +if [ -z "$BITLBEE_VERSION" -a -d .bzr ] && type bzr > /dev/null 2> /dev/null; then +	nick=`bzr nick` +	if [ -n "$nick" -a "$nick" != "bitlbee" ]; then +		nick="-$nick" +	else +		nick="" +	fi  	rev=`bzr revno`  	echo 'Using bzr revision #'$rev' as version number' -	BITLBEE_VERSION=\"bzr-$rev\" +	BITLBEE_VERSION=\"bzr$nick-$rev\"  fi  if [ -n "$BITLBEE_VERSION" ]; then @@ -312,6 +324,19 @@ if [ -n "$BITLBEE_VERSION" ]; then  	echo  fi +cat <<EOF>bitlbee.pc +prefix=$prefix +includedir=$includedir + +Name: bitlbee +Description: IRC to IM gateway +Requires: glib-2.0 +Version: $BITLBEE_VERSION +Libs: +Cflags: -I\${includedir} + +EOF +  protocols=''  protoobjs='' diff --git a/doc/bitlbee.8 b/doc/bitlbee.8 index f1d4dbce..201e366e 100644 --- a/doc/bitlbee.8 +++ b/doc/bitlbee.8 @@ -115,7 +115,7 @@ along with this program; if not, write to the Free Software  Foundation, Inc., 59 Temple PLace, Suite 330, Boston, MA  02111-1307  USA  .SH AUTHORS  .PP - Wilmer van der Gaast <lintux@lintux.cx> + Wilmer van der Gaast <wilmer@gaast.net>  .BR   Jelmer Vernooij <jelmer@vernstok.nl>  .BR diff --git a/doc/bitlbee.xinetd b/doc/bitlbee.xinetd index 5f05e26e..88d02013 100644 --- a/doc/bitlbee.xinetd +++ b/doc/bitlbee.xinetd @@ -13,7 +13,12 @@ service ircd  	user            = nobody  	server          = /usr/local/sbin/bitlbee -	## xinetd is fucking retarded, what's the use of this port flag if -	## it HAS to be the same as in /etc/services ? -	# port		= 6667 +	## You might want to limit access to localhost only: +	# bind            = 127.0.0.1 +	 +	## Thanks a lot to friedman@splode.com for telling us about the type +	## argument, so now this file can be used without having to edit +	## /etc/services too. +	type            = UNLISTED +	port            = 6667  } diff --git a/doc/example_plugin.c b/doc/example_plugin.c index 38d02260..a33907a8 100644 --- a/doc/example_plugin.c +++ b/doc/example_plugin.c @@ -2,10 +2,11 @@   * This is the most simple possible BitlBee plugin. To use, compile it as    * a shared library and place it in the plugin directory:    * - * gcc -o example.so -shared example.c + * gcc -o example.so -shared example.c `pkg-config --cflags bitlbee`   * cp example.so /usr/local/lib/bitlbee   */  #include <stdio.h> +#include <bitlbee.h>  void init_plugin(void)  { diff --git a/doc/user-guide/commands.xml b/doc/user-guide/commands.xml index b04a6b0a..44a9882f 100644 --- a/doc/user-guide/commands.xml +++ b/doc/user-guide/commands.xml @@ -140,6 +140,7 @@  	<bitlbee-command name="add">  		<short-description>Add a buddy to your contact list</short-description>  		<syntax>add <connection> <handle> [<nick>]</syntax> +		<syntax>add -tmp <connection> <handle> [<nick>]</syntax>  		<description>  			<para> @@ -149,6 +150,10 @@  			<para>  				If you want, you can also tell BitlBee what nick to give the new contact. Of course you can also use the <emphasis>rename</emphasis> command for that, but sometimes this might be more convenient.  			</para> +			 +			<para> +				Adding -tmp adds the buddy to the internal BitlBee structures only, not to the real contact list (like done by <emphasis>set handle_unknown add</emphasis>). This allows you to talk to people who are not in your contact list. +			</para>  		</description>  		<ircexample> @@ -196,11 +201,16 @@  		<short-description>Block someone</short-description>  		<syntax>block <nick></syntax>  		<syntax>block <connection> <handle></syntax> +		<syntax>block <connection></syntax>  		<description>  			<para>  				Puts the specified user on your ignore list. Either specify the user's nick when you have him/her in your contact list or a connection number and a user handle.  			</para> +			 +			<para> +				When called with only a connection specification as an argument, the command displays the current block list for that connection. +			</para>  		</description>  	</bitlbee-command> @@ -213,6 +223,10 @@  			<para>  				Reverse of block. Unignores the specified user or user handle on specified connection.  			</para> +			 +			<para> +				When called with only a connection specification as an argument, the command displays the current allow list for that connection. +			</para>  		</description>  	</bitlbee-command> @@ -606,7 +620,7 @@  			</para>  			<para> -				To identify yourself in later sessions, you can use the <emphasis>identify</emphasis> command. +				To identify yourself in later sessions, you can use the <emphasis>identify</emphasis> command. To change your password later, you can use the <emphasis>set password</emphasis> command.  			</para>  		</description> @@ -115,22 +115,21 @@ char *help_get( help_t **help, char *string )  		if( g_strcasecmp( h->string, string ) == 0 ) break;  		h = h->next;  	} -	if( h ) +	if( h && h->length > 0 )  	{  		char *s = g_new( char, h->length + 1 );  		if( fstat( h->fd, stat ) != 0 )  		{  			g_free( h ); -			*help=NULL; -			return( NULL ); +			*help = NULL; +			return NULL;  		}  		mtime = stat->st_mtime; -		if( mtime > h->mtime ) { -			return( NULL ); -			return( g_strdup( "Help file changed during this session. Please restart to get help back." ) ); -		} +		if( mtime > h->mtime ) +			return NULL; +		  		s[h->length] = 0;  		if( h->fd >= 0 )  		{ @@ -141,8 +140,8 @@ char *help_get( help_t **help, char *string )  		{  			strncpy( s, h->offset.mem_offset, h->length );  		} -		return( s ); +		return s;  	} -	return( NULL ); +	return NULL;  } @@ -83,8 +83,6 @@ void ipc_master_cmd_rehash( irc_t *data, char **cmd )  void ipc_master_cmd_restart( irc_t *data, char **cmd )  { -	struct bitlbee_child *child = (void*) data; -	  	if( global.conf->runmode != RUNMODE_FORKDAEMON )  	{  		/* Tell child that this is unsupported. */ @@ -508,7 +506,7 @@ int ipc_master_listen_socket()  		return 0;  	} -	if (bind(serversock, &un_addr, sizeof(un_addr)) == -1) { +	if (bind(serversock, (struct sockaddr *)&un_addr, sizeof(un_addr)) == -1) {  		log_message( LOGLVL_WARNING, "Unable to bind UNIX socket to %s: %s", IPCSOCKET, strerror(errno) );  		return 0;  	} @@ -572,5 +570,6 @@ int ipc_master_load_state()  	ipc_to_children_str( "HELLO\r\n" );  	ipc_to_children_str( "OPERMSG :New BitlBee master process started (version " BITLBEE_VERSION ")\r\n" ); +	fclose( fp );  	return 1;  } @@ -46,9 +46,9 @@ void ipc_master_free_one( struct bitlbee_child *child );  void ipc_master_free_all();  void ipc_to_master( char **cmd ); -void ipc_to_master_str( char *format, ... ); +void ipc_to_master_str( char *format, ... ) G_GNUC_PRINTF( 1, 2 );  void ipc_to_children( char **cmd ); -void ipc_to_children_str( char *format, ... ); +void ipc_to_children_str( char *format, ... ) G_GNUC_PRINTF( 1, 2 );  /* We need this function in inetd mode, so let's just make it non-static. */  void ipc_master_cmd_rehash( irc_t *data, char **cmd ); @@ -198,7 +198,7 @@ void irc_abort( irc_t *irc, int immed, char *format, ... )  	}  } -static gboolean irc_free_userhash( gpointer key, gpointer value, gpointer data ) +static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data )  {  	g_free( key ); @@ -231,9 +231,14 @@ void irc_free(irc_t * irc)  	g_io_channel_unref( irc->io_channel );  	irc_connection_list = g_slist_remove( irc_connection_list, irc ); -	for (account = irc->accounts; account; account = account->next) -		if (account->gc) +	for (account = irc->accounts; account; account = account->next) { +		if (account->gc) { +			account->gc->wants_to_die = TRUE;  			signoff(account->gc); +		} else if (account->reconnect) { +			cancel_auto_reconnect(account); +		} +	}  	g_free(irc->sendbuffer);  	g_free(irc->readbuffer); @@ -281,10 +286,10 @@ void irc_free(irc_t * irc)  		}  	} -	g_hash_table_foreach_remove(irc->userhash, irc_free_userhash, NULL); +	g_hash_table_foreach_remove(irc->userhash, irc_free_hashkey, NULL);  	g_hash_table_destroy(irc->userhash); -	g_hash_table_foreach_remove(irc->watches, irc_free_userhash, NULL); +	g_hash_table_foreach_remove(irc->watches, irc_free_hashkey, NULL);  	g_hash_table_destroy(irc->watches);  	if (irc->nicks != NULL) { @@ -342,7 +347,7 @@ void irc_setpass (irc_t *irc, const char *pass)  void irc_process( irc_t *irc )  { -	char **lines, *temp, **cmd; +	char **lines, *temp, **cmd, *cs;  	int i;  	if( irc->readbuffer != NULL ) @@ -351,6 +356,11 @@ void irc_process( irc_t *irc )  		for( i = 0; *lines[i] != '\0'; i ++ )  		{ +			char conv[IRC_MAX_LINE+1]; +			 +			/* [WvG] Because irc_tokenize splits at every newline, the lines[] list +			    should end with an empty string. This is why this actually works. +			    Took me a while to figure out, Maurits. :-P */  			if( lines[i+1] == NULL )  			{  				temp = g_strdup( lines[i] ); @@ -358,7 +368,14 @@ void irc_process( irc_t *irc )  				irc->readbuffer = temp;  				i ++;  				break; -			}			 +			} +			 +			if( ( cs = set_getstr( irc, "charset" ) ) && ( g_strcasecmp( cs, "utf-8" ) != 0 ) ) +			{ +				conv[IRC_MAX_LINE] = 0; +				if( do_iconv( cs, "UTF-8", lines[i], conv, 0, IRC_MAX_LINE - 2 ) != -1 ) +					lines[i] = conv; +			}  			if( ( cmd = irc_parse_line( lines[i] ) ) == NULL )  				continue; @@ -384,6 +401,8 @@ void irc_process( irc_t *irc )  	}  } +/* Splits a long string into separate lines. The array is NULL-terminated and, unless the string +   contains an incomplete line at the end, ends with an empty string. */  char **irc_tokenize( char *buffer )  {  	int i, j; @@ -424,6 +443,7 @@ char **irc_tokenize( char *buffer )  	return( lines );  } +/* Split an IRC-style line into little parts/arguments. */  char **irc_parse_line( char *line )  {  	int i, j; @@ -483,6 +503,7 @@ char **irc_parse_line( char *line )  	return cmd;  } +/* Converts such an array back into a command string. Mainly used for the IPC code right now. */  char *irc_build_line( char **cmd )  {  	int i, len; @@ -535,7 +556,7 @@ int irc_usermsg( irc_t *irc, char *format, ... )  	user_t *u;  	u = user_find( irc, irc->mynick ); -	if( u ) is_private = u->is_private; +	is_private = u->is_private;  	va_start( params, format );  	g_vsnprintf( text, sizeof( text ), format, params ); @@ -559,16 +580,25 @@ void irc_write( irc_t *irc, char *format, ... )  void irc_vawrite( irc_t *irc, char *format, va_list params )  {  	int size; -	char line[IRC_MAX_LINE]; -	 +	char line[IRC_MAX_LINE+1], *cs; +		  	if( irc->quit )  		return; - -	g_vsnprintf( line, IRC_MAX_LINE - 3, format, params ); - +	 +	line[IRC_MAX_LINE] = 0; +	g_vsnprintf( line, IRC_MAX_LINE - 2, format, params ); +	  	strip_newlines( line ); +	if( ( cs = set_getstr( irc, "charset" ) ) && ( g_strcasecmp( cs, "utf-8" ) != 0 ) ) +	{ +		char conv[IRC_MAX_LINE+1]; +		 +		conv[IRC_MAX_LINE] = 0; +		if( do_iconv( "UTF-8", cs, line, conv, 0, IRC_MAX_LINE - 2 ) != -1 ) +			strcpy( line, conv ); +	}  	strcat( line, "\r\n" ); - +	  	if( irc->sendbuffer != NULL ) {  		size = strlen( irc->sendbuffer ) + strlen( line );  		irc->sendbuffer = g_renew ( char, irc->sendbuffer, size + 1 ); @@ -799,7 +829,7 @@ void irc_topic( irc_t *irc, char *channel )  		if( c )  			irc_reply( irc, 332, "%s :BitlBee groupchat: \"%s\". Please keep in mind that root-commands won't work here. Have fun!", channel, c->title );  		else -			irc_reply( irc, 331, "%s :No topic for this channel" ); +			irc_reply( irc, 331, "%s :No topic for this channel", channel );  	}  } @@ -855,7 +885,7 @@ void irc_join( irc_t *irc, user_t *u, char *channel )  	nick_lc( nick );  	if( g_hash_table_lookup( irc->watches, nick ) )  	{ -		irc_reply( irc, 600, "%s %s %s %d :%s", u->nick, u->user, u->host, time( NULL ), "logged online" ); +		irc_reply( irc, 600, "%s %s %s %d :%s", u->nick, u->user, u->host, (int) time( NULL ), "logged online" );  	}  	g_free( nick );  } @@ -880,7 +910,7 @@ void irc_kill( irc_t *irc, user_t *u )  	nick_lc( nick );  	if( g_hash_table_lookup( irc->watches, nick ) )  	{ -		irc_reply( irc, 601, "%s %s %s %d :%s", u->nick, u->user, u->host, time( NULL ), "logged offline" ); +		irc_reply( irc, 601, "%s %s %s %d :%s", u->nick, u->user, u->host, (int) time( NULL ), "logged offline" );  	}  	g_free( nick );  } @@ -980,7 +1010,7 @@ int irc_send( irc_t *irc, char *nick, char *s, int flags )  	}  	else if( c && c->gc && c->gc->prpl )  	{ -		return( serv_send_chat( irc, c->gc, c->id, s ) ); +		return( bim_chat_msg( c->gc, c->id, s ) );  	}  	return( 0 ); @@ -990,8 +1020,12 @@ gboolean buddy_send_handler_delayed( gpointer data )  {  	user_t *u = data; +	/* Shouldn't happen, but just to be sure. */ +	if( u->sendbuf_len < 2 ) +		return FALSE; +	  	u->sendbuf[u->sendbuf_len-2] = 0; /* Cut off the last newline */ -	serv_send_im( u->gc->irc, u, u->sendbuf, u->sendbuf_flags ); +	bim_buddy_msg( u->gc, u->handle, u->sendbuf, u->sendbuf_flags );  	g_free( u->sendbuf );  	u->sendbuf = NULL; @@ -999,7 +1033,7 @@ gboolean buddy_send_handler_delayed( gpointer data )  	u->sendbuf_timer = 0;  	u->sendbuf_flags = 0; -	return( FALSE ); +	return FALSE;  }  void buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags ) @@ -1012,7 +1046,7 @@ void buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags )  		if( u->sendbuf_len > 0 && u->sendbuf_flags != flags)  		{ -			//Flush the buffer +			/* Flush the buffer */  			g_source_remove( u->sendbuf_timer );  			buddy_send_handler_delayed( u );  		} @@ -1020,14 +1054,14 @@ void buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags )  		if( u->sendbuf_len == 0 )  		{  			u->sendbuf_len = strlen( msg ) + 2; -			u->sendbuf = g_new (char, u->sendbuf_len ); +			u->sendbuf = g_new( char, u->sendbuf_len );  			u->sendbuf[0] = 0;  			u->sendbuf_flags = flags;  		}  		else  		{  			u->sendbuf_len += strlen( msg ) + 1; -			u->sendbuf = g_renew ( char, u->sendbuf, u->sendbuf_len ); +			u->sendbuf = g_renew( char, u->sendbuf, u->sendbuf_len );  		}  		strcat( u->sendbuf, msg ); @@ -1043,7 +1077,7 @@ void buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags )  	}  	else  	{ -		serv_send_im( irc, u, msg, flags ); +		bim_buddy_msg( u->gc, u->handle, msg, flags );  	}  } @@ -32,7 +32,7 @@  #define IRC_LOGIN_TIMEOUT 60  #define IRC_PING_STRING "PinglBee" -#define UMODES "iasw" +#define UMODES "abisw"  #define UMODES_PRIV "Ro"  #define CMODES "nt"  #define CMODE "t" @@ -104,7 +104,7 @@ typedef struct irc  extern GSList *irc_connection_list;  irc_t *irc_new( int fd ); -void irc_abort( irc_t *irc, int immed, char *format, ... ); +void irc_abort( irc_t *irc, int immed, char *format, ... ) G_GNUC_PRINTF( 3, 4 );  void irc_free( irc_t *irc );  void irc_exec( irc_t *irc, char **cmd ); @@ -113,10 +113,10 @@ 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, ... ); -void irc_write_all( int now, char *format, ... ); -void irc_reply( irc_t *irc, int code, char *format, ... ); -G_MODULE_EXPORT int irc_usermsg( irc_t *irc, char *format, ... ); +void irc_write( irc_t *irc, char *format, ... ) G_GNUC_PRINTF( 2, 3 ); +void irc_write_all( int now, char *format, ... ) G_GNUC_PRINTF( 2, 3 ); +void irc_reply( irc_t *irc, int code, char *format, ... ) G_GNUC_PRINTF( 3, 4 ); +G_MODULE_EXPORT int irc_usermsg( irc_t *irc, char *format, ... ) G_GNUC_PRINTF( 2, 3 );  char **irc_tokenize( char *buffer );  void irc_login( irc_t *irc ); diff --git a/irc_commands.c b/irc_commands.c index f2c7a645..fe67a534 100644 --- a/irc_commands.c +++ b/irc_commands.c @@ -384,9 +384,9 @@ static void irc_cmd_watch( irc_t *irc, char **cmd )  				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" ); +				irc_reply( irc, 604, "%s %s %s %d :%s", u->nick, u->user, u->host, (int) time( NULL ), "is online" );  			else -				irc_reply( irc, 605, "%s %s %s %d :%s", nick, "*", "*", time( NULL ), "is offline" ); +				irc_reply( irc, 605, "%s %s %s %d :%s", nick, "*", "*", (int) time( NULL ), "is offline" );  		}  		else if( cmd[i][0] == '-' )  		{ @@ -447,7 +447,7 @@ static void irc_cmd_away( irc_t *irc, char **cmd )  		struct gaim_connection *gc = a->gc;  		if( gc && gc->flags & OPT_LOGGED_IN ) -			proto_away( gc, u->away ); +			bim_set_away( gc, u->away );  	}  } @@ -510,6 +510,11 @@ static void irc_cmd_pong( irc_t *irc, char **cmd )  	irc->pinging = 0;  } +static void irc_cmd_version( irc_t *irc, char **cmd ) +{ +	irc_reply( irc, 351, "bitlbee-%s. %s :%s/%s ", BITLBEE_VERSION, irc->myhost, ARCH, CPU ); +} +  static void irc_cmd_completions( irc_t *irc, char **cmd )  {  	user_t *u = user_find( irc, irc->mynick ); @@ -567,6 +572,7 @@ static const command_t irc_commands[] = {  	{ "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 }, +	{ "version",     0, irc_cmd_version,     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",     1, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER }, @@ -53,7 +53,7 @@ typedef struct log_t {  void log_init(void);  void log_link(int level, int output); -void log_message(int level, char *message, ...); +void log_message(int level, char *message, ...) G_GNUC_PRINTF( 2, 3 );  void log_error(char *functionname);  #endif diff --git a/protocols/http_client.c b/protocols/http_client.c index 9417e200..5db31782 100644 --- a/protocols/http_client.c +++ b/protocols/http_client.c @@ -70,6 +70,37 @@ void *http_dorequest( char *host, int port, int ssl, char *request, http_input_f  	return( req );  } +void *http_dorequest_url( char *url_string, http_input_function func, gpointer data ) +{ +	url_t *url = g_new0( url_t, 1 ); +	char *request; +	void *ret; +	 +	if( !url_set( url, url_string ) ) +	{ +		g_free( url ); +		return NULL; +	} +	 +	if( url->proto != PROTO_HTTP && url->proto != PROTO_HTTPS ) +	{ +		g_free( url ); +		return NULL; +	} +	 +	request = g_strdup_printf( "GET %s HTTP/1.0\r\n" +	                           "Host: %s\r\n" +	                           "User-Agent: BitlBee " BITLBEE_VERSION " " ARCH "/" CPU "\r\n" +	                           "\r\n", url->file, url->host ); +	 +	ret = http_dorequest( url->host, url->port, +	                      url->proto == PROTO_HTTPS, request, func, data ); +	 +	g_free( url ); +	g_free( request ); +	return ret; +} +  /* This one is actually pretty simple... Might get more calls if we can't write      the whole request at once. */  static void http_connected( gpointer data, int source, GaimInputCondition cond ) @@ -221,21 +252,24 @@ got_reply:  		end1 = end2 + 1;  		evil_server = 1;  	} -	else +	else if( end1 )  	{  		end1 += 2;  	} -	 -	if( end1 ) +	else  	{ -		*end1 = 0; -		 -		if( evil_server ) -			req->reply_body = end1 + 1; -		else -			req->reply_body = end1 + 2; +		goto cleanup;  	} +	*end1 = 0; +	 +	if( evil_server ) +		req->reply_body = end1 + 1; +	else +		req->reply_body = end1 + 2; +	 +	req->body_size = req->reply_headers + req->bytes_read - req->reply_body; +	  	if( ( end1 = strchr( req->reply_headers, ' ' ) ) != NULL )  	{  		if( sscanf( end1 + 1, "%d", &req->status_code ) != 1 ) diff --git a/protocols/http_client.h b/protocols/http_client.h index 53c6fcd6..860cdd86 100644 --- a/protocols/http_client.h +++ b/protocols/http_client.h @@ -38,6 +38,7 @@ struct http_request  	int status_code;  	char *reply_headers;  	char *reply_body; +	int body_size;  	int finished;  	void *ssl; @@ -52,3 +53,4 @@ struct http_request  };  void *http_dorequest( char *host, int port, int ssl, char *request, http_input_function func, gpointer data ); +void *http_dorequest_url( char *url_string, http_input_function func, gpointer data ); diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index ba652b8a..ac6481a1 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -1044,7 +1044,7 @@ static void jabber_accept_add(gpointer w, struct jabber_add_permit *jap)  	 * ask if we want him or her added.  	 */  	if(find_buddy(GJ_GC(jap->gjc), jap->user) == NULL) { -		show_got_added(GJ_GC(jap->gjc), NULL, jap->user, NULL, NULL); +		show_got_added(GJ_GC(jap->gjc), jap->user, NULL);  	}  	g_free(jap->user);  	g_free(jap); @@ -1231,9 +1231,7 @@ static void jabber_handleroster(gjconn gjc, xmlnode querynode)  		x = xmlnode_get_nextsibling(x);  	} -	x = jutil_presnew(0, NULL, "Online"); -	gjab_send(gjc, x); -	xmlnode_free(x); +	account_online(GJ_GC(gjc));  }  static void jabber_handleauthresp(gjconn gjc, jpacket p) @@ -1249,7 +1247,6 @@ static void jabber_handleauthresp(gjconn gjc, jpacket p)  			gjab_auth(gjc);  		} else {  			gjab_reqroster(gjc); -			account_online(GJ_GC(gjc));  			((struct jabber_data *)GJ_GC(gjc)->proto_data)->did_import = TRUE;  		} @@ -1551,7 +1548,9 @@ static gboolean jabber_free(gpointer data)  	if(jd->gjc != NULL) {  		gjab_delete(jd->gjc); +		/* YAY for modules with their own memory pool managers!...  		g_free(jd->gjc->sid); +		And a less sarcastic yay for valgrind. :-) */  		jd->gjc = NULL;  	}  	g_free(jd); @@ -1887,24 +1886,11 @@ static void jabber_set_away(struct gaim_connection *gc, char *state, char *messa  	xmlnode_free(x);  } -static void jabber_set_idle(struct gaim_connection *gc, int idle) { -	struct jabber_data *jd = (struct jabber_data *)gc->proto_data; -   	jd->idle = idle ? time(NULL) - idle : idle; -} -  static void jabber_keepalive(struct gaim_connection *gc) {  	struct jabber_data *jd = (struct jabber_data *)gc->proto_data;  	gjab_send_raw(jd->gjc, "  \t  ");  } -static void jabber_buddy_free(struct buddy *b) -{ -	while (b->proto_data) { -		g_free(((GSList *)b->proto_data)->data); -		b->proto_data = g_slist_remove(b->proto_data, ((GSList *)b->proto_data)->data); -	} -} -  /*---------------------------------------*/  /* Jabber "set info" (vCard) support     */  /*---------------------------------------*/ @@ -2340,29 +2326,12 @@ static void jabber_handlevcard(gjconn gjc, xmlnode querynode, char *from)  	g_string_free(str, TRUE);  } - -static GList *jabber_actions() -{ -	GList *m = NULL; - -	m = g_list_append(m, _("Set User Info")); -	/* -	m = g_list_append(m, _("Set Dir Info")); -	m = g_list_append(m, _("Change Password")); -	 */ - -	return m; -} - -  void jabber_init()  {  	struct prpl *ret = g_new0(struct prpl, 1); -	/* the NULL's aren't required but they're nice to have */  	ret->name = "jabber";  	ret->away_states = jabber_away_states; -	ret->actions = jabber_actions;  	ret->login = jabber_login;  	ret->close = jabber_close;  	ret->send_im = jabber_send_im; @@ -2370,16 +2339,9 @@ void jabber_init()  	ret->get_info = jabber_get_info;  	ret->set_away = jabber_set_away;  	ret->get_away = jabber_get_away_msg; -	ret->set_idle = jabber_set_idle;  	ret->add_buddy = jabber_add_buddy;  	ret->remove_buddy = jabber_remove_buddy; -	ret->add_permit = NULL; -	ret->add_deny = NULL; -	ret->rem_permit = NULL; -	ret->rem_deny = NULL; -	ret->set_permit_deny = NULL;  	ret->keepalive = jabber_keepalive; -	ret->buddy_free = jabber_buddy_free;  	ret->alias_buddy = jabber_roster_update;  	ret->group_buddy = jabber_group_change;  	ret->cmp_buddynames = g_strcasecmp; diff --git a/protocols/jabber/xmlparse.c b/protocols/jabber/xmlparse.c index 492da948..bbef7d59 100644 --- a/protocols/jabber/xmlparse.c +++ b/protocols/jabber/xmlparse.c @@ -1460,7 +1460,7 @@ initializeEncoding(XML_Parser parser)  #else  s = protocolEncodingName;  #endif -    if ((ns ? XmlInitEncodingNS : XmlInitEncoding)(&initEncoding, &encoding, s)) +    if (ns ? XmlInitEncodingNS(&initEncoding, &encoding, s) : XmlInitEncoding(&initEncoding, &encoding, s))          return XML_ERROR_NONE;      return handleUnknownEncoding(parser, protocolEncodingName);  } @@ -1474,8 +1474,7 @@ processXmlDecl(XML_Parser parser, int isGeneralTextEntity,      const char *version;      int standalone = -1;      if (!(ns -            ? XmlParseXmlDeclNS -            : XmlParseXmlDecl)(isGeneralTextEntity, +            ? XmlParseXmlDeclNS(isGeneralTextEntity,                                 encoding,                                 s,                                 next, @@ -1483,7 +1482,16 @@ processXmlDecl(XML_Parser parser, int isGeneralTextEntity,                                 &version,                                 &encodingName,                                 &newEncoding, -                               &standalone)) +                               &standalone) +            : XmlParseXmlDecl(isGeneralTextEntity, +                               encoding, +                               s, +                               next, +                               &eventPtr, +                               &version, +                               &encodingName, +                               &newEncoding, +                               &standalone)))          return XML_ERROR_SYNTAX;      if (!isGeneralTextEntity && standalone == 1)          dtd.standalone = 1; @@ -1536,11 +1544,14 @@ handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName)                  return XML_ERROR_NO_MEMORY;              }              enc = (ns -                   ? XmlInitUnknownEncodingNS -                   : XmlInitUnknownEncoding)(unknownEncodingMem, +                   ? XmlInitUnknownEncodingNS(unknownEncodingMem, +                                             info.map, +                                             info.convert, +                                             info.data) +                   : XmlInitUnknownEncoding(unknownEncodingMem,                                               info.map,                                               info.convert, -                                             info.data); +                                             info.data));              if (enc) {                  unknownEncodingData = info.data;                  unknownEncodingRelease = info.release; diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h index 9727c537..0cd174f2 100644 --- a/protocols/msn/msn.h +++ b/protocols/msn/msn.h @@ -65,8 +65,11 @@ struct msn_data  	GSList *msgq;  	GSList *switchboards; -	int buddycount;  	const struct msn_away_state *away_state; +	 +	int buddycount; +	int groupcount; +	char **grouplist;  };  struct msn_switchboard diff --git a/protocols/msn/msn_util.c b/protocols/msn/msn_util.c index e5f0b2c9..c3bd73cc 100644 --- a/protocols/msn/msn_util.c +++ b/protocols/msn/msn_util.c @@ -45,19 +45,8 @@ int msn_write( struct gaim_connection *gc, char *s, int len )  int msn_logged_in( struct gaim_connection *gc )  { -	struct msn_data *md = gc->proto_data; -	char buf[1024]; -	  	account_online( gc ); -	/* account_online() sets an away state if there is any, so only -	   execute this code if we're not away. */ -	if( md->away_state == msn_away_state_list ) -	{ -		g_snprintf( buf, sizeof( buf ), "CHG %d %s %d\r\n", ++md->trId, md->away_state->code, 0 ); -		return( msn_write( gc, buf, strlen( buf ) ) ); -	} -	  	return( 0 );  } @@ -141,6 +130,9 @@ static void msn_buddy_ask_yes( gpointer w, struct msn_buddy_ask_data *bla )  {  	msn_buddy_list_add( bla->gc, "AL", bla->handle, bla->realname ); +	if( find_buddy( bla->gc, bla->handle ) == NULL ) +		show_got_added( bla->gc, bla->handle, NULL ); +	  	g_free( bla->handle );  	g_free( bla->realname );  	g_free( bla ); diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index 4ced58a0..90d525ef 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -256,6 +256,9 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )  		if( num_parts == 5 )  		{  			md->buddycount = atoi( cmd[3] ); +			md->groupcount = atoi( cmd[4] ); +			if( md->groupcount > 0 ) +				md->grouplist = g_new0( char *, md->groupcount );  			if( !*cmd[3] || md->buddycount == 0 )  				msn_logged_in( gc ); @@ -268,18 +271,6 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )  			msn_logged_in( gc );  		}  	} -	else if( strcmp( cmd[0], "GTC" ) == 0 ) -	{ -	} -	else if( strcmp( cmd[0], "BLP" ) == 0 ) -	{ -	} -	else if( strcmp( cmd[0], "PRP" ) == 0 ) -	{ -	} -	else if( strcmp( cmd[0], "LSG" ) == 0 ) -	{ -	}  	else if( strcmp( cmd[0], "LST" ) == 0 )  	{  		int list; @@ -296,7 +287,13 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )  		if( list & 1 ) /* FL */  		{ -			add_buddy( gc, NULL, cmd[1], cmd[2] ); +			char *group = NULL; +			int num; +			 +			if( cmd[4] != NULL && sscanf( cmd[4], "%d", &num ) == 1 ) +				group = md->grouplist[num]; +			 +			add_buddy( gc, group, cmd[1], cmd[2] );  		}  		if( list & 2 ) /* AL */  		{ @@ -326,11 +323,22 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )  			}  		}  	} -	else if( strcmp( cmd[0], "BPR" ) == 0 ) -	{ -	} -	else if( strcmp( cmd[0], "CHG" ) == 0 ) +	else if( strcmp( cmd[0], "LSG" ) == 0 )  	{ +		int num; +		 +		if( num_parts != 4 ) +		{ +			hide_login_progress_error( gc, "Syntax error" ); +			signoff( gc ); +			return( 0 ); +		} +		 +		http_decode( cmd[2] ); +		num = atoi( cmd[1] ); +		 +		if( num < md->groupcount ) +			md->grouplist[num] = g_strdup( cmd[2] );  	}  	else if( strcmp( cmd[0], "CHL" ) == 0 )  	{ @@ -356,12 +364,6 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )  		return( msn_write( gc, buf, strlen( buf ) ) );  	} -	else if( strcmp( cmd[0], "QRY" ) == 0 ) -	{ -	} -	else if( strcmp( cmd[0], "QNG" ) == 0 ) -	{ -	}  	else if( strcmp( cmd[0], "ILN" ) == 0 )  	{  		const struct msn_away_state *st; @@ -478,9 +480,6 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )  			msn_buddy_ask( gc, cmd[4], cmd[5] );  		}  	} -	else if( strcmp( cmd[0], "REM" ) == 0 ) -	{ -	}  	else if( strcmp( cmd[0], "OUT" ) == 0 )  	{  		if( cmd[1] && strcmp( cmd[1], "OTH" ) == 0 ) diff --git a/protocols/msn/sb.c b/protocols/msn/sb.c index deaceba1..234be1d6 100644 --- a/protocols/msn/sb.c +++ b/protocols/msn/sb.c @@ -201,9 +201,6 @@ void msn_sb_destroy( struct msn_switchboard *sb )  	debug( "Destroying switchboard: %s", sb->who ? sb->who : sb->key ? sb->key : "" ); -	if( sb->key ) g_free( sb->key ); -	if( sb->who ) g_free( sb->who ); -	  	if( sb->msgq )  	{  		struct msn_message *m; @@ -221,9 +218,12 @@ void msn_sb_destroy( struct msn_switchboard *sb )  		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)" ); +		                   sb->who ? sb->who : "(unknown)" );  	} +	if( sb->key ) g_free( sb->key ); +	if( sb->who ) g_free( sb->who ); +	  	if( sb->chat )  	{  		serv_got_chat_left( gc, sb->chat->id ); diff --git a/protocols/nogaim.c b/protocols/nogaim.c index 29ae860a..04d48236 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -13,7 +13,7 @@   * from scratch for BitlBee and doesn't contain any code from Gaim anymore   * (except for the function names).   * - * Copyright 2002-2004 Wilmer van der Gaast <lintux@lintux.cx> + * Copyright 2002-2006 Wilmer van der Gaast <wilmer@gaast.net> and others   */  /* @@ -36,19 +36,6 @@  #define BITLBEE_CORE  #include "nogaim.h"  #include <ctype.h> -#include <iconv.h> - -static char *proto_away_alias[7][5] = -{ -	{ "Away from computer", "Away", "Extended away", NULL }, -	{ "NA", "N/A", "Not available", NULL }, -	{ "Busy", "Do not disturb", "DND", "Occupied", NULL }, -	{ "Be right back", "BRB", NULL }, -	{ "On the phone", "Phone", "On phone", NULL }, -	{ "Out to lunch", "Lunch", "Food", NULL }, -	{ NULL } -}; -static char *proto_away_alias_find( GList *gcm, char *away );  static int remove_chat_buddy_silent( struct conversation *b, char *handle ); @@ -157,83 +144,6 @@ void nogaim_init()  GSList *get_connections() { return connections; } -int proto_away( struct gaim_connection *gc, char *away ) -{ -	GList *m, *ms; -	char *s; -	 -	if( !away ) away = ""; -	ms = m = gc->prpl->away_states( gc ); -	 -	while( m ) -	{ -		if( *away ) -		{ -			if( g_strncasecmp( m->data, away, strlen( m->data ) ) == 0 ) -				break; -		} -		else -		{ -			if( g_strcasecmp( m->data, "Available" ) == 0 ) -				break; -			if( g_strcasecmp( m->data, "Online" ) == 0 ) -				break; -		} -		m = m->next; -	} -	 -	if( m ) -	{ -		gc->prpl->set_away( gc, m->data, *away ? away : NULL ); -	} -	else -	{ -		s = proto_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 ); -		} -		else -			gc->prpl->set_away( gc, GAIM_AWAY_CUSTOM, away ); -	} -	 -	g_list_free( ms ); -	 -	return( 1 ); -} - -static char *proto_away_alias_find( GList *gcm, char *away ) -{ -	GList *m; -	int i, j; -	 -	for( i = 0; *proto_away_alias[i]; i ++ ) -	{ -		for( j = 0; proto_away_alias[i][j]; j ++ ) -			if( g_strncasecmp( away, proto_away_alias[i][j], strlen( proto_away_alias[i][j] ) ) == 0 ) -				break; -		 -		if( !proto_away_alias[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; proto_away_alias[i][j]; j ++ ) -		{ -			m = gcm; -			while( m ) -			{ -				if( g_strcasecmp( proto_away_alias[i][j], m->data ) == 0 ) -					return( proto_away_alias[i][j] ); -				m = m->next; -			} -		} -	} -	 -	return( NULL ); -} -  /* multi.c */  struct gaim_connection *new_gaim_conn( struct aim_user *user ) @@ -304,36 +214,29 @@ void hide_login_progress_error( struct gaim_connection *gc, char *msg )  void serv_got_crap( struct gaim_connection *gc, char *format, ... )  {  	va_list params; -	char text[1024], buf[1024], acc_id[33]; -	char *msg; +	char *text;  	account_t *a;  	va_start( params, format ); -	g_vsnprintf( text, sizeof( text ), format, params ); +	text = g_strdup_vprintf( format, params );  	va_end( params ); -	if( g_strncasecmp( set_getstr( gc->irc, "charset" ), "none", 4 ) != 0 && -	    do_iconv( "UTF8", set_getstr( gc->irc, "charset" ), text, buf, 0, 1024 ) != -1 ) -		msg = buf; -	else -		msg = text; -	  	if( ( g_strcasecmp( set_getstr( gc->irc, "strip_html" ), "always" ) == 0 ) ||  	    ( ( gc->flags & OPT_CONN_HTML ) && set_getint( gc->irc, "strip_html" ) ) ) -		strip_html( msg ); +		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 )  			break; -	/* If we found one, add the screenname to the acc_id. */ +	/* If we found one, include the screenname in the message. */  	if( a ) -		g_snprintf( acc_id, 32, "%s(%s)", gc->prpl->name, gc->username ); +		irc_usermsg( gc->irc, "%s(%s) - %s", gc->prpl->name, gc->username, text );  	else -		g_snprintf( acc_id, 32, "%s", gc->prpl->name ); +		irc_usermsg( gc->irc, "%s - %s", gc->prpl->name, text ); -	irc_usermsg( gc->irc, "%s - %s", acc_id, msg ); +	g_free( text );  }  static gboolean send_keepalive( gpointer d ) @@ -351,7 +254,7 @@ void account_online( struct gaim_connection *gc )  	user_t *u;  	/* MSN servers sometimes redirect you to a different server and do -	   the whole login sequence again, so subsequent calls to this +	   the whole login sequence again, so these "late" calls to this  	   function should be handled correctly. (IOW, ignored) */  	if( gc->flags & OPT_LOGGED_IN )  		return; @@ -363,18 +266,9 @@ void account_online( struct gaim_connection *gc )  	gc->keepalive = g_timeout_add( 60000, send_keepalive, gc );  	gc->flags |= OPT_LOGGED_IN; -	if( u && u->away ) proto_away( gc, u->away ); -	 - 	if( !strcmp(gc->prpl->name, "icq") ) -	{ -		for( u = gc->irc->users; u; u = u->next ) -			if( u->gc == gc ) -				break; -		 -		if( u == NULL ) -			serv_got_crap( gc, "\x02""***\x02"" BitlBee now supports ICQ server-side contact lists. " -			                      "See \x02""help import_buddies\x02"" for more information." ); -	} +	/* Also necessary when we're not away, at least for some of the +	   protocols. */ +	bim_set_away( gc, u->away );  }  gboolean auto_reconnect( gpointer data ) @@ -393,12 +287,6 @@ void cancel_auto_reconnect( account_t *a )  	a->reconnect = 0;  } -void account_offline( struct gaim_connection *gc ) -{ -	gc->wants_to_die = TRUE; -	signoff( gc ); -} -  void signoff( struct gaim_connection *gc )  {  	irc_t *irc = gc->irc; @@ -469,16 +357,6 @@ void do_ask_dialog( struct gaim_connection *gc, char *msg, void *data, void *doi  /* list.c */ -int bud_list_cache_exists( struct gaim_connection *gc ) -{ -	return( 0 ); -} - -void do_import( struct gaim_connection *gc, void *null ) -{ -	return; -} -  void add_buddy( struct gaim_connection *gc, char *group, char *handle, char *realname )  {  	user_t *u; @@ -514,7 +392,14 @@ void add_buddy( struct gaim_connection *gc, char *group, char *handle, char *rea  	}  	else if( gc->user->proto_opt[0] && *gc->user->proto_opt[0] )  	{ -		u->host = g_strdup( gc->user->proto_opt[0] ); +		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->user = g_strdup( handle );  		/* s/ /_/ ... important for AOL screennames */ @@ -530,6 +415,7 @@ void add_buddy( struct gaim_connection *gc, char *group, char *handle, char *rea  	u->gc = gc;  	u->handle = g_strdup( handle ); +	if( group ) u->group = g_strdup( group );  	u->send_handler = buddy_send_handler;  	u->last_typing_notice = 0;  } @@ -553,11 +439,6 @@ struct buddy *find_buddy( struct gaim_connection *gc, char *handle )  	return( b );  } -void do_export( struct gaim_connection *gc ) -{ -	return; -} -  void signoff_blocked( struct gaim_connection *gc )  {  	return; /* Make all blocked users look invisible (TODO?) */ @@ -567,22 +448,14 @@ void signoff_blocked( struct gaim_connection *gc )  void serv_buddy_rename( struct gaim_connection *gc, char *handle, char *realname )  {  	user_t *u = user_findhandle( gc, handle ); -	char *name, buf[1024];  	if( !u ) return; -	/* Convert all UTF-8 */ -	if( g_strncasecmp( set_getstr( gc->irc, "charset" ), "none", 4 ) != 0 && -	    do_iconv( "UTF-8", set_getstr( gc->irc, "charset" ), realname, buf, 0, sizeof( buf ) ) != -1 ) -		name = buf; -	else -		name = realname; -	 -	if( g_strcasecmp( u->realname, name ) != 0 ) +	if( g_strcasecmp( u->realname, realname ) != 0 )  	{  		if( u->realname != u->nick ) g_free( u->realname ); -		u->realname = g_strdup( name ); +		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 ); @@ -592,9 +465,40 @@ void serv_buddy_rename( struct gaim_connection *gc, char *handle, char *realname  /* prpl.c */ -void show_got_added( struct gaim_connection *gc, char *id, char *handle, const char *realname, const char *msg ) +struct show_got_added_data +{ +	struct gaim_connection *gc; +	char *handle; +}; + +void show_got_added_no( gpointer w, struct show_got_added_data *data ) +{ +	g_free( data->handle ); +	g_free( data ); +} + +void show_got_added_yes( gpointer w, struct show_got_added_data *data )  { -	return; +	data->gc->prpl->add_buddy( data->gc, data->handle ); +	add_buddy( data->gc, 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 ) +{ +	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 ) +		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->handle = g_strdup( handle ); +	query_add( gc->irc, gc, s, show_got_added_yes, show_got_added_no, data );  } @@ -624,7 +528,8 @@ void serv_got_update( struct gaim_connection *gc, char *handle, int loggedin, in  			return;  		} -		return; +		/* Why did we have this here.... +		return; */  	}  	oa = u->away != NULL; @@ -688,7 +593,6 @@ void serv_got_im( struct gaim_connection *gc, char *handle, char *msg, guint32 f  {  	irc_t *irc = gc->irc;  	user_t *u; -	char buf[8192];  	u = user_findhandle( gc, handle ); @@ -730,10 +634,6 @@ void serv_got_im( struct gaim_connection *gc, char *handle, char *msg, guint32 f  	    ( ( gc->flags & OPT_CONN_HTML ) && set_getint( gc->irc, "strip_html" ) ) )  		strip_html( msg ); -	if( g_strncasecmp( set_getstr( irc, "charset" ), "none", 4 ) != 0 && -	    do_iconv( "UTF-8", set_getstr( irc, "charset" ), msg, buf, 0, 8192 ) != -1 ) -		msg = buf; -	  	while( strlen( msg ) > 425 )  	{  		char tmp, *nl; @@ -830,7 +730,6 @@ void serv_got_chat_in( struct gaim_connection *gc, int id, char *who, int whispe  {  	struct conversation *c;  	user_t *u; -	char buf[8192];  	/* Gaim sends own messages through this too. IRC doesn't want this, so kill them */  	if( g_strcasecmp( who, gc->user->username ) == 0 ) @@ -843,10 +742,6 @@ void serv_got_chat_in( struct gaim_connection *gc, int id, char *who, int whispe  	    ( ( gc->flags & OPT_CONN_HTML ) && set_getint( gc->irc, "strip_html" ) ) )  		strip_html( msg ); -	if( g_strncasecmp( set_getstr( gc->irc, "charset" ), "none", 4 ) != 0 && -	    do_iconv( "UTF-8", set_getstr( gc->irc, "charset" ), msg, buf, 0, 8192 ) != -1 ) -		msg = buf; -	  	if( c && u )  		irc_privmsg( gc->irc, u, "PRIVMSG", c->channel, "", msg );  	else @@ -883,11 +778,6 @@ struct conversation *serv_got_joined_chat( struct gaim_connection *gc, int id, c  	return( c );  } -void serv_finish_login( struct gaim_connection *gc ) -{ -	return; -} -  /* buddy_chat.c */ @@ -972,20 +862,6 @@ static int remove_chat_buddy_silent( struct conversation *b, char *handle )  } -/* prefs.c */ - -/* Necessary? */ -void build_block_list() -{ -	return; -} - -void build_allow_list() -{ -	return; -} - -  /* Misc. BitlBee stuff which shouldn't really be here */  struct conversation *conv_findchannel( char *channel ) @@ -1064,89 +940,179 @@ char *set_eval_away_devoice( irc_t *irc, set_t *set, char *value )  	return( set_eval_bool( irc, set, value ) );  } -int serv_send_im( irc_t *irc, user_t *u, char *msg, int flags ) + + + +/* 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 )  { -	char buf[8192]; +	char *buf = NULL; +	int st; -	if( g_strncasecmp( set_getstr( irc, "charset" ), "none", 4 ) != 0 && -	    do_iconv( set_getstr( irc, "charset" ), "UTF-8", msg, buf, 0, 8192 ) != -1 ) -		msg = buf; - -	if( ( u->gc->flags & OPT_CONN_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) ) +	if( ( gc->flags & OPT_CONN_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) )  	{ -		char *html; -		 -		html = escape_html( msg ); -		strncpy( buf, html, 8192 ); -		g_free( html ); -		 +		buf = escape_html( msg );  		msg = buf;  	} -	return( ((struct gaim_connection *)u->gc)->prpl->send_im( u->gc, u->handle, msg, strlen( msg ), flags ) ); +	st = gc->prpl->send_im( gc, handle, msg, strlen( msg ), flags ); +	g_free( buf ); +	 +	return st;  } -int serv_send_chat( irc_t *irc, struct gaim_connection *gc, int id, char *msg ) +int bim_chat_msg( struct gaim_connection *gc, int id, char *msg )  { -	char buf[8192]; +	char *buf = NULL; +	int st; -	if( g_strncasecmp( set_getstr( irc, "charset" ), "none", 4 ) != 0 && -	    do_iconv( set_getstr( irc, "charset" ), "UTF-8", msg, buf, 0, 8192 ) != -1 ) +	if( ( gc->flags & OPT_CONN_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) ) +	{ +		buf = escape_html( msg );  		msg = buf; - -	if( gc->flags & OPT_CONN_HTML) { -		char * html = escape_html(msg); -		strncpy(buf, html, 8192); -		g_free(html);  	} -	return( gc->prpl->chat_send( gc, id, msg ) ); +	st = gc->prpl->chat_send( gc, id, msg ); +	g_free( buf ); +	 +	return st;  } -/* Convert from one charset to another. -    -   from_cs, to_cs: Source and destination charsets -   src, dst: Source and destination strings -   size: Size if src. 0 == use strlen(). strlen() is not reliable for UNICODE/UTF16 strings though. -   maxbuf: Maximum number of bytes to write to dst -    -   Returns the number of bytes written to maxbuf or -1 on an error. -*/ -signed int do_iconv( char *from_cs, char *to_cs, char *src, char *dst, size_t size, size_t maxbuf ) +static char *bim_away_alias_find( GList *gcm, char *away ); + +int bim_set_away( struct gaim_connection *gc, char *away )  { -	iconv_t cd; -	size_t res; -	size_t inbytesleft, outbytesleft; -	char *inbuf = src; -	char *outbuf = dst; -	 -	cd = iconv_open( to_cs, from_cs ); -	if( cd == (iconv_t) -1 ) -		return( -1 ); -	 -	inbytesleft = size ? size : strlen( src ); -	outbytesleft = maxbuf - 1; -	res = iconv( cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft ); -	*outbuf = '\0'; -	iconv_close( cd ); -	 -	if( res == (size_t) -1 ) -		return( -1 ); +	GList *m, *ms; +	char *s; +	 +	if( !away ) away = ""; +	ms = m = gc->prpl->away_states( gc ); +	 +	while( m ) +	{ +		if( *away ) +		{ +			if( g_strncasecmp( m->data, away, strlen( m->data ) ) == 0 ) +				break; +		} +		else +		{ +			if( g_strcasecmp( m->data, "Available" ) == 0 ) +				break; +			if( g_strcasecmp( m->data, "Online" ) == 0 ) +				break; +		} +		m = m->next; +	} +	 +	if( m ) +	{ +		gc->prpl->set_away( gc, m->data, *away ? away : NULL ); +	}  	else -		return( outbuf - dst ); +	{ +		s = bim_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 ); +		} +		else +			gc->prpl->set_away( gc, GAIM_AWAY_CUSTOM, away ); +	} +	 +	g_list_free( ms ); +	 +	return( 1 );  } -char *set_eval_charset( irc_t *irc, set_t *set, char *value ) +static char *bim_away_alias_list[8][5] =  { -	iconv_t cd; +	{ "Away from computer", "Away", "Extended away", NULL }, +	{ "NA", "N/A", "Not available", NULL }, +	{ "Busy", "Do not disturb", "DND", "Occupied", NULL }, +	{ "Be right back", "BRB", NULL }, +	{ "On the phone", "Phone", "On phone", NULL }, +	{ "Out to lunch", "Lunch", "Food", NULL }, +	{ "Invisible", "Hidden" }, +	{ NULL } +}; -	if ( g_strncasecmp( value, "none", 4 ) == 0 ) -		return( value ); +static char *bim_away_alias_find( GList *gcm, char *away ) +{ +	GList *m; +	int i, j; +	 +	for( i = 0; *bim_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 ) +				break; +		 +		if( !bim_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 ++ ) +		{ +			m = gcm; +			while( m ) +			{ +				if( g_strcasecmp( bim_away_alias_list[i][j], m->data ) == 0 ) +					return( bim_away_alias_list[i][j] ); +				m = m->next; +			} +		} +	} +	 +	return( NULL ); +} -	cd = iconv_open( "UTF-8", value ); -	if( cd == (iconv_t) -1 ) -		return( NULL ); +void bim_add_allow( struct gaim_connection *gc, char *handle ) +{ +	if( g_slist_find_custom( gc->permit, handle, (GCompareFunc) gc->prpl->cmp_buddynames ) == NULL ) +	{ +		gc->permit = g_slist_prepend( gc->permit, g_strdup( handle ) ); +	} +	 +	gc->prpl->add_permit( gc, handle ); +} + +void bim_rem_allow( struct gaim_connection *gc, char *handle ) +{ +	GSList *l; +	 +	if( ( l = g_slist_find_custom( gc->permit, handle, (GCompareFunc) gc->prpl->cmp_buddynames ) ) ) +	{ +		g_free( l->data ); +		gc->permit = g_slist_delete_link( gc->permit, l ); +	} +	 +	gc->prpl->rem_permit( gc, handle ); +} -	iconv_close( cd ); -	return( value ); +void bim_add_block( struct gaim_connection *gc, char *handle ) +{ +	if( g_slist_find_custom( gc->deny, handle, (GCompareFunc) gc->prpl->cmp_buddynames ) == NULL ) +	{ +		gc->deny = g_slist_prepend( gc->deny, g_strdup( handle ) ); +	} +	 +	gc->prpl->add_deny( gc, handle ); +} + +void bim_rem_block( struct gaim_connection *gc, char *handle ) +{ +	GSList *l; +	 +	if( ( l = g_slist_find_custom( gc->deny, handle, (GCompareFunc) gc->prpl->cmp_buddynames ) ) ) +	{ +		g_free( l->data ); +		gc->deny = g_slist_delete_link( gc->deny, l ); +	} +	 +	gc->prpl->rem_deny( gc, handle );  } diff --git a/protocols/nogaim.h b/protocols/nogaim.h index afc39a80..3721361c 100644 --- a/protocols/nogaim.h +++ b/protocols/nogaim.h @@ -14,7 +14,7 @@   *   * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net>   *                          (and possibly other members of the Gaim team) - * Copyright 2002-2004 Wilmer van der Gaast <lintux@lintux.cx> + * Copyright 2002-2004 Wilmer van der Gaast <wilmer@gaast.net>   */  /* @@ -51,31 +51,24 @@  #define SELF_ALIAS_LEN 400  #define BUDDY_ALIAS_MAXLEN 388   /* because MSN names can be 387 characters */ -#define PERMIT_ALL      1 -#define PERMIT_NONE     2 -#define PERMIT_SOME     3 -#define DENY_SOME       4 -  #define WEBSITE "http://www.bitlee.org/"  #define IM_FLAG_AWAY 0x0020  #define OPT_CONN_HTML 0x00000001  #define OPT_LOGGED_IN 0x00010000  #define GAIM_AWAY_CUSTOM "Custom" -#define GAIM_LOGO	0 -#define GAIM_ERROR	1 -#define GAIM_WARNING	2 -#define GAIM_INFO	3 -  /* ok. now the fun begins. first we create a connection structure */ -struct gaim_connection { -	/* we need to do either oscar or TOC */ -	/* we make this as an int in case if we want to add more protocols later */ +struct gaim_connection +{  	struct prpl *prpl;  	guint32 flags; +	/* each connection then can have its own protocol-specific data */ +	void *proto_data; +	  	/* all connections need an input watcher */  	int inpa; +	guint keepalive;  	/* buddy list stuff. there is still a global groups for the buddy list, but  	 * we need to maintain our own set of buddies, and our own permit/deny lists */ @@ -83,33 +76,19 @@ struct gaim_connection {  	GSList *deny;  	int permdeny; -	/* all connections need a list of chats, even if they don't have chat */ -	GSList *buddy_chats; -	 -	/* each connection then can have its own protocol-specific data */ -	void *proto_data; -	  	struct aim_user *user;  	char username[64];  	char displayname[128];  	char password[32]; -	guint keepalive; -	/* stuff needed for per-connection idle times */ -	guint idle_timer; -	time_t login_time; -	time_t lastsent; -	int is_idle;  	char *away; -	int is_auto_away;  	int evil;  	gboolean wants_to_die; /* defaults to FALSE */  	/* BitlBee */  	irc_t *irc; -	int lstitems;  /* added for msnP8 */  	struct conversation *conversations;  }; @@ -182,66 +161,41 @@ struct prpl {  	int options;  	const char *name; -	/* for ICQ and Yahoo, who have off/on per-conversation options */ -	/* char *checkbox; this should be per-connection */ - -	GList *(* away_states)(struct gaim_connection *gc); -	GList *(* actions)(); -	void   (* do_action)(struct gaim_connection *, char *); -	/* user_opts returns a GList* of g_malloc'd struct proto_user_opts */ -	GList *(* user_opts)(); -	GList *(* chat_info)(struct gaim_connection *); - -	/* all the server-related functions */ - -	/* a lot of these (like get_dir) are protocol-dependent and should be removed. ones like -	 * set_dir (which is also protocol-dependent) can stay though because there's a dialog -	 * (i.e. the prpl says you can set your dir info, the ui shows a dialog and needs to call -	 * set_dir in order to set it) */ -  	void (* login)		(struct aim_user *); +	void (* keepalive)	(struct gaim_connection *);  	void (* close)		(struct gaim_connection *); +	  	int  (* send_im)	(struct gaim_connection *, char *who, char *message, int len, int away); -	int  (* send_typing)	(struct gaim_connection *, char *who, int typing); -	void (* set_info)	(struct gaim_connection *, char *info); -	void (* get_info)	(struct gaim_connection *, char *who);  	void (* set_away)	(struct gaim_connection *, char *state, char *message);  	void (* get_away)       (struct gaim_connection *, char *who); -	void (* set_idle)	(struct gaim_connection *, int idletime); +	int  (* send_typing)	(struct gaim_connection *, char *who, int typing); +	  	void (* add_buddy)	(struct gaim_connection *, char *name); +	void (* group_buddy)	(struct gaim_connection *, char *who, char *old_group, char *new_group);  	void (* remove_buddy)	(struct gaim_connection *, char *name, char *group);  	void (* add_permit)	(struct gaim_connection *, char *name);  	void (* add_deny)	(struct gaim_connection *, char *name);  	void (* rem_permit)	(struct gaim_connection *, char *name);  	void (* rem_deny)	(struct gaim_connection *, char *name);  	void (* set_permit_deny)(struct gaim_connection *); +	 +	void (* set_info)	(struct gaim_connection *, char *info); +	void (* get_info)	(struct gaim_connection *, char *who); +	void (* alias_buddy)	(struct gaim_connection *, char *who);	/* save/store buddy's alias on server list/roster */ +	 +	/* Group chat stuff. */  	void (* join_chat)	(struct gaim_connection *, GList *data);  	void (* chat_invite)	(struct gaim_connection *, int id, char *who, char *message);  	void (* chat_leave)	(struct gaim_connection *, int id); -	void (* chat_whisper)	(struct gaim_connection *, int id, char *who, char *message);  	int  (* chat_send)	(struct gaim_connection *, int id, char *message);  	int  (* chat_open)	(struct gaim_connection *, char *who); -	void (* keepalive)	(struct gaim_connection *); - -	/* get "chat buddy" info and away message */ -	void (* get_cb_info)	(struct gaim_connection *, int, char *who); -	void (* get_cb_away)	(struct gaim_connection *, int, char *who); - -	/* save/store buddy's alias on server list/roster */ -	void (* alias_buddy)	(struct gaim_connection *, char *who); - -	/* change a buddy's group on a server list/roster */ -	void (* group_buddy)	(struct gaim_connection *, char *who, char *old_group, char *new_group); - -	/* file transfers */ -	struct ft_send_req *(* req_send_file) (struct gaim_connection *, const char *file); -	void (* send_file_part) (struct gaim_connection *, struct ft*, void *data, size_t length); -	void (* accept_recv_file) (struct gaim_connection *, struct ft*, ft_recv_handler); - -	void (* buddy_free)	(struct buddy *); - +	 +	/* DIE! */  	char *(* get_status_string) (struct gaim_connection *gc, int stat); - +	 +	GList *(* away_states)(struct gaim_connection *gc); +	 +	/* Mainly for AOL, since they think "Bung hole" == "Bu ngho le". *sigh* */  	int (* cmp_buddynames) (const char *who1, const char *who2);  }; @@ -258,14 +212,16 @@ G_MODULE_EXPORT struct prpl *find_protocol(const char *name);  G_MODULE_EXPORT void register_protocol(struct prpl *);  /* nogaim.c */ -int serv_send_im(irc_t *irc, user_t *u, char *msg, int flags); -int serv_send_chat(irc_t *irc, struct gaim_connection *gc, int id, char *msg ); +int bim_set_away( struct gaim_connection *gc, char *away ); +int bim_buddy_msg( struct gaim_connection *gc, char *handle, char *msg, int flags ); +int bim_chat_msg( struct gaim_connection *gc, int id, char *msg ); -G_MODULE_EXPORT signed int do_iconv( char *from_cs, char *to_cs, char *src, char *dst, size_t size, size_t maxbuf ); -char *set_eval_charset( irc_t *irc, set_t *set, char *value ); +void bim_add_allow( struct gaim_connection *gc, char *handle ); +void bim_rem_allow( struct gaim_connection *gc, char *handle ); +void bim_add_block( struct gaim_connection *gc, char *handle ); +void bim_rem_block( struct gaim_connection *gc, char *handle );  void nogaim_init(); -int proto_away( struct gaim_connection *gc, char *away );  char *set_eval_away_devoice( irc_t *irc, set_t *set, char *value );  gboolean auto_reconnect( gpointer data ); @@ -277,9 +233,8 @@ G_MODULE_EXPORT void destroy_gaim_conn( struct gaim_connection *gc );  G_MODULE_EXPORT void set_login_progress( struct gaim_connection *gc, int step, char *msg );  G_MODULE_EXPORT void hide_login_progress( struct gaim_connection *gc, char *msg );  G_MODULE_EXPORT void hide_login_progress_error( struct gaim_connection *gc, char *msg ); -G_MODULE_EXPORT void serv_got_crap( struct gaim_connection *gc, char *format, ... ); +G_MODULE_EXPORT void serv_got_crap( struct gaim_connection *gc, char *format, ... ) G_GNUC_PRINTF( 2, 3 );  G_MODULE_EXPORT void account_online( struct gaim_connection *gc ); -G_MODULE_EXPORT void account_offline( struct gaim_connection *gc );  G_MODULE_EXPORT void signoff( struct gaim_connection *gc );  /* dialogs.c */ @@ -287,11 +242,8 @@ G_MODULE_EXPORT void do_error_dialog( struct gaim_connection *gc, char *msg, cha  G_MODULE_EXPORT void do_ask_dialog( struct gaim_connection *gc, char *msg, void *data, void *doit, void *dont );  /* list.c */ -G_MODULE_EXPORT int bud_list_cache_exists( struct gaim_connection *gc ); -G_MODULE_EXPORT void do_import( struct gaim_connection *gc, void *null );  G_MODULE_EXPORT void add_buddy( struct gaim_connection *gc, char *group, char *handle, char *realname );  G_MODULE_EXPORT struct buddy *find_buddy( struct gaim_connection *gc, char *handle ); -G_MODULE_EXPORT void do_export( struct gaim_connection *gc );  G_MODULE_EXPORT void signoff_blocked( struct gaim_connection *gc );  G_MODULE_EXPORT void serv_buddy_rename( struct gaim_connection *gc, char *handle, char *realname ); @@ -301,7 +253,7 @@ G_MODULE_EXPORT void add_chat_buddy( struct conversation *b, char *handle );  G_MODULE_EXPORT void remove_chat_buddy( struct conversation *b, char *handle, char *reason );  /* prpl.c */ -G_MODULE_EXPORT void show_got_added( struct gaim_connection *gc, char *id, char *handle, const char *realname, const char *msg ); +G_MODULE_EXPORT void show_got_added( struct gaim_connection *gc, char *handle, const char *realname );  /* server.c */                      G_MODULE_EXPORT void serv_got_update( struct gaim_connection *gc, char *handle, int loggedin, int evil, time_t signon, time_t idle, int type, guint caps ); @@ -312,23 +264,6 @@ G_MODULE_EXPORT struct conversation *serv_got_joined_chat( struct gaim_connectio  G_MODULE_EXPORT void serv_got_chat_in( struct gaim_connection *gc, int id, char *who, int whisper, char *msg, time_t mtime );  G_MODULE_EXPORT void serv_got_chat_left( struct gaim_connection *gc, int id ); -/* util.c */ -G_MODULE_EXPORT void strip_linefeed( gchar *text ); -G_MODULE_EXPORT char *add_cr( char *text ); -G_MODULE_EXPORT char *tobase64( const char *text ); -G_MODULE_EXPORT char *normalize( const char *s ); -G_MODULE_EXPORT time_t get_time( int year, int month, int day, int hour, int min, int sec ); -G_MODULE_EXPORT void strip_html( char *msg ); -G_MODULE_EXPORT char *escape_html( const char *html ); -G_MODULE_EXPORT void info_string_append(GString *str, char *newline, char *name, char *value); -G_MODULE_EXPORT char *ipv6_wrap( char *src ); -G_MODULE_EXPORT char *ipv6_unwrap( char *src ); - -/* prefs.c */ -G_MODULE_EXPORT void build_block_list(); -G_MODULE_EXPORT void build_allow_list(); -  struct conversation *conv_findchannel( char *channel ); -  #endif diff --git a/protocols/oscar/aim.h b/protocols/oscar/aim.h index 24cd7730..93887103 100644 --- a/protocols/oscar/aim.h +++ b/protocols/oscar/aim.h @@ -727,8 +727,11 @@ struct aim_chat_exchangeinfo {  	char *lang2;  }; -#define AIM_CHATFLAGS_NOREFLECT 0x0001 -#define AIM_CHATFLAGS_AWAY      0x0002 +#define AIM_CHATFLAGS_NOREFLECT 	0x0001 +#define AIM_CHATFLAGS_AWAY      	0x0002 +#define AIM_CHATFLAGS_UNICODE		0x0004 +#define AIM_CHATFLAGS_ISO_8859_1	0x0008 +  int aim_chat_send_im(aim_session_t *sess, aim_conn_t *conn, guint16 flags, const char *msg, int msglen);  int aim_chat_join(aim_session_t *sess, aim_conn_t *conn, guint16 exchange, const char *roomname, guint16 instance);  int aim_chat_attachname(aim_conn_t *conn, guint16 exchange, const char *roomname, guint16 instance); diff --git a/protocols/oscar/chat.c b/protocols/oscar/chat.c index 033c2577..8843b499 100644 --- a/protocols/oscar/chat.c +++ b/protocols/oscar/chat.c @@ -158,7 +158,19 @@ int aim_chat_send_im(aim_session_t *sess, aim_conn_t *conn, guint16 flags, const  	 */  	if (flags & AIM_CHATFLAGS_AWAY)  		aim_addtlvtochain_noval(&otl, 0x0007); - +	 +	/* [WvG] This wasn't there originally, but we really should send +	         the right charset flags, as we also do with normal +	         messages. Hope this will work. :-) */ +	if (flags & AIM_CHATFLAGS_UNICODE) +		aimbs_put16(&fr->data, 0x0002); +	else if (flags & AIM_CHATFLAGS_ISO_8859_1) +		aimbs_put16(&fr->data, 0x0003); +	else +		aimbs_put16(&fr->data, 0x0000); +	 +	aimbs_put16(&fr->data, 0x0000); +	  	/*  	 * SubTLV: Type 1: Message  	 */ diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c index 4e552bce..5174f95c 100644 --- a/protocols/oscar/oscar.c +++ b/protocols/oscar/oscar.c @@ -1,6 +1,8 @@  /*   * gaim   * + * Some code copyright (C) 2002-2006, Jelmer Vernooij <jelmer@samba.org> + *                                    and the BitlBee team.   * Some code copyright (C) 1998-1999, Mark Spencer <markster@marko.net>   * libfaim code copyright 1998, 1999 Adam Fritzler <afritz@auk.cx>   * @@ -355,7 +357,9 @@ static void oscar_login(struct aim_user *user) {  	if (isdigit(*user->username)) {  		odata->icq = TRUE; -		/* this is odd but it's necessary for a proper do_import and do_export */ +		/* This is odd but it's necessary for a proper do_import and do_export. +		   We don't do those anymore, but let's stick with it, just in case +		   it accidentally fixes something else too... */  		gc->password[8] = 0;  	} else {  		gc->flags |= OPT_CONN_HTML; @@ -380,7 +384,7 @@ static void oscar_login(struct aim_user *user) {  	if (g_strcasecmp(user->proto_opt[USEROPT_AUTH], "login.icq.com") != 0 &&  	    g_strcasecmp(user->proto_opt[USEROPT_AUTH], "login.oscar.aol.com") != 0) { -		serv_got_crap(gc, "Warning: Unknown OSCAR server: `%s'. Please review your configuration if the connection fails."); +		serv_got_crap(gc, "Warning: Unknown OSCAR server: `%s'. Please review your configuration if the connection fails.",user->proto_opt[USEROPT_AUTH]);  	}  	g_snprintf(buf, sizeof(buf), _("Signon: %s"), gc->username); @@ -1116,7 +1120,8 @@ static void gaim_icq_authgrant(gpointer w, struct icq_auth *data) {  	message = 0;  	aim_ssi_auth_reply(od->sess, od->conn, uin, 1, "");  	// aim_send_im_ch4(od->sess, uin, AIM_ICQMSG_AUTHGRANTED, &message); -	show_got_added(data->gc, NULL, uin, NULL, NULL); +	if(find_buddy(data->gc, uin) == NULL) +		show_got_added(data->gc, uin, NULL);  	g_free(uin);  	g_free(data); @@ -1147,7 +1152,7 @@ static void gaim_icq_authask(struct gaim_connection *gc, guint32 uin, char *msg)  	if (strlen(msg) > 6)  		reason = msg + 6; -	dialog_msg = g_strdup_printf("The user %u wants to add you to their buddy list for the following reason:\n\n%s", uin, reason ? reason : "No reason given."); +	dialog_msg = g_strdup_printf("The user %u wants to add you to their buddy list for the following reason: %s", uin, reason ? reason : "No reason given.");  	data->gc = gc;  	data->uin = uin;  	do_ask_dialog(gc, dialog_msg, data, gaim_icq_authgrant, gaim_icq_authdeny); @@ -1736,11 +1741,6 @@ static int gaim_bosrights(aim_session_t *sess, aim_frame_t *fr, ...) {  	odata->rights.maxpermits = (guint)maxpermits;  	odata->rights.maxdenies = (guint)maxdenies; -//	serv_finish_login(gc); - -	if (bud_list_cache_exists(gc)) -		do_import(gc, NULL); -  	aim_clientready(sess, fr->conn);  	aim_reqservice(sess, fr->conn, AIM_CONN_TYPE_CHATNAV); @@ -2059,7 +2059,6 @@ static int gaim_ssi_parselist(aim_session_t *sess, aim_frame_t *fr, ...) {  						char *name;  						name = g_strdup(normalize(curitem->name));  						gc->permit = g_slist_append(gc->permit, name); -						build_allow_list();  						tmp++;  					}  				} @@ -2073,7 +2072,6 @@ static int gaim_ssi_parselist(aim_session_t *sess, aim_frame_t *fr, ...) {  						char *name;  						name = g_strdup(normalize(curitem->name));  						gc->deny = g_slist_append(gc->deny, name); -						build_block_list();  						tmp++;  					}  				} @@ -2095,8 +2093,6 @@ static int gaim_ssi_parselist(aim_session_t *sess, aim_frame_t *fr, ...) {  		} /* End of switch on curitem->type */  	} /* End of for loop */ -	if (tmp) -		do_export(gc);  	aim_ssi_enable(sess, fr->conn);  	/* Request offline messages, now that the buddy list is complete. */ @@ -2281,7 +2277,7 @@ static int gaim_icqinfo(aim_session_t *sess, aim_frame_t *fr, ...)                  struct tm tm;                  tm.tm_mday = (int)info->birthday;                  tm.tm_mon = (int)info->birthmonth-1; -                tm.tm_year = (int)info->birthyear-1900; +                tm.tm_year = (int)info->birthyear%100;                  strftime(date, sizeof(date), "%Y-%m-%d", &tm);                  info_string_append(str, "\n", _("Birthday"), date);          } @@ -2505,6 +2501,7 @@ int oscar_chat_send(struct gaim_connection * gc, int id, char *message)  	struct chat_connection * ccon;  	int ret;  	guint8 len = strlen(message); +	guint16 flags;  	char *s;  	if(!(ccon = find_oscar_chat(gc, id))) @@ -2513,15 +2510,19 @@ int oscar_chat_send(struct gaim_connection * gc, int id, char *message)  	for (s = message; *s; s++)  		if (*s & 128)  			break; -	  	 +	 +	flags = AIM_CHATFLAGS_NOREFLECT; +	  	/* Message contains high ASCII chars, time for some translation! */  	if (*s) {  		s = g_malloc(BUF_LONG);  		/* Try if we can put it in an ISO8859-1 string first.  		   If we can't, fall back to UTF16. */  		if ((ret = do_iconv("UTF-8", "ISO8859-1", message, s, len, BUF_LONG)) >= 0) { +			flags |= AIM_CHATFLAGS_ISO_8859_1;  			len = ret;  		} else if ((ret = do_iconv("UTF-8", "UNICODEBIG", message, s, len, BUF_LONG)) >= 0) { +			flags |= AIM_CHATFLAGS_UNICODE;  			len = ret;  		} else {  			/* OOF, translation failed... Oh well.. */ @@ -2532,7 +2533,7 @@ int oscar_chat_send(struct gaim_connection * gc, int id, char *message)  		s = message;  	} -	ret = aim_chat_send_im(od->sess, ccon->conn, AIM_CHATFLAGS_NOREFLECT, s, len); +	ret = aim_chat_send_im(od->sess, ccon->conn, flags, s, len);  	if (s != message) {	  		g_free(s); diff --git a/protocols/oscar/oscar_util.c b/protocols/oscar/oscar_util.c index 1bb27559..0ce06bd9 100644 --- a/protocols/oscar/oscar_util.c +++ b/protocols/oscar/oscar_util.c @@ -108,7 +108,7 @@ static int aim_snlen(const char *sn)  		return 0;  	curPtr = sn; -	while ( (*curPtr) != (char) NULL) { +	while ( (*curPtr) != (char) '\0') {  		if ((*curPtr) != ' ')  		i++;  		curPtr++; @@ -139,7 +139,7 @@ int aim_sncmp(const char *sn1, const char *sn2)  	curPtr1 = sn1;  	curPtr2 = sn2; -	while ( (*curPtr1 != (char) NULL) && (*curPtr2 != (char) NULL) ) { +	while ( (*curPtr1 != (char) '\0') && (*curPtr2 != (char) '\0') ) {  		if ( (*curPtr1 == ' ') || (*curPtr2 == ' ') ) {  			if (*curPtr1 == ' ')  				curPtr1++; diff --git a/protocols/oscar/service.c b/protocols/oscar/service.c index 573e1983..4596974f 100644 --- a/protocols/oscar/service.c +++ b/protocols/oscar/service.c @@ -732,7 +732,7 @@ int aim_setextstatus(aim_session_t *sess, aim_conn_t *conn, guint32 status)  	guint32 data;  	int tlvlen; -	data = AIM_ICQ_STATE_WEBAWARE | AIM_ICQ_STATE_HIDEIP | status; /* yay for error checking ;^) */ +	data = AIM_ICQ_STATE_HIDEIP | status; /* yay for error checking ;^) */  	tlvlen = aim_addtlvtochain32(&tl, 0x0006, data); @@ -880,13 +880,14 @@ int aim_sendmemblock(aim_session_t *sess, aim_conn_t *conn, guint32 offset, guin  			aimbs_put32(&fr->data, 0xa46d3b39);  #endif +/* len can't be 0 here anyway...  		} else if ((offset == 0x00001000) && (len == 0x00000000)) {  			aimbs_put32(&fr->data, 0xd41d8cd9);  			aimbs_put32(&fr->data, 0x8f00b204);  			aimbs_put32(&fr->data, 0xe9800998);  			aimbs_put32(&fr->data, 0xecf8427e); - +*/  		} else  			do_error_dialog(sess->aux_data, "WARNING: unknown hash request", "Gaim"); diff --git a/protocols/ssl_nss.c b/protocols/ssl_nss.c index dfd32622..00d32834 100644 --- a/protocols/ssl_nss.c +++ b/protocols/ssl_nss.c @@ -121,10 +121,10 @@ static void ssl_connected( gpointer data, gint source, GaimInputCondition cond )  	if( source == -1 )  		goto ssl_connected_failure; - - - +	/* Until we find out how to handle non-blocking I/O with NSS... */ +	sock_make_blocking( conn->fd ); +	  	conn->prfd = SSL_ImportFD(NULL, PR_ImportTCPSocket(source));  	SSL_OptionSet(conn->prfd, SSL_SECURITY, PR_TRUE);  	SSL_OptionSet(conn->prfd, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE); @@ -180,3 +180,9 @@ int ssl_getfd( void *conn )  {  	return( ((struct scd*)conn)->fd );  } + +GaimInputCondition ssl_getdirection( void *conn ) +{ +	/* Just in case someone calls us, let's return the most likely case: */ +	return GAIM_INPUT_READ; +} diff --git a/protocols/ssl_openssl.c b/protocols/ssl_openssl.c index e62f95b9..b79088cc 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 - OpenTLS version                                          */ +/* SSL module - OpenSSL version                                         */  /*    This program is free software; you can redistribute it and/or modify @@ -40,11 +40,13 @@ static gboolean initialized = FALSE;  struct scd  { -	SslInputFunction func; +	ssl_input_function func;  	gpointer data;  	int fd;  	gboolean established; +	int inpa; +	int lasterr;		/* Necessary for SSL_get_error */  	SSL *ssl;  	SSL_CTX *ssl_ctx;  }; @@ -53,7 +55,7 @@ static void ssl_connected( gpointer data, gint source, GaimInputCondition cond ) -void *ssl_connect( char *host, int port, SslInputFunction func, gpointer data ) +void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data )  {  	struct scd *conn = g_new0( struct scd, 1 );  	SSL_METHOD *meth; @@ -92,19 +94,45 @@ void *ssl_connect( char *host, int port, SslInputFunction 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 ) -		goto ssl_connected_failure; +		return ssl_handshake( data, -1, cond ); +	/* Make it non-blocking at least during the handshake... */ +	sock_make_nonblocking( conn->fd );  	SSL_set_fd( conn->ssl, conn->fd ); -	if( SSL_connect( conn->ssl ) < 0 ) -		goto ssl_connected_failure; +	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; +	}  	conn->established = TRUE; +	sock_make_blocking( conn->fd );		/* For now... */  	conn->func( conn->data, conn, cond );  	return; @@ -126,24 +154,57 @@ ssl_connected_failure:  int ssl_read( void *conn, char *buf, int len )  { +	int st; +	  	if( !((struct scd*)conn)->established ) -		return( 0 ); +	{ +		ssl_errno = SSL_NOHANDSHAKE; +		return -1; +	} +	 +	st = SSL_read( ((struct scd*)conn)->ssl, buf, len ); -	return( SSL_read( ((struct scd*)conn)->ssl, buf, len ) ); +	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;  }  int ssl_write( void *conn, const char *buf, int len )  { +	int st; +	  	if( !((struct scd*)conn)->established ) -		return( 0 ); +	{ +		ssl_errno = SSL_NOHANDSHAKE; +		return -1; +	} +	 +	st = SSL_write( ((struct scd*)conn)->ssl, buf, len ); -	return( SSL_write( ((struct scd*)conn)->ssl, buf, len ) ); +	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;  }  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 ); @@ -158,3 +219,8 @@ 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 ); +} diff --git a/protocols/yahoo/yahoo.c b/protocols/yahoo/yahoo.c index 4f257d99..1c3c73d9 100644 --- a/protocols/yahoo/yahoo.c +++ b/protocols/yahoo/yahoo.c @@ -226,16 +226,11 @@ static void byahoo_set_away( struct gaim_connection *gc, char *state, char *msg  			yd->current_status = YAHOO_STATUS_INVISIBLE;  		else if( g_strcasecmp( state, GAIM_AWAY_CUSTOM ) == 0 )  		{ -			if (gc->is_idle) -				yd->current_status = YAHOO_STATUS_IDLE; -			else -				yd->current_status = YAHOO_STATUS_AVAILABLE; +			yd->current_status = YAHOO_STATUS_AVAILABLE;  			gc->away = NULL;  		}  	} -	else if( gc->is_idle ) -		yd->current_status = YAHOO_STATUS_IDLE;  	else  		yd->current_status = YAHOO_STATUS_AVAILABLE; @@ -614,7 +609,8 @@ void ext_yahoo_status_changed( int id, char *who, int stat, char *msg, int away  {  	struct gaim_connection *gc = byahoo_get_gc_by_id( id ); -	serv_got_update( gc, who, stat != YAHOO_STATUS_OFFLINE, 0, 0, 0, +	serv_got_update( gc, who, stat != YAHOO_STATUS_OFFLINE, 0, 0, +	                 ( stat == YAHOO_STATUS_IDLE ) ? away : 0,  	                 ( stat != YAHOO_STATUS_AVAILABLE ) | ( stat << 1 ), 0 );  } @@ -39,6 +39,17 @@ query_t *query_add( irc_t *irc, struct gaim_connection *gc, char *question, void  	q->no = no;  	q->data = data; +	if( strchr( irc->umode, 'b' ) != NULL ) +	{ +		char *s; +		 +		/* At least for the machine-parseable version, get rid of +		   newlines to make "parsing" easier. */ +		for( s = q->question; *s; s ++ ) +			if( *s == '\r' || *s == '\n' ) +				*s = ' '; +	} +	  	if( irc->queries )  	{  		query_t *l = irc->queries; @@ -126,16 +137,15 @@ void query_answer( irc_t *irc, query_t *q, int ans )  		q = query_default( irc );  		disp = 1;  	} -	//Using irc_usermsg instead of serv_got_crap because \x02A is a char too, so a SPACE is needed.	  	if( ans )  	{ -		q->yes( NULL, q->data );  		serv_got_crap( q->gc, "Accepted: %s", q->question ); +		q->yes( NULL, q->data );  	}  	else  	{ -		q->no( NULL, q->data );  		serv_got_crap( q->gc, "Rejected: %s", q->question ); +		q->no( NULL, q->data );  	}  	q->data = NULL; diff --git a/root_commands.c b/root_commands.c index f69442d3..0e12e9ab 100644 --- a/root_commands.c +++ b/root_commands.c @@ -56,6 +56,17 @@ void root_command_string( irc_t *irc, user_t *u, char *command, int flags )  				cmd[k++] = s;  				s --;  			} +			else +			{ +				break; +			} +		} +		else if( *s == '\\' && ( ( !q && s[1] ) || ( q && q == s[1] ) ) ) +		{ +			char *cpy; +			 +			for( cpy = s; *cpy; cpy ++ ) +				cpy[0] = cpy[1];  		}  		else if( *s == q )  		{ @@ -244,6 +255,9 @@ static void cmd_account( irc_t *irc, char **cmd )  	{  		int i = 0; +		if( strchr( irc->umode, 'b' ) ) +			irc_usermsg( irc, "Account list:" ); +		  		for( a = irc->accounts; a; a = a->next )  		{  			char *con; @@ -346,6 +360,13 @@ static void cmd_account( irc_t *irc, char **cmd )  static void cmd_add( irc_t *irc, char **cmd )  {  	account_t *a; +	int add_for_real = 1; +	 +	if( g_strcasecmp( cmd[1], "-tmp" ) == 0 ) +	{ +		add_for_real = 0; +		cmd ++;		/* So evil... :-D */ +	}  	if( !( a = account_get( irc, cmd[1] ) ) )  	{ @@ -375,7 +396,12 @@ static void cmd_add( irc_t *irc, char **cmd )  			nick_set( irc, cmd[2], a->gc->prpl, cmd[3] );  		}  	} -	a->gc->prpl->add_buddy( a->gc, cmd[2] ); +	 +	/* By making this optional, you can talk to people without having to +	   add them to your *real* (server-side) contact list. */ +	if( add_for_real ) +		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 ); @@ -483,7 +509,27 @@ static void cmd_block( irc_t *irc, char **cmd )  	struct gaim_connection *gc;  	account_t *a; -	if( !cmd[2] ) +	if( !cmd[2] && ( a = account_get( irc, cmd[1] ) ) && a->gc ) +	{ +		char *format; +		GSList *l; +		 +		if( strchr( irc->umode, 'b' ) != NULL ) +			format = "%s\t%s"; +		else +			format = "%-32.32s  %-16.16s"; +		 +		irc_usermsg( irc, format, "Handle", "Nickname" ); +		for( l = a->gc->deny; l; l = l->next ) +		{ +			user_t *u = user_findhandle( a->gc, l->data ); +			irc_usermsg( irc, format, l->data, u ? u->nick : "(none)" ); +		} +		irc_usermsg( irc, "End of list." ); +		 +		return; +	} +	else if( !cmd[2] )  	{  		user_t *u = user_find( irc, cmd[1] );  		if( !u || !u->gc ) @@ -511,9 +557,9 @@ static void cmd_block( irc_t *irc, char **cmd )  	}  	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] ); +		bim_rem_allow( gc, cmd[2] ); +		bim_add_block( gc, cmd[2] ); +		irc_usermsg( irc, "Buddy `%s' moved from your allow- to your block-list", cmd[2] );  	}  } @@ -522,7 +568,27 @@ static void cmd_allow( irc_t *irc, char **cmd )  	struct gaim_connection *gc;  	account_t *a; -	if( !cmd[2] ) +	if( !cmd[2] && ( a = account_get( irc, cmd[1] ) ) && a->gc ) +	{ +		char *format; +		GSList *l; +		 +		if( strchr( irc->umode, 'b' ) != NULL ) +			format = "%s\t%s"; +		else +			format = "%-32.32s  %-16.16s"; +		 +		irc_usermsg( irc, format, "Handle", "Nickname" ); +		for( l = a->gc->deny; l; l = l->next ) +		{ +			user_t *u = user_findhandle( a->gc, l->data ); +			irc_usermsg( irc, format, l->data, u ? u->nick : "(none)" ); +		} +		irc_usermsg( irc, "End of list." ); +		 +		return; +	} +	else if( !cmd[2] )  	{  		user_t *u = user_find( irc, cmd[1] );  		if( !u || !u->gc ) @@ -550,10 +616,10 @@ static void cmd_allow( irc_t *irc, char **cmd )  	}  	else  	{ -		gc->prpl->rem_deny( gc, cmd[2] ); -		gc->prpl->add_permit( gc, cmd[2] ); +		bim_rem_block( gc, cmd[2] ); +		bim_add_allow( gc, cmd[2] ); -		irc_usermsg( irc, "Buddy `%s' moved from your deny- to your permit-list", cmd[2] ); +		irc_usermsg( irc, "Buddy `%s' moved from your block- to your allow-list", cmd[2] );  	}  } @@ -634,7 +700,8 @@ static void cmd_blist( irc_t *irc, char **cmd )  {  	int online = 0, away = 0, offline = 0;  	user_t *u; -	char s[64]; +	char s[256]; +	char *format;  	int n_online = 0, n_away = 0, n_offline = 0;  	if( cmd[1] && g_strcasecmp( cmd[1], "all" ) == 0 ) @@ -648,26 +715,41 @@ static void cmd_blist( irc_t *irc, char **cmd )  	else  		online =  away = 1; -	irc_usermsg( irc, "%-16.16s  %-40.40s  %s", "Nick", "User/Host/Network", "Status" ); +	if( strchr( irc->umode, 'b' ) != NULL ) +		format = "%s\t%s\t%s"; +	else +		format = "%-16.16s  %-40.40s  %s"; +	 +	irc_usermsg( irc, format, "Nick", "User/Host/Network", "Status" ); -	if( online == 1 ) for( u = irc->users; u; u = u->next ) if( u->gc && u->online && !u->away ) +	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" ); +		if( online == 1 ) +		{ +			g_snprintf( s, sizeof( s ) - 1, "%s@%s (%s)", u->user, u->host, u->gc->user->prpl->name ); +			irc_usermsg( irc, format, u->nick, s, "Online" ); +		} +		  		n_online ++;  	} -	if( away == 1 ) for( u = irc->users; u; u = u->next ) if( u->gc && u->online && u->away ) +	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 ); +		if( away == 1 ) +		{ +			g_snprintf( s, sizeof( s ) - 1, "%s@%s (%s)", u->user, u->host, u->gc->user->prpl->name ); +			irc_usermsg( irc, format, u->nick, s, u->away ); +		}  		n_away ++;  	} -	if( offline == 1 ) for( u = irc->users; u; u = u->next ) if( u->gc && !u->online ) +	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" ); +		if( offline == 1 ) +		{ +			g_snprintf( s, sizeof( s ) - 1, "%s@%s (%s)", u->user, u->host, u->gc->user->prpl->name ); +			irc_usermsg( irc, format, u->nick, s, "Offline" ); +		}  		n_offline ++;  	} @@ -696,15 +778,9 @@ static void cmd_nick( irc_t *irc, char **cmd )  	}  	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] ); +		a->gc->prpl->set_info( a->gc, cmd[2] );  	}  } @@ -149,7 +149,11 @@ void set_del( irc_t *irc, char *key )  	}  	if( s )  	{ -		t->next = s->next; +		if( t ) +			t->next = s->next; +		else +			irc->set = s->next; +		  		g_free( s->key );  		if( s->value ) g_free( s->value );  		if( s->def ) g_free( s->def ); @@ -167,8 +167,8 @@ void user_rename( irc_t *irc, char *oldnick, char *newnick )  	if( u->nick == u->realname ) u->realname = NULL;  	u->nick = g_strdup( newnick );  	if( !u->user ) u->user = u->nick; -	if( !u->host ) u->user = u->host; -	if( !u->realname ) u->user = u->realname; +	if( !u->host ) u->host = u->nick; +	if( !u->realname ) u->realname = u->nick;  	/* Remove the old reference to this user from the hash and create a  	   new one with the new nick. This is indeed a bit messy. */ @@ -36,6 +36,7 @@ typedef struct __USER  	char online;  	char *handle; +	char *group;  	struct gaim_connection *gc;   	char *sendbuf; @@ -38,6 +38,7 @@  #include <ctype.h>  #include <glib.h>  #include <time.h> +#include <iconv.h>  void strip_linefeed(gchar *text)  { @@ -444,3 +445,51 @@ char *ipv6_unwrap( char *src )  	return ( src + 7 );  }  #endif + +/* Convert from one charset to another. +    +   from_cs, to_cs: Source and destination charsets +   src, dst: Source and destination strings +   size: Size if src. 0 == use strlen(). strlen() is not reliable for UNICODE/UTF16 strings though. +   maxbuf: Maximum number of bytes to write to dst +    +   Returns the number of bytes written to maxbuf or -1 on an error. +*/ +signed int do_iconv( char *from_cs, char *to_cs, char *src, char *dst, size_t size, size_t maxbuf ) +{ +	iconv_t cd; +	size_t res; +	size_t inbytesleft, outbytesleft; +	char *inbuf = src; +	char *outbuf = dst; +	 +	cd = iconv_open( to_cs, from_cs ); +	if( cd == (iconv_t) -1 ) +		return( -1 ); +	 +	inbytesleft = size ? size : strlen( src ); +	outbytesleft = maxbuf - 1; +	res = iconv( cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft ); +	*outbuf = '\0'; +	iconv_close( cd ); +	 +	if( res == (size_t) -1 ) +		return( -1 ); +	else +		return( outbuf - dst ); +} + +char *set_eval_charset( irc_t *irc, set_t *set, char *value ) +{ +	iconv_t cd; + +	if ( g_strncasecmp( value, "none", 4 ) == 0 ) +		return( value ); + +	cd = iconv_open( "UTF-8", value ); +	if( cd == (iconv_t) -1 ) +		return( NULL ); + +	iconv_close( cd ); +	return( value ); +} @@ -0,0 +1,50 @@ +  /********************************************************************\ +  * BitlBee -- An IRC to other IM-networks gateway                     * +  *                                                                    * +  * Copyright 2002-2004 Wilmer van der Gaast and others                * +  \********************************************************************/ + +/* Misc. functions                                                      */ + +/* +  This program is free software; you can redistribute it and/or modify +  it under the terms of the GNU General Public License as published by +  the Free Software Foundation; either version 2 of the License, or +  (at your option) any later version. + +  This program is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +  GNU General Public License for more details. + +  You should have received a copy of the GNU General Public License with +  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; +  if not, write to the Free Software Foundation, Inc., 59 Temple Place, +  Suite 330, Boston, MA  02111-1307  USA +*/ + +#ifndef _UTIL_H +#define _UTIL_H + +G_MODULE_EXPORT void strip_linefeed( gchar *text ); +G_MODULE_EXPORT char *add_cr( char *text ); +G_MODULE_EXPORT char *strip_newlines(char *source); +G_MODULE_EXPORT char *tobase64( const char *text ); +G_MODULE_EXPORT char *normalize( const char *s ); +G_MODULE_EXPORT void info_string_append( GString *str, char *newline, char *name, char *value ); + +G_MODULE_EXPORT time_t get_time( int year, int month, int day, int hour, int min, int sec ); +double gettime( void ); + +G_MODULE_EXPORT void strip_html( char *msg ); +G_MODULE_EXPORT char *escape_html( const char *html ); +G_MODULE_EXPORT void http_decode( char *s ); +G_MODULE_EXPORT void http_encode( char *s ); + +G_MODULE_EXPORT char *ipv6_wrap( char *src ); +G_MODULE_EXPORT char *ipv6_unwrap( char *src ); + +G_MODULE_EXPORT signed int do_iconv( char *from_cs, char *to_cs, char *src, char *dst, size_t size, size_t maxbuf ); +char *set_eval_charset( irc_t *irc, set_t *set, char *value ); + +#endif diff --git a/utils/bitlbeed.c b/utils/bitlbeed.c index b8db348e..82bd0879 100644 --- a/utils/bitlbeed.c +++ b/utils/bitlbeed.c @@ -5,7 +5,7 @@  *  A tiny daemon to allow you to run The Bee as a non-root user  *  *  (without access to /etc/inetd.conf or whatever)               *  *                                                                * -*  Copyright 2002-2004 Wilmer van der Gaast <lintux@debian.org>  * +*  Copyright 2002-2004 Wilmer van der Gaast <wilmer@gaast.net>   *  *                                                                *  *  Licensed under the GNU General Public License                 *  *                                                                * | 
