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 * * * |