diff options
42 files changed, 787 insertions, 555 deletions
@@ -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 @@ -110,6 +110,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. */ @@ -132,10 +133,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 ); @@ -170,29 +170,11 @@ if $PKG_CONFIG --version > /dev/null 2>/dev/null && $PKG_CONFIG glib-2.0; then EFLAGS+=`$PKG_CONFIG --libs glib-2.0 gmodule-2.0` CFLAGS+=`$PKG_CONFIG --cflags glib-2.0 gmodule-2.0` EOF - echo '#define GLIB2' >> config.h -elif type glib-config > /dev/null 2> /dev/null; then - cat<<EOF>>Makefile.settings -EFLAGS+=`glib-config --libs` -CFLAGS+=`glib-config --cflags` -EOF - echo '#define GLIB1' >> config.h else - echo 'Cannot find glib development libraries, aborting. (Install libglib-dev?)' + echo 'Cannot find glib2 development libraries, aborting. (Install libglib2-dev?)' exit 1; fi -if [ -r /usr/include/iconv.h ]; then - :; -elif [ -r /usr/local/include/iconv.h ]; then - echo CFLAGS+=-I/usr/local/include >> Makefile.settings; -else - echo - echo 'Warning: Could not find iconv.h, you might have to install it and/or modify' - echo 'Makefile.settings to tell where this file is.'; -fi - - detect_gnutls() { if libgnutls-config --version > /dev/null 2> /dev/null; then @@ -332,10 +314,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 @@ -408,18 +396,15 @@ Linux ) GNU/* ) ;; *BSD ) - echo 'EFLAGS+=-liconv' >> Makefile.settings; -;; -SunOS ) - echo 'EFLAGS+=-lresolv -lnsl -lsocket' >> Makefile.settings - echo 'STRIP=\# skip strip' >> Makefile.settings - echo 'EFLAGS+=-liconv' >> Makefile.settings; ;; Darwin ) - echo 'EFLAGS+=-liconv' >> Makefile.settings; ;; IRIX ) ;; +SunOS ) + echo 'EFLAGS+=-lresolv -lnsl -lsocket' >> Makefile.settings + echo 'STRIP=\# skip strip' >> Makefile.settings +;; CYGWIN* ) echo 'Cygwin is not officially supported.' ;; @@ -46,7 +46,7 @@ DEPENDENCIES ============ BitlBee's only real dependency is GLib. This is available on virtually every -platform. Any recent version of GLib (including 1.x versions) will work. +platform. Any recent version of GLib (2.0 or higher) will work. These days, MSN Messenger clients have to connect to the MS Passport servers through HTTPS. BitlBee can use several SSL libraries for this: GnuTLS, NSS 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/user-guide/commands.xml b/doc/user-guide/commands.xml index fd803801..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> @@ -615,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> @@ -506,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; } @@ -570,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 ); @@ -54,13 +54,9 @@ irc_t *irc_new( int fd ) irc->fd = fd; irc->io_channel = g_io_channel_unix_new( fd ); -#ifdef GLIB2 g_io_channel_set_encoding (irc->io_channel, NULL, NULL); g_io_channel_set_buffered (irc->io_channel, FALSE); g_io_channel_set_flags( irc->io_channel, G_IO_FLAG_NONBLOCK, NULL ); -#else - fcntl( irc->fd, F_SETFL, O_NONBLOCK); -#endif irc->r_watch_source_id = g_io_add_watch( irc->io_channel, G_IO_IN | G_IO_ERR | G_IO_HUP, bitlbee_io_current_client_read, irc ); irc->status = USTATUS_OFFLINE; @@ -198,7 +194,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 ); @@ -232,10 +228,12 @@ void irc_free(irc_t * irc) irc_connection_list = g_slist_remove( irc_connection_list, irc ); for (account = irc->accounts; account; account = account->next) { - if (account->gc) - account_offline(account->gc); - else if (account->reconnect) - g_source_remove(account->reconnect); + if (account->gc) { + account->gc->wants_to_die = TRUE; + signoff(account->gc); + } else if (account->reconnect) { + cancel_auto_reconnect(account); + } } g_free(irc->sendbuffer); @@ -284,10 +282,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) { @@ -345,7 +343,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 ) @@ -354,6 +352,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] ); @@ -361,7 +364,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; @@ -387,6 +397,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; @@ -427,6 +439,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; @@ -486,6 +499,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; @@ -538,7 +552,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 ); @@ -562,16 +576,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 ); @@ -802,7 +825,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 ); } } @@ -858,7 +881,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 ); } @@ -875,15 +898,37 @@ void irc_kick( irc_t *irc, user_t *u, char *channel, user_t *kicker ) void irc_kill( irc_t *irc, user_t *u ) { - char *nick; + char *nick, *s; + char reason[64]; - irc_write( irc, ":%s!%s@%s QUIT :%s", u->nick, u->user, u->host, "Leaving..." ); + if( u->gc && u->gc->flags & OPT_LOGGING_OUT ) + { + if( u->gc->user->proto_opt[0][0] ) + g_snprintf( reason, sizeof( reason ), "%s %s", irc->myhost, + u->gc->user->proto_opt[0] ); + else if( ( s = strchr( u->gc->username, '@' ) ) ) + g_snprintf( reason, sizeof( reason ), "%s %s", irc->myhost, + s + 1 ); + else + g_snprintf( reason, sizeof( reason ), "%s %s.%s", irc->myhost, + u->gc->prpl->name, irc->myhost ); + + /* proto_opt might contain garbage after the : */ + if( ( s = strchr( reason, ':' ) ) ) + *s = 0; + } + else + { + strcpy( reason, "Leaving..." ); + } + + irc_write( irc, ":%s!%s@%s QUIT :%s", u->nick, u->user, u->host, reason ); nick = g_strdup( u->nick ); 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 ); } @@ -983,7 +1028,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 ); @@ -993,8 +1038,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; @@ -1002,7 +1051,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 ) @@ -1015,7 +1064,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 ); } @@ -1023,14 +1072,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 ); @@ -1046,7 +1095,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 ); } } @@ -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 01b01dfb..dc59f7ee 100644 --- a/irc_commands.c +++ b/irc_commands.c @@ -176,7 +176,7 @@ static void irc_cmd_join( irc_t *irc, char **cmd ) if( !u->gc->prpl->chat_open( u->gc, u->handle ) ) { - irc_usermsg( irc, "Could not open a groupchat with %s, maybe you don't have a connection to him/her yet?", u->nick ); + irc_usermsg( irc, "Could not open a groupchat with %s.", u->nick ); } } else if( u ) @@ -320,7 +320,7 @@ static void irc_cmd_userhost( irc_t *irc, char **cmd ) static void irc_cmd_ison( irc_t *irc, char **cmd ) { user_t *u; - char buff[IRC_MAX_LINE]; + char buff[IRC_MAX_LINE], *s; int lenleft, i; buff[0] = '\0'; @@ -330,28 +330,41 @@ static void irc_cmd_ison( irc_t *irc, char **cmd ) for( i = 1; cmd[i]; i ++ ) { - if( ( u = user_find( irc, cmd[i] ) ) && u->online ) + char *this, *next; + + this = cmd[i]; + while( *this ) { - /* [SH] Make sure we don't use too much buffer space. */ - lenleft -= strlen( u->nick ) + 1; + if( ( next = strchr( this, ' ' ) ) ) + *next = 0; - if( lenleft < 0 ) + if( ( u = user_find( irc, this ) ) && u->online ) { - break; + lenleft -= strlen( u->nick ) + 1; + + if( lenleft < 0 ) + break; + + strcat( buff, u->nick ); + strcat( buff, " " ); } - /* [SH] Add the nick to the buffer. Note - * that an extra space is always added. Even - * if it's the last nick in the list. Who - * cares? - */ - - strcat( buff, u->nick ); - strcat( buff, " " ); + if( next ) + { + *next = ' '; + this = next + 1; + } + else + { + break; + } } + + /* *sigh* */ + if( lenleft < 0 ) + break; } - /* [WvG] Well, maybe someone cares, so why not remove it? */ if( strlen( buff ) > 0 ) buff[strlen(buff)-1] = '\0'; @@ -384,9 +397,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 +460,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 ); } } @@ -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..c793d9d4 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 ) @@ -125,6 +156,8 @@ static void http_connected( gpointer data, int source, GaimInputCondition cond ) return; error: + req->status_string = g_strdup( "Error while writing HTTP request" ); + req->func( req ); g_free( req->request ); @@ -184,6 +217,7 @@ static void http_incoming_data( gpointer data, int source, GaimInputCondition co { if( !sockerr_again() ) { + req->status_string = g_strdup( strerror( errno ) ); goto cleanup; } } @@ -208,6 +242,14 @@ static void http_incoming_data( gpointer data, int source, GaimInputCondition co return; got_reply: + /* Maybe if the webserver is overloaded, or when there's bad SSL + support... */ + if( req->bytes_read == 0 ) + { + req->status_string = g_strdup( "Empty HTTP reply" ); + goto cleanup; + } + /* Zero termination is very convenient. */ req->reply_headers[req->bytes_read] = 0; @@ -221,28 +263,53 @@ 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; + req->status_string = g_strdup( "Malformed HTTP reply" ); + 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 ) + { + req->status_string = g_strdup( "Can't parse status code" ); req->status_code = -1; + } + else + { + char *eol; + + if( evil_server ) + eol = strchr( end1, '\n' ); + else + eol = strchr( end1, '\r' ); + + req->status_string = g_strndup( end1 + 1, eol - end1 - 1 ); + + /* Just to be sure... */ + if( ( eol = strchr( req->status_string, '\r' ) ) ) + *eol = 0; + if( ( eol = strchr( req->status_string, '\n' ) ) ) + *eol = 0; + } } else { + req->status_string = g_strdup( "Can't locate status code" ); req->status_code = -1; } @@ -251,9 +318,16 @@ got_reply: char *loc, *new_request, *new_host; int error = 0, new_port, new_proto; + /* We might fill it again, so let's not leak any memory. */ + g_free( req->status_string ); + req->status_string = NULL; + loc = strstr( req->reply_headers, "\nLocation: " ); if( loc == NULL ) /* We can't handle this redirect... */ + { + req->status_string = g_strdup( "Can't locate Location: header" ); goto cleanup; + } loc += 11; while( *loc == ' ' ) @@ -270,6 +344,8 @@ got_reply: /* Since we don't cache the servername, and since we don't need this yet anyway, I won't implement it. */ + req->status_string = g_strdup( "Can't handle recursive redirects" ); + goto cleanup; } else @@ -287,6 +363,7 @@ got_reply: if( !url_set( url, loc ) ) { + req->status_string = g_strdup( "Malformed redirect URL" ); g_free( url ); goto cleanup; } @@ -297,28 +374,18 @@ got_reply: /* So, now I just allocated enough memory, so I'm going to use strcat(), whether you like it or not. :-) */ - /* First, find the GET/POST/whatever from the original request. */ - s = strchr( req->request, ' ' ); - if( s == NULL ) - { - g_free( new_request ); - g_free( url ); - goto cleanup; - } - - *s = 0; - sprintf( new_request, "%s %s HTTP/1.0\r\n", req->request, url->file ); - *s = ' '; + sprintf( new_request, "GET %s HTTP/1.0", url->file ); s = strstr( req->request, "\r\n" ); if( s == NULL ) { + req->status_string = g_strdup( "Error while rebuilding request string" ); g_free( new_request ); g_free( url ); goto cleanup; } - strcat( new_request, s + 2 ); + strcat( new_request, s ); new_host = g_strdup( url->host ); new_port = url->port; new_proto = url->proto; @@ -332,7 +399,7 @@ got_reply: closesocket( req->fd ); req->fd = -1; - req->ssl = 0; + req->ssl = NULL; if( new_proto == PROTO_HTTPS ) { @@ -350,6 +417,7 @@ got_reply: if( error ) { + req->status_string = g_strdup( "Connection problem during redirect" ); g_free( new_request ); goto cleanup; } @@ -378,5 +446,6 @@ cleanup: g_free( req->request ); g_free( req->reply_headers ); + g_free( req->status_string ); g_free( req ); } diff --git a/protocols/http_client.h b/protocols/http_client.h index 53c6fcd6..50ee80cf 100644 --- a/protocols/http_client.h +++ b/protocols/http_client.h @@ -36,8 +36,10 @@ struct http_request char *request; int request_length; int status_code; + char *status_string; char *reply_headers; char *reply_body; + int body_size; int finished; void *ssl; @@ -52,3 +54,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 224762ce..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); @@ -1548,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); @@ -1884,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 */ /*---------------------------------------*/ @@ -2337,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; @@ -2367,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_util.c b/protocols/msn/msn_util.c index 5cda9f1c..c3bd73cc 100644 --- a/protocols/msn/msn_util.c +++ b/protocols/msn/msn_util.c @@ -130,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 90d525ef..523de0ae 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -649,8 +649,15 @@ static void msn_auth_got_passport_id( struct passport_reply *rep ) if( key == NULL ) { - hide_login_progress( gc, "Error during Passport authentication" ); + char *err; + + err = g_strdup_printf( "Error during Passport authentication (%s)", + rep->error_string ? rep->error_string : "Unknown error" ); + + hide_login_progress( gc, err ); signoff( gc ); + + g_free( err ); } else { diff --git a/protocols/msn/passport.c b/protocols/msn/passport.c index 34703432..dd1d9b6f 100644 --- a/protocols/msn/passport.c +++ b/protocols/msn/passport.c @@ -68,8 +68,7 @@ static int passport_get_id_real( gpointer func, gpointer data, char *header ) return( 0 ); } - reqs = g_malloc( strlen( header ) + strlen( dummy ) + 128 ); - sprintf( reqs, "GET %s HTTP/1.0\r\n%s\r\n\r\n", dummy, header ); + reqs = g_strdup_printf( "GET %s HTTP/1.0\r\n%s\r\n\r\n", dummy, header ); *dummy = 0; req = http_dorequest( server, 443, 1, reqs, passport_get_id_ready, rep ); @@ -87,13 +86,13 @@ static void passport_get_id_ready( struct http_request *req ) { struct passport_reply *rep = req->data; - if( !g_slist_find( msn_connections, rep->data ) || !req->finished || !req->reply_headers ) + if( !g_slist_find( msn_connections, rep->data ) ) { destroy_reply( rep ); return; } - if( req->status_code == 200 ) + if( req->finished && req->reply_headers && req->status_code == 200 ) { char *dummy; @@ -108,6 +107,15 @@ static void passport_get_id_ready( struct http_request *req ) rep->result = g_strdup( dummy ); } + else + { + rep->error_string = g_strdup( "Could not parse Passport server response" ); + } + } + else + { + rep->error_string = g_strdup_printf( "HTTP error: %s", + req->status_string ? req->status_string : "Unknown error" ); } rep->func( rep ); @@ -144,7 +152,6 @@ static char *passport_create_header( char *cookie, char *email, char *pwd ) return( buffer ); } -#define PPR_REQUEST "GET /rdr/pprdr.asp HTTP/1.0\r\n\r\n" static int passport_retrieve_dalogin( gpointer func, gpointer data, char *header ) { struct passport_reply *rep = g_new0( struct passport_reply, 1 ); @@ -154,7 +161,7 @@ static int passport_retrieve_dalogin( gpointer func, gpointer data, char *header rep->func = func; rep->header = header; - req = http_dorequest( "nexus.passport.com", 443, 1, PPR_REQUEST, passport_retrieve_dalogin_ready, rep ); + req = http_dorequest_url( "https://nexus.passport.com/rdr/pprdr.asp", passport_retrieve_dalogin_ready, rep ); if( !req ) destroy_reply( rep ); @@ -168,16 +175,26 @@ static void passport_retrieve_dalogin_ready( struct http_request *req ) char *dalogin; char *urlend; - if( !g_slist_find( msn_connections, rep->data ) || !req->finished || !req->reply_headers ) + if( !g_slist_find( msn_connections, rep->data ) ) { destroy_reply( rep ); return; } + if( !req->finished || !req->reply_headers || req->status_code != 200 ) + { + rep->error_string = g_strdup_printf( "HTTP error while fetching DALogin: %s", + req->status_string ? req->status_string : "Unknown error" ); + goto failure; + } + dalogin = strstr( req->reply_headers, "DALogin=" ); if( !dalogin ) + { + rep->error_string = g_strdup( "Parse error while fetching DALogin" ); goto failure; + } dalogin += strlen( "DALogin=" ); urlend = strchr( dalogin, ',' ); @@ -207,5 +224,6 @@ static void destroy_reply( struct passport_reply *rep ) { g_free( rep->result ); g_free( rep->header ); + g_free( rep->error_string ); g_free( rep ); } diff --git a/protocols/msn/passport.h b/protocols/msn/passport.h index f7e6ebb6..9fd81a82 100644 --- a/protocols/msn/passport.h +++ b/protocols/msn/passport.h @@ -38,6 +38,7 @@ struct passport_reply void *data; char *result; char *header; + char *error_string; }; int passport_get_id( gpointer func, gpointer data, char *username, char *password, char *cookie ); diff --git a/protocols/msn/sb.c b/protocols/msn/sb.c index 234be1d6..34b0a30a 100644 --- a/protocols/msn/sb.c +++ b/protocols/msn/sb.c @@ -522,14 +522,14 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts ) if( err->flags & STATUS_SB_FATAL ) { msn_sb_destroy( sb ); - return( 0 ); + return 0; } - if( err->flags & STATUS_FATAL ) + else if( err->flags & STATUS_FATAL ) { signoff( gc ); - return( 0 ); + return 0; } - if( err->flags & STATUS_SB_IM_SPARE ) + else if( err->flags & STATUS_SB_IM_SPARE ) { if( sb->who ) { @@ -552,6 +552,8 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts ) g_slist_free( sb->msgq ); sb->msgq = NULL; } + + /* Do NOT return 0 here, we want to keep this sb. */ } } else diff --git a/protocols/msn/tables.c b/protocols/msn/tables.c index f8e98350..5ba9ea73 100644 --- a/protocols/msn/tables.c +++ b/protocols/msn/tables.c @@ -126,7 +126,7 @@ const struct msn_status_code msn_status_code_list[] = { 800, "Changing too rapidly", 0 }, { 910, "Server is busy", STATUS_FATAL }, - { 911, "Authentication failed", STATUS_FATAL }, + { 911, "Authentication failed", STATUS_SB_FATAL | STATUS_FATAL }, { 912, "Server is busy", STATUS_FATAL }, { 913, "Not allowed when hiding", 0 }, { 914, "Server is unavailable", STATUS_FATAL }, diff --git a/protocols/nogaim.c b/protocols/nogaim.c index 28f76fff..f95ddd8a 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -36,20 +36,6 @@ #define BITLBEE_CORE #include "nogaim.h" #include <ctype.h> -#include <iconv.h> - -static char *proto_away_alias[8][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 }, - { "Invisible", "Hidden" }, - { NULL } -}; -static char *proto_away_alias_find( GList *gcm, char *away ); static int remove_chat_buddy_silent( struct conversation *b, char *handle ); @@ -158,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 ) @@ -305,38 +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; - 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 ) - acc_id = g_strdup_printf( "%s(%s)", gc->prpl->name, gc->username ); + irc_usermsg( gc->irc, "%s(%s) - %s", gc->prpl->name, gc->username, text ); else - acc_id = g_strdup( gc->prpl->name ); + irc_usermsg( gc->irc, "%s - %s", gc->prpl->name, text ); - irc_usermsg( gc->irc, "%s - %s", acc_id, msg ); - - g_free( acc_id ); + g_free( text ); } static gboolean send_keepalive( gpointer d ) @@ -368,18 +268,7 @@ void account_online( struct gaim_connection *gc ) /* Also necessary when we're not away, at least for some of the protocols. */ - proto_away( gc, u->away ); - - if( strcmp( gc->prpl->name, "ICQ" ) == 0 ) - { - 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." ); - } + bim_set_away( gc, u->away ); } gboolean auto_reconnect( gpointer data ) @@ -398,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; @@ -411,7 +294,8 @@ void signoff( struct gaim_connection *gc ) account_t *a; serv_got_crap( gc, "Signing off.." ); - + gc->flags |= OPT_LOGGING_OUT; + gaim_input_remove( gc->keepalive ); gc->keepalive = 0; gc->prpl->close( gc ); @@ -509,7 +393,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 */ @@ -558,22 +449,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 ); @@ -583,9 +466,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 { - return; + 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 ) +{ + 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 ); } @@ -615,7 +529,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; @@ -679,7 +594,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 ); @@ -721,10 +635,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; @@ -821,7 +731,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 ) @@ -834,10 +743,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 @@ -958,20 +863,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 ) @@ -1050,89 +941,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 ); +} - iconv_close( cd ); - return( value ); +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 ); +} + +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 3d45d0a0..b143440a 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,26 @@ #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 WEBSITE "http://www.bitlbee.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 +#define OPT_CONN_HTML 0x00000001 +#define OPT_LOGGED_IN 0x00010000 +#define OPT_LOGGING_OUT 0x00020000 /* 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 +78,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; }; @@ -163,61 +144,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); - - 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); }; @@ -234,14 +195,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 ); @@ -253,9 +216,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 */ @@ -263,11 +225,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 ); @@ -277,7 +236,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 ); @@ -288,23 +247,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..df535c4f 100644 --- a/protocols/oscar/chat.c +++ b/protocols/oscar/chat.c @@ -158,7 +158,21 @@ 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/im.c b/protocols/oscar/im.c index c829d409..7cccabc7 100644 --- a/protocols/oscar/im.c +++ b/protocols/oscar/im.c @@ -1468,7 +1468,7 @@ static void incomingim_ch2_icqserverrelay(aim_session_t *sess, aim_module_t *mod case AIM_MTYPE_AUTOFFC: case 0x9c: /* ICQ 5 seems to send this */ aim_send_im_ch2_statusmessage(sess, userinfo->sn, args->cookie, - gc->away, sess->aim_icq_state, dc); + gc->away ? gc->away : "", sess->aim_icq_state, dc); break; } diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c index 97384afb..c2716c6b 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> * @@ -135,9 +137,9 @@ static char *extract_name(const char *name) { char *tmp; int i, j; char *x = strchr(name, '-'); - if (!x) return NULL; + if (!x) return g_strdup(name); x = strchr(++x, '-'); - if (!x) return NULL; + if (!x) return g_strdup(name); tmp = g_strdup(++x); for (i = 0, j = 0; x[i]; i++) { @@ -382,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); @@ -1118,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); @@ -2056,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++; } } @@ -2070,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++; } } @@ -2276,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); } @@ -2500,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))) @@ -2508,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.. */ @@ -2527,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); @@ -2600,9 +2606,9 @@ int oscar_chat_open(struct gaim_connection * gc, char *who) struct oscar_data * od = (struct oscar_data *)gc->proto_data; int ret; static int chat_id = 0; - char * chatname = g_new0(char, strlen(gc->username)+4); + char * chatname; - g_snprintf(chatname, strlen(gc->username) + 4, "%s%d", gc->username, chat_id++); + chatname = g_strdup_printf("%s%d", gc->username, chat_id++); ret = oscar_chat_join(gc, chatname); 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/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 ); } @@ -139,13 +139,13 @@ void query_answer( irc_t *irc, query_t *q, int ans ) } 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 36eec8c3..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 ); @@ -491,7 +517,7 @@ static void cmd_block( irc_t *irc, char **cmd ) if( strchr( irc->umode, 'b' ) != NULL ) format = "%s\t%s"; else - format = "%-32.32 %-16.16s"; + format = "%-32.32s %-16.16s"; irc_usermsg( irc, format, "Handle", "Nickname" ); for( l = a->gc->deny; l; l = l->next ) @@ -531,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] ); } } @@ -550,7 +576,7 @@ static void cmd_allow( irc_t *irc, char **cmd ) if( strchr( irc->umode, 'b' ) != NULL ) format = "%s\t%s"; else - format = "%-32.32 %-16.16s"; + format = "%-32.32s %-16.16s"; irc_usermsg( irc, format, "Handle", "Nickname" ); for( l = a->gc->deny; l; l = l->next ) @@ -590,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] ); } } @@ -752,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. */ @@ -444,3 +444,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 ) +{ + GIConv cd; + size_t res; + size_t inbytesleft, outbytesleft; + char *inbuf = src; + char *outbuf = dst; + + cd = g_iconv_open( to_cs, from_cs ); + if( cd == (GIConv) -1 ) + return( -1 ); + + inbytesleft = size ? size : strlen( src ); + outbytesleft = maxbuf - 1; + res = g_iconv( cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft ); + *outbuf = '\0'; + g_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 ) +{ + GIConv cd; + + if ( g_strncasecmp( value, "none", 4 ) == 0 ) + return( value ); + + cd = g_iconv_open( "UTF-8", value ); + if( cd == (GIConv) -1 ) + return( NULL ); + + g_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 * * * |