diff options
94 files changed, 5908 insertions, 15642 deletions
@@ -11,7 +11,7 @@ # Program variables objects = account.o bitlbee.o conf.o crypting.o help.o ipc.o irc.o irc_commands.o log.o nick.o query.o root_commands.o set.o storage.o $(STORAGE_OBJS) unix.o user.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 lib +subdirs = lib protocols # Expansion of variables subdirobjs = $(foreach dir,$(subdirs),$(dir)/$(dir).o) @@ -44,7 +44,7 @@ clean: $(subdirs) distclean: clean $(subdirs) rm -f Makefile.settings config.h bitlbee.pc find . -name 'DEADJOE' -o -name '*.orig' -o -name '*.rej' -o -name '*~' -exec rm -f {} \; - $(MAKE) -C test distclean + $(MAKE) -C tests distclean check: all $(MAKE) -C tests @@ -64,8 +64,8 @@ account_t *account_add( irc_t *irc, struct prpl *prpl, char *user, char *pass ) /* This function adds some more settings (and might want to do more things that have to be done now, although I can't think of anything. */ - if( prpl->acc_init ) - prpl->acc_init( a ); + if( prpl->init ) + prpl->init( a ); return( a ); } @@ -75,7 +75,7 @@ char *set_eval_account( set_t *set, char *value ) account_t *acc = set->data; /* Double-check: We refuse to edit on-line accounts. */ - if( set->flags & ACC_SET_OFFLINE_ONLY && acc->gc ) + if( set->flags & ACC_SET_OFFLINE_ONLY && acc->ic ) return NULL; if( strcmp( set->key, "username" ) == 0 ) @@ -179,7 +179,7 @@ void account_del( irc_t *irc, account_t *acc ) for( a = irc->accounts; a; a = (l=a)->next ) if( a == acc ) { - if( a->gc ) return; /* Caller should have checked, accounts still in use can't be deleted. */ + if( a->ic ) return; /* Caller should have checked, accounts still in use can't be deleted. */ if( l ) { @@ -208,7 +208,7 @@ void account_del( irc_t *irc, account_t *acc ) void account_on( irc_t *irc, account_t *a ) { - if( a->gc ) + if( a->ic ) { /* Trying to enable an already-enabled account */ return; @@ -222,9 +222,8 @@ void account_on( irc_t *irc, account_t *a ) void account_off( irc_t *irc, account_t *a ) { - a->gc->wants_to_die = TRUE; - signoff( a->gc ); - a->gc = NULL; + imc_logout( a->ic, FALSE ); + a->ic = NULL; if( a->reconnect ) { /* Shouldn't happen */ @@ -40,7 +40,7 @@ typedef struct account GHashTable *nicks; struct irc *irc; - struct gaim_connection *gc; + struct im_connection *ic; struct account *next; } account_t; @@ -68,6 +68,7 @@ int bitlbee_daemon_init() setsockopt( global.listen_socket, SOL_SOCKET, SO_REUSEADDR, &i, sizeof( i ) ); #ifdef IPV6 + memset( &listen_addr6, 0, sizeof( listen_addr6 ) ); listen_addr6.sin6_family = AF_INET6; listen_addr6.sin6_port = htons( global.conf->port ); if( ( i = inet_pton( AF_INET6, ipv6_wrap( global.conf->iface ), &listen_addr6.sin6_addr ) ) != 1 ) @@ -75,6 +76,7 @@ int bitlbee_daemon_init() /* Forget about IPv6 in this function. */ use_ipv6 = 0; #endif + memset( &listen_addr, 0, sizeof( listen_addr ) ); listen_addr.sin_family = AF_INET; listen_addr.sin_port = htons( global.conf->port ); if( strcmp( global.conf->iface, "::" ) == 0 ) @@ -29,7 +29,7 @@ #define _GNU_SOURCE /* Stupid GNU :-P */ #define PACKAGE "BitlBee" -#define BITLBEE_VERSION "BZR" +#define BITLBEE_VERSION "1.1dev" #define VERSION BITLBEE_VERSION #define MAX_STRING 128 @@ -62,7 +62,7 @@ conf_t *conf_load( int argc, char *argv[] ) conf->oper_pass = NULL; conf->configdir = g_strdup( CONFIG ); conf->plugindir = g_strdup( PLUGINDIR ); - conf->pidfile = g_strdup( "/var/run/bitlbee.pid" ); + conf->pidfile = g_strdup( PIDFILE ); conf->motdfile = g_strdup( ETCDIR "/motd.txt" ); conf->ping_interval = 180; conf->ping_timeout = 300; @@ -131,7 +131,7 @@ conf_t *conf_load( int argc, char *argv[] ) } else if( opt == 'h' ) { - printf( "Usage: bitlbee [-D [-i <interface>] [-p <port>] [-n] [-v]] [-I]\n" + printf( "Usage: bitlbee [-D/-F [-i <interface>] [-p <port>] [-n] [-v]] [-I]\n" " [-c <file>] [-d <dir>] [-h]\n" "\n" "An IRC-to-other-chat-networks gateway\n" @@ -17,7 +17,7 @@ plugindir='$prefix/lib/bitlbee/' includedir='$prefix/include/bitlbee/' libevent='/usr/' pidfile='/var/run/bitlbee.pid' -ipcsocket='/var/run/bitlbee' +ipcsocket='/var/run/bitlbee.sock' pcdir='$prefix/lib/pkgconfig' msn=1 @@ -106,7 +106,6 @@ MANDIR=$mandir DATADIR=$datadir PLUGINDIR=$plugindir CONFIG=$config -IPCSOCKET=$ipcsocket INCLUDEDIR=$includedir PCDIR=$pcdir @@ -329,6 +328,14 @@ fi; echo 'SSL_CLIENT=ssl_'$ssl'.o' >> Makefile.settings +for i in /lib /usr/lib /usr/local/lib; do + if [ -e $i/libresolv.a ]; then + echo '#define HAVE_RESOLV_A' >> config.h + echo 'EFLAGS+='$i'/libresolv.a' >> Makefile.settings + break + fi +done + STORAGES="text xml" if [ "$ldap" = "auto" ]; then @@ -338,6 +345,11 @@ fi if [ "$ldap" = 0 ]; then echo "#undef WITH_LDAP" >> config.h elif [ "$ldap" = 1 ]; then + echo + echo 'LDAP support is a work in progress and does NOT work AT ALL right now.' + echo + exit 1 + echo "#define WITH_LDAP 1" >> config.h STORAGES="$STORAGES ldap" fi @@ -464,6 +476,9 @@ SunOS ) echo 'EFLAGS+=-lresolv -lnsl -lsocket' >> Makefile.settings echo 'STRIP=\# skip strip' >> Makefile.settings ;; +AIX ) + echo 'EFLAGS+=-Wl,-brtl' >> Makefile.settings +;; CYGWIN* ) echo 'Cygwin is not officially supported.' ;; diff --git a/doc/CHANGES b/doc/CHANGES index e9435216..3f509c46 100644 --- a/doc/CHANGES +++ b/doc/CHANGES @@ -1,4 +1,7 @@ -Version x.x: +Version 1.1dev: +- First BitlBee development/testing RELEASE. This should be quite stable + though (and for most people more stable than 1.0.x). It just has a couple + of rough edges and needs a bit more testing. - Added ForkDaemon mode next to the existing Daemon- and inetd modes. With ForkDaemon you can run BitlBee as a stand-alone daemon and every connection will run in its own process. No more need to configure inetd, and still you @@ -18,6 +21,7 @@ Version x.x: - Many, many, MANY little changes, improvements, fixes. Using non-blocking I/O as much as possible, fixed lots of little bugs (including bugs that affected daemon mode stability). See the bzr logs for more information. +- Added units tests, will have to add some more before the real release. - Most important change: New file format for user data (accounts, nicks and settings). Migration to the new format should happen transparently, BitlBee will read the old files and once you quit/save it will save in the @@ -40,6 +44,26 @@ Version x.x: lose the nicknames, you can now use "account set" to change the username and password for the existing connection. * Per-account settings (see the new "account set" command). +- A brand new Jabber module. Besides the major code cleanup, it also has + has these new features: + * Pretty complete XMPP support: RFC3920, RFC3921 plus a number of XEPs + including XEP73 and XEP85. (See http://www.xmpp.org/ for what all these + things mean exactly.) Privacy lists are not supported for obvious + reasons. + * This complete support also includes TLS and SASL support and SRV record + lookup. This means that specifying a server tag for connections should + (almost) never be necessary anymore, BitlBee can find the server and can + automatically convert plaintext connections to TLS-encrypted ones. + * XEP85 means typing notifications. The older XEP22 (still used by some + clients including Gaim <2.0) is not supported. + * Better handling of buddies who have more than one resource on-line. As + long as one resource is on-line (and visible), BitlBee will show this. + (The previous module didn't keep track of resources and sent an offline + event as soon as any resource disappears.) + * You can now set your resource priority. + * The info command now gives away state/message information for all + resources available for that buddy. (Of course this only works if the + buddy is in your contact list.) Version 1.0.3: - Fixed ugliness in block/allow list commands (still not perfect though, the diff --git a/doc/CREDITS b/doc/CREDITS index 83a19f51..f805c251 100644 --- a/doc/CREDITS +++ b/doc/CREDITS @@ -49,9 +49,11 @@ The authors thank the following people: - Elizabeth Krumbach, for her help on the docs. - Frank Thieme, for the info-command enhancements and other patches. - Marcus Dennis, for some bitlbeed enhancements. -- 1nfamus, for security auditing BitlBee code. +- infamous41md, for security auditing BitlBee code. - Tijmen Ruizendaal, for some useful BitlBee-related irssi scripts. - Ed Schouten, for reporting bugs. +- Greg (gropeep.org), for updating the Yahoo! module to fix some issues + that were there for quite some time already. - And all other users who help us by sending useful bug reports, positive feedback, nice patches and cool addons. Mentioning you all would make @@ -46,7 +46,7 @@ DEPENDENCIES ============ BitlBee's only real dependency is GLib. This is available on virtually every -platform. Any recent version of GLib (2.0 or higher) will work. +platform. Any recent version of GLib (2.4 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 @@ -183,17 +183,10 @@ LEGAL BitlBee is distributed under the GPL (GNU General Public License). See the file COPYING for this license. -Unfortunately some parts of the Gaim Jabber plugin (most notably the XML -code) were licensed under the MPL (Mozilla Public License) version 1.1. We -could not relicense this code under the GPL. As such it is still licensed -under the MPL. The parts of the code to which this applies are marked as -such. - -The MPL is provided in the file MPL-1.1.txt. This license is not GPL -compatible. It is however a free software license. - -Another part (the md5 algorithm) is licensed under the Aladdin license. -This license can be found in the files, to which this applies. +The MD5 algorithm code is licensed under the Aladdin license. This license +can be found in the files, to which this applies. The SHA1 algorithm code +is licensed under the Mozilla Public License, see http://www.mozilla.org/MPL/ +for details. The Yahoo! library used by BitlBee is libyahoo2 <http://libyahoo2.sf.net/>, also licensed under the GPL. @@ -201,5 +194,5 @@ also licensed under the GPL. BitlBee - An IRC to other chat networks gateway <http://www.bitlbee.org/> - Copyright (C) 2002-2006 Wilmer van der Gaast <wilmer@gaast.net> + Copyright (C) 2002-2007 Wilmer van der Gaast <wilmer@gaast.net> and others diff --git a/doc/bitlbee.8 b/doc/bitlbee.8 index 201e366e..ae1cfb05 100644 --- a/doc/bitlbee.8 +++ b/doc/bitlbee.8 @@ -62,6 +62,10 @@ option. Run in daemon mode. In this mode, BitlBee forks to the background and waits for new connections. All clients will be served from one process. This is still experimental. See the note above for more information. +.IP "-F" +Run in ForkDaemon mode. This is similar to ordinary daemon mode, but every +client gets its own process. Easier to set up than inetd mode, but without +the possible stability issues. .IP "-i \fIaddress\fP" Only useful when running in daemon mode, to specify the network interface (identified by IP address) to which the daemon should attach. Use this if diff --git a/doc/user-guide/commands.xml b/doc/user-guide/commands.xml index a920cfae..6646d0db 100644 --- a/doc/user-guide/commands.xml +++ b/doc/user-guide/commands.xml @@ -29,20 +29,13 @@ <description> <para> - Note that the servertag argument is optional. You only have to use it if the part after the @ in your handle isn't the hostname of your Jabber server, or if you want to use SSL/connect to a non-standard port number. The format is simple: [<servername>[:<portnumber>][:ssl]]. + The handle should be a full handle, including the domain name. You can specify a servername if necessary. Normally BitlBee doesn't need this though, since it's able to find out the server by doing DNS SRV lookups. </para> - </description> - <description> <para> - Google Talk uses the Jabber protocol. Please note that Google talk is SSL-only, but officially reachable over both port 5222 and 5223. Usually BitlBee users have to connect via port 5223, for example like this: + In previous versions it was also possible to specify port numbers and/or SSL in the server tag. This is deprecated and should now be done using the <emphasis>account set</emphasis> command. This also applies to specifying a resource in the handle (like <emphasis>wilmer@bitlbee.org/work</emphasis>). </para> </description> - - <ircexample> - <ircline nick="wilmer">account add jabber example@gmail.com hobbelmeeuw talk.google.com:5223:ssl</ircline> - <ircline nick="root">Account successfully added</ircline> - </ircexample> </bitlbee-command> <bitlbee-command name="msn"> @@ -516,6 +509,20 @@ </description> </bitlbee-setting> + <bitlbee-setting name="priority" type="integer" scope="account"> + <default>0</default> + + <description> + <para> + Can be set for Jabber connections. When connecting to one account from multiple places, this priority value will help the server to determine where to deliver incoming messages (that aren't addressed to a specific resource already). + </para> + + <para> + According to RFC 3921 servers will always deliver messages to the server with the highest priority value. Mmessages will not be delivered to resources with a negative priority setting (and should be saved as an off-line message if all available resources have a negative priority value). + </para> + </description> + </bitlbee-setting> + <bitlbee-setting name="private" type="boolean" scope="global"> <default>true</default> @@ -555,6 +562,21 @@ </description> </bitlbee-setting> + <bitlbee-setting name="resource_select" type="string" scope="account"> + <default>priority</default> + <possible-values>priority, time</possible-values> + + <description> + <para> + Because the IRC interface makes it pretty hard to specify the resource to talk to (when a buddy is online through different resources), this setting was added. + </para> + + <para> + Normally it's set to <emphasis>priority</emphasis> which means messages will always be delivered to the buddy's resource with the highest priority. If the setting is set to <emphasis>time</emphasis>, messages will be delivered to the resource that was last used to send you a message (or the resource that most recently connected). + </para> + </description> + </bitlbee-setting> + <bitlbee-setting name="save_on_quit" type="boolean" scope="global"> <default>true</default> @@ -596,6 +618,20 @@ </description> </bitlbee-setting> + <bitlbee-setting name="tls" type="boolean" scope="account"> + <default>try</default> + + <description> + <para> + Newer Jabber servers allow clients to convert a plain-text session to a TLS/SSL-encrypted session. Normally (with this setting set to <emphasis>try</emphasis>) BitlBee will do this, if possible. + </para> + + <para> + If you want to force BitlBee to use TLS sessions only (and to give up if that doesn't seem to be possible) you can set this setting to <emphasis>true</emphasis>. Set it to <emphasis>false</emphasis> if you want the session to remain plain-text. + </para> + </description> + </bitlbee-setting> + <bitlbee-setting name="to_char" type="string" scope="global"> <default>": "</default> @@ -774,27 +810,27 @@ </bitlbee-command> - <bitlbee-command name="import_buddies"> - <short-description>Copy local buddy list to server (normally only needed when upgrading)</short-description> - <syntax>import_buddies <connection> [clear]</syntax> + <bitlbee-command name="join_chat"> + <short-description>Join a named groupchat/conference room</short-description> + <syntax>import_buddies <connection> <room name> [<channel name>] [<room nickname>] [<password>]</syntax> <description> <para> - This command copies the locally stored buddy list to the server. This command exists for upgrading purposes. Previous versions of BitlBee didn't support server-side buddy lists for ICQ, so the list was stored locally. - </para> - - <para> - Since version 0.91 however, server-side contact lists are supported for all protocols, so the local list is now ignored. When upgrading from an older BitlBee to version 0.91, you might need this command to get your buddy list back. + On most IM-networks groupchats can be started using the /join command. (<emphasis>/join #foo</emphasis> to start a chatroom with you and <emphasis>foo</emphasis>) This doesn't work with names groupchats though (which exist on Jabber networks and AIM, for example), instead you can use this command. </para> <para> - The only argument this command needs is your ICQ account identification. If your serverside buddy list contains some old buddies you don't want anymore, you can pass <emphasis>clear</emphasis> as a second argument. + The first two arguments are required. <emphasis>room name</emphasis> is the name of the chatroom on the IM-network. <emphasis>channel name</emphasis> is the IRC channel name BitlBee should map this to. <emphasis>room nickname</emphasis> is the nickname you want to have in this channel. If you don't give these options, BitlBee will do the right guesses. </para> <para> - After giving this command, you have to wait for a while before all the adds are handled, because of ICQ's rate limiting. If your buddy list is very large and the ICQ server starts complaining, you might have to reconnect and enter this command again. + The following command will join you to the chatroom called <emphasis>bitlbee@conference.bitlbee.org</emphasis>. The channel will be called <emphasis>&bitlbee-help</emphasis> because <emphasis>&bitlbee</emphasis> will already be in use. Your nickname will be <emphasis>help-me</emphasis>. </para> </description> + <ircexample> + <ircline nick="wilmer">join_chat jabber bitlbee@conference.bitlbee.org &bitlbee-help help-me</ircline> + </ircexample> + </bitlbee-command> </chapter> @@ -229,9 +229,8 @@ 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->gc->wants_to_die = TRUE; - signoff(account->gc); + if (account->ic) { + imc_logout(account->ic, TRUE); } else if (account->reconnect) { cancel_auto_reconnect(account); } @@ -255,7 +254,12 @@ void irc_free(irc_t * irc) query_del(irc, irc->queries); while (irc->accounts) - account_del(irc, irc->accounts); + if (irc->accounts->ic == NULL) + account_del(irc, irc->accounts); + else + /* Nasty hack, but account_del() doesn't work in this + case and we don't want infinite loops, do we? ;-) */ + irc->accounts = irc->accounts->next; while (irc->set) set_del(&irc->set, irc->set->key); @@ -627,7 +631,7 @@ void irc_names( irc_t *irc, char *channel ) { user_t *u; char namelist[385] = ""; - struct conversation *c = NULL; + struct groupchat *c = NULL; char *ops = set_getstr( &irc->set, "ops" ); /* RFCs say there is no error reply allowed on NAMES, so when the @@ -643,7 +647,7 @@ void irc_names( irc_t *irc, char *channel ) *namelist = 0; } - if( u->gc && !u->away && set_getbool( &irc->set, "away_devoice" ) ) + if( u->ic && !u->away && set_getbool( &irc->set, "away_devoice" ) ) strcat( namelist, "+" ); else if( ( strcmp( u->nick, irc->mynick ) == 0 && ( strcmp( ops, "root" ) == 0 || strcmp( ops, "both" ) == 0 ) ) || ( strcmp( u->nick, irc->nick ) == 0 && ( strcmp( ops, "user" ) == 0 || strcmp( ops, "both" ) == 0 ) ) ) @@ -653,7 +657,7 @@ void irc_names( irc_t *irc, char *channel ) strcat( namelist, " " ); } } - else if( ( c = conv_findchannel( channel ) ) ) + else if( ( c = chat_by_channel( channel ) ) ) { GList *l; @@ -662,7 +666,7 @@ void irc_names( irc_t *irc, char *channel ) sprintf( namelist, "%s%s %s%s ", strcmp( ops, "root" ) == 0 || strcmp( ops, "both" ) ? "@" : "", irc->mynick, strcmp( ops, "user" ) == 0 || strcmp( ops, "both" ) ? "@" : "", irc->nick ); - for( l = c->in_room; l; l = l->next ) if( ( u = user_findhandle( c->gc, l->data ) ) ) + for( l = c->in_room; l; l = l->next ) if( ( u = user_findhandle( c->ic, l->data ) ) ) { if( strlen( namelist ) + strlen( u->nick ) > sizeof( namelist ) - 4 ) { @@ -806,7 +810,7 @@ void irc_topic( irc_t *irc, char *channel ) } else { - struct conversation *c = conv_findchannel( channel ); + struct groupchat *c = chat_by_channel( 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 ); @@ -905,17 +909,17 @@ void irc_kill( irc_t *irc, user_t *u ) char *nick, *s; char reason[128]; - if( u->gc && u->gc->flags & OPT_LOGGING_OUT ) + if( u->ic && u->ic->flags & OPT_LOGGING_OUT ) { - if( u->gc->acc->server ) + if( u->ic->acc->server ) g_snprintf( reason, sizeof( reason ), "%s %s", irc->myhost, - u->gc->acc->server ); - else if( ( s = strchr( u->gc->username, '@' ) ) ) + u->ic->acc->server ); + else if( ( s = strchr( u->ic->acc->user, '@' ) ) ) g_snprintf( reason, sizeof( reason ), "%s %s", irc->myhost, s + 1 ); else g_snprintf( reason, sizeof( reason ), "%s %s.%s", irc->myhost, - u->gc->acc->prpl->name, irc->myhost ); + u->ic->acc->prpl->name, irc->myhost ); /* proto_opt might contain garbage after the : */ if( ( s = strchr( reason, ':' ) ) ) @@ -939,12 +943,12 @@ void irc_kill( irc_t *irc, user_t *u ) int irc_send( irc_t *irc, char *nick, char *s, int flags ) { - struct conversation *c = NULL; + struct groupchat *c = NULL; user_t *u = NULL; if( *nick == '#' || *nick == '&' ) { - if( !( c = conv_findchannel( nick ) ) ) + if( !( c = chat_by_channel( nick ) ) ) { irc_reply( irc, 403, "%s :Channel does not exist", nick ); return( 0 ); @@ -991,13 +995,13 @@ int irc_send( irc_t *irc, char *nick, char *s, int flags ) } else if( g_strncasecmp( s + 1, "TYPING", 6 ) == 0 ) { - if( u && u->gc && u->gc->acc->prpl->send_typing && strlen( s ) >= 10 ) + if( u && u->ic && u->ic->acc->prpl->send_typing && strlen( s ) >= 10 ) { time_t current_typing_notice = time( NULL ); if( current_typing_notice - u->last_typing_notice >= 5 ) { - u->gc->acc->prpl->send_typing( u->gc, u->handle, s[8] == '1' ); + u->ic->acc->prpl->send_typing( u->ic, u->handle, ( s[8] - '0' ) << 8 ); u->last_typing_notice = current_typing_notice; } } @@ -1030,9 +1034,9 @@ int irc_send( irc_t *irc, char *nick, char *s, int flags ) return 1; } } - else if( c && c->gc && c->gc->acc && c->gc->acc->prpl ) + else if( c && c->ic && c->ic->acc && c->ic->acc->prpl ) { - return( bim_chat_msg( c->gc, c->id, s ) ); + return( imc_chat_msg( c, s, 0 ) ); } return( 0 ); @@ -1047,7 +1051,7 @@ static gboolean buddy_send_handler_delayed( gpointer data, gint fd, b_input_cond return FALSE; u->sendbuf[u->sendbuf_len-2] = 0; /* Cut off the last newline */ - bim_buddy_msg( u->gc, u->handle, u->sendbuf, u->sendbuf_flags ); + imc_buddy_msg( u->ic, u->handle, u->sendbuf, u->sendbuf_flags ); g_free( u->sendbuf ); u->sendbuf = NULL; @@ -1060,7 +1064,7 @@ static gboolean buddy_send_handler_delayed( gpointer data, gint fd, b_input_cond void buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags ) { - if( !u || !u->gc ) return; + if( !u || !u->ic ) return; if( set_getbool( &irc->set, "buddy_sendbuffer" ) && set_getint( &irc->set, "buddy_sendbuffer_delay" ) > 0 ) { @@ -1099,7 +1103,7 @@ void buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags ) } else { - bim_buddy_msg( u->gc, u->handle, msg, flags ); + imc_buddy_msg( u->ic, u->handle, msg, flags ); } } diff --git a/irc_commands.c b/irc_commands.c index b1045c93..8d841aaa 100644 --- a/irc_commands.c +++ b/irc_commands.c @@ -133,7 +133,7 @@ static void irc_cmd_names( irc_t *irc, char **cmd ) static void irc_cmd_part( irc_t *irc, char **cmd ) { - struct conversation *c; + struct groupchat *c; if( g_strcasecmp( cmd[1], irc->channel ) == 0 ) { @@ -143,16 +143,16 @@ static void irc_cmd_part( irc_t *irc, char **cmd ) irc_part( irc, u, irc->channel ); irc_join( irc, u, irc->channel ); } - else if( ( c = conv_findchannel( cmd[1] ) ) ) + else if( ( c = chat_by_channel( cmd[1] ) ) ) { user_t *u = user_find( irc, irc->nick ); irc_part( irc, u, c->channel ); - if( c->gc ) + if( c->ic ) { c->joined = 0; - c->gc->acc->prpl->chat_leave( c->gc, c->id ); + c->ic->acc->prpl->chat_leave( c ); } } else @@ -172,11 +172,11 @@ static void irc_cmd_join( irc_t *irc, char **cmd ) { user_t *u = user_find( irc, cmd[1] + 1 ); - if( u && u->gc && u->gc->acc->prpl->chat_open ) + if( u && u->ic && u->ic->acc->prpl->chat_with ) { irc_reply( irc, 403, "%s :Initializing groupchat in a different channel", cmd[1] ); - if( !u->gc->acc->prpl->chat_open( u->gc, u->handle ) ) + if( !u->ic->acc->prpl->chat_with( u->ic, u->handle ) ) { irc_usermsg( irc, "Could not open a groupchat with %s.", u->nick ); } @@ -200,13 +200,13 @@ static void irc_cmd_join( irc_t *irc, char **cmd ) static void irc_cmd_invite( irc_t *irc, char **cmd ) { char *nick = cmd[1], *channel = cmd[2]; - struct conversation *c = conv_findchannel( channel ); + struct groupchat *c = chat_by_channel( channel ); user_t *u = user_find( irc, nick ); - if( u && c && ( u->gc == c->gc ) ) - if( c->gc && c->gc->acc->prpl->chat_invite ) + if( u && c && ( u->ic == c->ic ) ) + if( c->ic && c->ic->acc->prpl->chat_invite ) { - c->gc->acc->prpl->chat_invite( c->gc, c->id, "", u->handle ); + c->ic->acc->prpl->chat_invite( c, "", u->handle ); irc_reply( irc, 341, "%s %s", nick, channel ); return; } @@ -262,7 +262,7 @@ static void irc_cmd_privmsg( irc_t *irc, char **cmd ) { irc->is_private = 1; } - irc_send( irc, cmd[1], cmd[2], ( g_strcasecmp( cmd[0], "NOTICE" ) == 0 ) ? IM_FLAG_AWAY : 0 ); + irc_send( irc, cmd[1], cmd[2], ( g_strcasecmp( cmd[0], "NOTICE" ) == 0 ) ? OPT_AWAY : 0 ); } } @@ -270,7 +270,7 @@ static void irc_cmd_who( irc_t *irc, char **cmd ) { char *channel = cmd[1]; user_t *u = irc->users; - struct conversation *c; + struct groupchat *c; GList *l; if( !channel || *channel == '0' || *channel == '*' || !*channel ) @@ -286,10 +286,10 @@ static void irc_cmd_who( irc_t *irc, char **cmd ) irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->away ? 'G' : 'H', u->realname ); u = u->next; } - else if( ( c = conv_findchannel( channel ) ) ) + else if( ( c = chat_by_channel( channel ) ) ) for( l = c->in_room; l; l = l->next ) { - if( ( u = user_findhandle( c->gc, l->data ) ) ) + if( ( u = user_findhandle( c->ic, l->data ) ) ) irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->away ? 'G' : 'H', u->realname ); } else if( ( u = user_find( irc, channel ) ) ) @@ -459,10 +459,10 @@ static void irc_cmd_away( irc_t *irc, char **cmd ) for( a = irc->accounts; a; a = a->next ) { - struct gaim_connection *gc = a->gc; + struct im_connection *ic = a->ic; - if( gc && gc->flags & OPT_LOGGED_IN ) - bim_set_away( gc, u->away ); + if( ic && ic->flags & OPT_LOGGED_IN ) + imc_set_away( ic, u->away ); } } @@ -475,10 +475,10 @@ static void irc_cmd_whois( irc_t *irc, char **cmd ) { irc_reply( irc, 311, "%s %s %s * :%s", u->nick, u->user, u->host, u->realname ); - if( u->gc ) - irc_reply( irc, 312, "%s %s.%s :%s network", u->nick, u->gc->acc->user, - u->gc->acc->server && *u->gc->acc->server ? u->gc->acc->server : "", - u->gc->acc->prpl->name ); + if( u->ic ) + irc_reply( irc, 312, "%s %s.%s :%s network", u->nick, u->ic->acc->user, + u->ic->acc->server && *u->ic->acc->server ? u->ic->acc->server : "", + u->ic->acc->prpl->name ); else irc_reply( irc, 312, "%s %s :%s", u->nick, irc->myhost, IRCD_INFO ); @@ -39,6 +39,11 @@ #include <glib.h> #include <time.h> +#ifdef HAVE_RESOLV_A +#include <arpa/nameser.h> +#include <resolv.h> +#endif + void strip_linefeed(gchar *text) { int i, j; @@ -487,3 +492,55 @@ int bool2int( char *value ) return 0; } + +struct ns_srv_reply *srv_lookup( char *service, char *protocol, char *domain ) +{ + struct ns_srv_reply *reply = NULL; +#ifdef HAVE_RESOLV_A + char name[1024]; + unsigned char querybuf[1024]; + const unsigned char *buf; + ns_msg nsh; + ns_rr rr; + int i, len, size; + + g_snprintf( name, sizeof( name ), "_%s._%s.%s", service, protocol, domain ); + + if( ( size = res_query( name, ns_c_in, ns_t_srv, querybuf, sizeof( querybuf ) ) ) <= 0 ) + return NULL; + + if( ns_initparse( querybuf, size, &nsh ) != 0 ) + return NULL; + + if( ns_parserr( &nsh, ns_s_an, 0, &rr ) != 0 ) + return NULL; + + size = ns_rr_rdlen( rr ); + buf = ns_rr_rdata( rr ); + + len = 0; + for( i = 6; i < size && buf[i]; i += buf[i] + 1 ) + len += buf[i] + 1; + + if( i > size ) + return NULL; + + reply = g_malloc( sizeof( struct ns_srv_reply ) + len ); + memcpy( reply->name, buf + 7, len ); + + for( i = buf[6]; i < len && buf[7+i]; i += buf[7+i] + 1 ) + reply->name[i] = '.'; + + if( i > len ) + { + g_free( reply ); + return NULL; + } + + reply->prio = ( buf[0] << 8 ) | buf[1]; + reply->weight = ( buf[2] << 8 ) | buf[3]; + reply->port = ( buf[4] << 8 ) | buf[5]; +#endif + + return reply; +} @@ -29,6 +29,14 @@ #include <gmodule.h> #include <time.h> +struct ns_srv_reply +{ + int prio; + int weight; + int port; + char name[]; +}; + G_MODULE_EXPORT void strip_linefeed( gchar *text ); G_MODULE_EXPORT char *add_cr( char *text ); G_MODULE_EXPORT char *strip_newlines(char *source); @@ -53,4 +61,6 @@ G_MODULE_EXPORT void random_bytes( unsigned char *buf, int count ); G_MODULE_EXPORT int is_bool( char *value ); G_MODULE_EXPORT int bool2int( char *value ); +G_MODULE_EXPORT struct ns_srv_reply *srv_lookup( char *service, char *protocol, char *domain ); + #endif diff --git a/lib/ssl_client.h b/lib/ssl_client.h index 964caee4..dcbf9a01 100644 --- a/lib/ssl_client.h +++ b/lib/ssl_client.h @@ -51,6 +51,10 @@ typedef gboolean (*ssl_input_function)(gpointer, void*, b_input_condition); blocking I/O! (Except for the DNS lookups, for now...) */ G_MODULE_EXPORT void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data ); +/* Start an SSL session on an existing fd. Useful for STARTTLS functionality, + for example in Jabber. */ +G_MODULE_EXPORT void *ssl_starttls( int fd, ssl_input_function func, gpointer data ); + /* Obviously you need special read/write functions to read data. */ G_MODULE_EXPORT int ssl_read( void *conn, char *buf, int len ); G_MODULE_EXPORT int ssl_write( void *conn, const char *buf, int len ); diff --git a/lib/ssl_gnutls.c b/lib/ssl_gnutls.c index 3ebe1756..fbd1d0c0 100644 --- a/lib/ssl_gnutls.c +++ b/lib/ssl_gnutls.c @@ -48,6 +48,8 @@ struct scd }; static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ); +static gboolean ssl_starttls_real( gpointer data, gint source, b_input_condition cond ); +static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond ); void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data ) @@ -62,25 +64,41 @@ void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data if( conn->fd < 0 ) { g_free( conn ); - return( NULL ); + return NULL; } - if( !initialized ) - { - gnutls_global_init(); - initialized = TRUE; - atexit( gnutls_global_deinit ); - } + return conn; +} + +void *ssl_starttls( int fd, ssl_input_function func, gpointer data ) +{ + struct scd *conn = g_new0( struct scd, 1 ); - gnutls_certificate_allocate_credentials( &conn->xcred ); - gnutls_init( &conn->session, GNUTLS_CLIENT ); - gnutls_set_default_priority( conn->session ); - gnutls_credentials_set( conn->session, GNUTLS_CRD_CERTIFICATE, conn->xcred ); + conn->fd = fd; + conn->func = func; + conn->data = data; + conn->inpa = -1; + + /* This function should be called via a (short) timeout instead of + directly from here, because these SSL calls are *supposed* to be + *completely* asynchronous and not ready yet when this function + (or *_connect, for examle) returns. Also, errors are reported via + the callback function, not via this function's return value. + + In short, doing things like this makes the rest of the code a lot + simpler. */ + + b_timeout_add( 1, ssl_starttls_real, conn ); - return( conn ); + return conn; } -static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond ); +static gboolean ssl_starttls_real( gpointer data, gint source, b_input_condition cond ) +{ + struct scd *conn = data; + + return ssl_connected( conn, conn->fd, GAIM_INPUT_WRITE ); +} static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ) { @@ -89,15 +107,22 @@ static gboolean ssl_connected( gpointer data, gint source, b_input_condition con if( source == -1 ) { conn->func( conn->data, NULL, cond ); - - gnutls_deinit( conn->session ); - gnutls_certificate_free_credentials( conn->xcred ); - g_free( conn ); - return FALSE; } + if( !initialized ) + { + gnutls_global_init(); + initialized = TRUE; + atexit( gnutls_global_deinit ); + } + + gnutls_certificate_allocate_credentials( &conn->xcred ); + gnutls_init( &conn->session, GNUTLS_CLIENT ); + gnutls_set_default_priority( conn->session ); + gnutls_credentials_set( conn->session, GNUTLS_CRD_CERTIFICATE, conn->xcred ); + sock_make_nonblocking( conn->fd ); gnutls_transport_set_ptr( conn->session, (gnutls_transport_ptr) conn->fd ); diff --git a/lib/ssl_openssl.c b/lib/ssl_openssl.c index b6f6c520..b1ba1db9 100644 --- a/lib/ssl_openssl.c +++ b/lib/ssl_openssl.c @@ -52,23 +52,66 @@ struct scd }; static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ); +static gboolean ssl_starttls_real( gpointer data, gint source, b_input_condition cond ); +static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond ); void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data ) { struct scd *conn = g_new0( struct scd, 1 ); - SSL_METHOD *meth; conn->fd = proxy_connect( host, port, ssl_connected, conn ); conn->func = func; conn->data = data; + conn->inpa = -1; if( conn->fd < 0 ) { g_free( conn ); - return( NULL ); + return NULL; } + return conn; +} + +void *ssl_starttls( int fd, ssl_input_function func, gpointer data ) +{ + struct scd *conn = g_new0( struct scd, 1 ); + + conn->fd = fd; + conn->func = func; + conn->data = data; + conn->inpa = -1; + + /* This function should be called via a (short) timeout instead of + directly from here, because these SSL calls are *supposed* to be + *completely* asynchronous and not ready yet when this function + (or *_connect, for examle) returns. Also, errors are reported via + the callback function, not via this function's return value. + + In short, doing things like this makes the rest of the code a lot + simpler. */ + + b_timeout_add( 1, ssl_starttls_real, conn ); + + return conn; +} + +static gboolean ssl_starttls_real( gpointer data, gint source, b_input_condition cond ) +{ + struct scd *conn = data; + + return ssl_connected( conn, conn->fd, GAIM_INPUT_WRITE ); +} + +static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ) +{ + struct scd *conn = data; + SSL_METHOD *meth; + + if( source == -1 ) + goto ssl_connected_failure; + if( !initialized ) { initialized = TRUE; @@ -78,35 +121,35 @@ void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data meth = TLSv1_client_method(); conn->ssl_ctx = SSL_CTX_new( meth ); if( conn->ssl_ctx == NULL ) - { - conn->fd = -1; - return( NULL ); - } + goto ssl_connected_failure; conn->ssl = SSL_new( conn->ssl_ctx ); if( conn->ssl == NULL ) - { - conn->fd = -1; - return( NULL ); - } - - return( conn ); -} - -static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond ); - -static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ) -{ - struct scd *conn = data; - - if( source == -1 ) - return ssl_handshake( data, -1, cond ); + goto ssl_connected_failure; /* We can do at least the handshake with non-blocking I/O */ sock_make_nonblocking( conn->fd ); SSL_set_fd( conn->ssl, conn->fd ); return ssl_handshake( data, source, cond ); + +ssl_connected_failure: + conn->func( conn->data, NULL, cond ); + + if( conn->ssl ) + { + SSL_shutdown( conn->ssl ); + SSL_free( conn->ssl ); + } + if( conn->ssl_ctx ) + { + SSL_CTX_free( conn->ssl_ctx ); + } + if( source >= 0 ) closesocket( source ); + g_free( conn ); + + return FALSE; + } static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond ) @@ -118,7 +161,18 @@ static gboolean ssl_handshake( gpointer data, gint source, b_input_condition con { 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->func( conn->data, NULL, cond ); + + SSL_shutdown( conn->ssl ); + SSL_free( conn->ssl ); + SSL_CTX_free( conn->ssl_ctx ); + + if( source >= 0 ) closesocket( source ); + g_free( conn ); + + return FALSE; + } conn->inpa = b_input_add( conn->fd, ssl_getdirection( conn ), ssl_handshake, data ); return FALSE; @@ -128,23 +182,6 @@ static gboolean ssl_handshake( gpointer data, gint source, b_input_condition con sock_make_blocking( conn->fd ); /* For now... */ conn->func( conn->data, conn, cond ); return FALSE; - -ssl_connected_failure: - conn->func( conn->data, NULL, cond ); - - if( conn->ssl ) - { - SSL_shutdown( conn->ssl ); - SSL_free( conn->ssl ); - } - if( conn->ssl_ctx ) - { - SSL_CTX_free( conn->ssl_ctx ); - } - if( source >= 0 ) closesocket( source ); - g_free( conn ); - - return FALSE; } int ssl_read( void *conn, char *buf, int len ) @@ -13,6 +13,6 @@ information. The developers of the Bee hope you have a buzzing time. -* BitlBee development team: wilmer, ctrlsoft, Maurits +* BitlBee development team: wilmer, jelmer, Maurits ... Buzzing, haha, get it? @@ -1,7 +1,7 @@ /********************************************************************\ * BitlBee -- An IRC to other IM-networks gateway * * * - * Copyright 2002-2006 Wilmer van der Gaast and others * + * Copyright 2002-2007 Wilmer van der Gaast and others * \********************************************************************/ /* Some stuff to fetch, save and handle nicknames for your buddies */ @@ -52,7 +52,7 @@ void nick_set( account_t *acc, const char *handle, const char *nick ) g_hash_table_replace( acc->nicks, store_handle, store_nick ); } -char *nick_get( account_t *acc, const char *handle, const char *realname ) +char *nick_get( account_t *acc, const char *handle ) { static char nick[MAX_NICK_LENGTH+1]; char *store_handle, *found_nick; @@ -76,12 +76,6 @@ char *nick_get( account_t *acc, const char *handle, const char *realname ) while( *s ) *(s++) = 0; - /* All-digit handles (mainly ICQ UINs) aren't cool, try to - use the realname instead. */ - for( s = nick; *s && isdigit( *s ); s ++ ); - if( !*s && realname && *realname ) - g_snprintf( nick, MAX_NICK_LENGTH, "%s", realname ); - nick_strip( nick ); if( set_getbool( &acc->irc->set, "lcnicks" ) ) nick_lc( nick ); @@ -129,6 +123,19 @@ char *nick_get( account_t *acc, const char *handle, const char *realname ) return nick; } +/* Just check if there is a nickname set for this buddy or if we'd have to + generate one. */ +int nick_saved( account_t *acc, const char *handle ) +{ + char *store_handle, *found; + + store_handle = clean_handle( handle ); + found = g_hash_table_lookup( acc->nicks, store_handle ); + g_free( store_handle ); + + return found != NULL; +} + void nick_del( account_t *acc, const char *handle ) { g_hash_table_remove( acc->nicks, handle ); @@ -175,7 +182,7 @@ int nick_ok( const char *nick ) int nick_lc( char *nick ) { - static char tab[256] = { 0 }; + static char tab[128] = { 0 }; int i; if( tab['A'] == 0 ) @@ -24,7 +24,8 @@ */ void nick_set( account_t *acc, const char *handle, const char *nick ); -char *nick_get( account_t *acc, const char *handle, const char *realname ); +char *nick_get( account_t *acc, const char *handle ); +int nick_saved( account_t *acc, const char *handle ); void nick_del( account_t *acc, const char *handle ); void nick_strip( char *nick ); diff --git a/protocols/jabber/Makefile b/protocols/jabber/Makefile index 7a185d00..e81e6c5a 100644 --- a/protocols/jabber/Makefile +++ b/protocols/jabber/Makefile @@ -9,7 +9,7 @@ -include ../../Makefile.settings # [SH] Program variables -objects = expat.o hashtable.o jid.o jpacket.o jutil.o log.o pool.o str.o xmlnode.o xmlparse.o xmlrole.o xmltok.o jabber.o +objects = io.o iq.o jabber.o jabber_util.o message.o presence.o sasl.o xmltree.o CFLAGS += -Wall LFLAGS += -r diff --git a/protocols/jabber/asciitab.h b/protocols/jabber/asciitab.h deleted file mode 100644 index 8a8a2dd3..00000000 --- a/protocols/jabber/asciitab.h +++ /dev/null @@ -1,62 +0,0 @@ -/* -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in -compliance with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" -basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -License for the specific language governing rights and limitations -under the License. - -The Original Code is expat. - -The Initial Developer of the Original Code is James Clark. -Portions created by James Clark are Copyright (C) 1998, 1999 -James Clark. All Rights Reserved. - -Contributor(s): - -Alternatively, the contents of this file may be used under the terms -of the GNU General Public License (the "GPL"), in which case the -provisions of the GPL are applicable instead of those above. If you -wish to allow use of your version of this file only under the terms of -the GPL and not to allow others to use your version of this file under -the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the -GPL. If you do not delete the provisions above, a recipient may use -your version of this file under either the MPL or the GPL. -*/ - -/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, -/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, -/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML, -/* 0x0C */ BT_NONXML, BT_CR, BT_NONXML, BT_NONXML, -/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, -/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, -/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, -/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, -/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM, -/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS, -/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS, -/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL, -/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, -/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, -/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI, -/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST, -/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, -/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, -/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB, -/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT, -/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, -/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, -/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, -/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER, diff --git a/protocols/jabber/expat.c b/protocols/jabber/expat.c deleted file mode 100644 index 0eedb321..00000000 --- a/protocols/jabber/expat.c +++ /dev/null @@ -1,54 +0,0 @@ -/* -------------------------------------------------------------------------- - * - * License - * - * The contents of this file are subject to the Jabber Open Source License - * Version 1.0 (the "JOSL"). You may not copy or use this file, in either - * source code or executable form, except in compliance with the JOSL. You - * may obtain a copy of the JOSL at http://www.jabber.org/ or at - * http://www.opensource.org/. - * - * Software distributed under the JOSL is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the JOSL - * for the specific language governing rights and limitations under the - * JOSL. - * - * Copyrights - * - * Portions created by or assigned to Jabber.com, Inc. are - * Copyright (c) 1999-2002 Jabber.com, Inc. All Rights Reserved. Contact - * information for Jabber.com, Inc. is available at http://www.jabber.com/. - * - * Portions Copyright (c) 1998-1999 Jeremie Miller. - * - * Acknowledgements - * - * Special thanks to the Jabber Open Source Contributors for their - * suggestions and support of Jabber. - * - * Alternatively, the contents of this file may be used under the terms of the - * GNU General Public License Version 2 or later (the "GPL"), in which case - * the provisions of the GPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * GPL and not to allow others to use your version of this file under the JOSL, - * indicate your decision by deleting the provisions above and replace them - * with the notice and other provisions required by the GPL. If you do not - * delete the provisions above, a recipient may use your version of this file - * under either the JOSL or the GPL. - * - * - * --------------------------------------------------------------------------*/ - -#include "lib.h" -#include <glib.h> - -void xmlnode_put_expat_attribs(xmlnode owner, const char** atts) -{ - int i = 0; - if (atts == NULL) return; - while (atts[i] != '\0') - { - xmlnode_put_attrib(owner, atts[i], atts[i+1]); - i += 2; - } -} diff --git a/protocols/jabber/hashtable.c b/protocols/jabber/hashtable.c deleted file mode 100644 index 82c33bc3..00000000 --- a/protocols/jabber/hashtable.c +++ /dev/null @@ -1,142 +0,0 @@ -/* -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in -csompliance with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" -basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -License for the specific language governing rights and limitations -under the License. - -The Original Code is expat. - -The Initial Developer of the Original Code is James Clark. -Portions created by James Clark are Copyright (C) 1998, 1999 -James Clark. All Rights Reserved. - -Contributor(s): - -*/ - -#include "xmldef.h" - -#ifdef XML_UNICODE_WCHAR_T -#ifndef XML_UNICODE -#define XML_UNICODE -#endif -#endif - -#include "hashtable.h" - -#define INIT_SIZE 64 - -static -int keyeq(KEY s1, KEY s2) -{ - for (; *s1 == *s2; s1++, s2++) - if (*s1 == 0) - return 1; - return 0; -} - -static -unsigned long hash(KEY s) -{ - unsigned long h = 0; - while (*s) - h = (h << 5) + h + (unsigned char)*s++; - return h; -} - -NAMED *lookup(HASH_TABLE *table, KEY name, size_t createSize) -{ - size_t i; - if (table->size == 0) { - if (!createSize) - return 0; - table->v = calloc(INIT_SIZE, sizeof(NAMED *)); - if (!table->v) - return 0; - table->size = INIT_SIZE; - table->usedLim = INIT_SIZE / 2; - i = hash(name) & (table->size - 1); - } - else { - unsigned long h = hash(name); - for (i = h & (table->size - 1); - table->v[i]; - i == 0 ? i = table->size - 1 : --i) { - if (keyeq(name, table->v[i]->name)) - return table->v[i]; - } - if (!createSize) - return 0; - if (table->used == table->usedLim) { - /* check for overflow */ - size_t newSize = table->size * 2; - NAMED **newV = calloc(newSize, sizeof(NAMED *)); - if (!newV) - return 0; - for (i = 0; i < table->size; i++) - if (table->v[i]) { - size_t j; - for (j = hash(table->v[i]->name) & (newSize - 1); - newV[j]; - j == 0 ? j = newSize - 1 : --j) - ; - newV[j] = table->v[i]; - } - g_free(table->v); - table->v = newV; - table->size = newSize; - table->usedLim = newSize/2; - for (i = h & (table->size - 1); - table->v[i]; - i == 0 ? i = table->size - 1 : --i) - ; - } - } - table->v[i] = calloc(1, createSize); - if (!table->v[i]) - return 0; - table->v[i]->name = name; - (table->used)++; - return table->v[i]; -} - -void hashTableDestroy(HASH_TABLE *table) -{ - size_t i; - for (i = 0; i < table->size; i++) { - NAMED *p = table->v[i]; - if (p) - g_free(p); - } - g_free(table->v); -} - -void hashTableInit(HASH_TABLE *p) -{ - p->size = 0; - p->usedLim = 0; - p->used = 0; - p->v = 0; -} - -void hashTableIterInit(HASH_TABLE_ITER *iter, const HASH_TABLE *table) -{ - iter->p = table->v; - iter->end = iter->p + table->size; -} - -NAMED *hashTableIterNext(HASH_TABLE_ITER *iter) -{ - while (iter->p != iter->end) { - NAMED *tem = *(iter->p)++; - if (tem) - return tem; - } - return 0; -} - diff --git a/protocols/jabber/hashtable.h b/protocols/jabber/hashtable.h deleted file mode 100644 index df8ab8a4..00000000 --- a/protocols/jabber/hashtable.h +++ /dev/null @@ -1,69 +0,0 @@ -/* -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in -compliance with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" -basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -License for the specific language governing rights and limitations -under the License. - -The Original Code is expat. - -The Initial Developer of the Original Code is James Clark. -Portions created by James Clark are Copyright (C) 1998, 1999 -James Clark. All Rights Reserved. - -Contributor(s): - -Alternatively, the contents of this file may be used under the terms -of the GNU General Public License (the "GPL"), in which case the -provisions of the GPL are applicable instead of those above. If you -wish to allow use of your version of this file only under the terms of -the GPL and not to allow others to use your version of this file under -the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the -GPL. If you do not delete the provisions above, a recipient may use -your version of this file under either the MPL or the GPL. -*/ - - -#include <stddef.h> - -#ifdef XML_UNICODE - -#ifdef XML_UNICODE_WCHAR_T -typedef const wchar_t *KEY; -#else /* not XML_UNICODE_WCHAR_T */ -typedef const unsigned short *KEY; -#endif /* not XML_UNICODE_WCHAR_T */ - -#else /* not XML_UNICODE */ - -typedef const char *KEY; - -#endif /* not XML_UNICODE */ - -typedef struct { - KEY name; -} NAMED; - -typedef struct { - NAMED **v; - size_t size; - size_t used; - size_t usedLim; -} HASH_TABLE; - -NAMED *lookup(HASH_TABLE *table, KEY name, size_t createSize); -void hashTableInit(HASH_TABLE *); -void hashTableDestroy(HASH_TABLE *); - -typedef struct { - NAMED **p; - NAMED **end; -} HASH_TABLE_ITER; - -void hashTableIterInit(HASH_TABLE_ITER *, const HASH_TABLE *); -NAMED *hashTableIterNext(HASH_TABLE_ITER *); diff --git a/protocols/jabber/iasciitab.h b/protocols/jabber/iasciitab.h deleted file mode 100644 index 333d6bb7..00000000 --- a/protocols/jabber/iasciitab.h +++ /dev/null @@ -1,63 +0,0 @@ -/* -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in -compliance with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" -basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -License for the specific language governing rights and limitations -under the License. - -The Original Code is expat. - -The Initial Developer of the Original Code is James Clark. -Portions created by James Clark are Copyright (C) 1998, 1999 -James Clark. All Rights Reserved. - -Contributor(s): - -Alternatively, the contents of this file may be used under the terms -of the GNU General Public License (the "GPL"), in which case the -provisions of the GPL are applicable instead of those above. If you -wish to allow use of your version of this file only under the terms of -the GPL and not to allow others to use your version of this file under -the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the -GPL. If you do not delete the provisions above, a recipient may use -your version of this file under either the MPL or the GPL. -*/ - -/* Like asciitab.h, except that 0xD has code BT_S rather than BT_CR */ -/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, -/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, -/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML, -/* 0x0C */ BT_NONXML, BT_S, BT_NONXML, BT_NONXML, -/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, -/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, -/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, -/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, -/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM, -/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS, -/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS, -/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL, -/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, -/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, -/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI, -/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST, -/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, -/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, -/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB, -/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT, -/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, -/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, -/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, -/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER, diff --git a/protocols/jabber/io.c b/protocols/jabber/io.c new file mode 100644 index 00000000..67deb3a6 --- /dev/null +++ b/protocols/jabber/io.c @@ -0,0 +1,549 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Jabber module - I/O stuff (plain, SSL), queues, etc * +* * +* Copyright 2006 Wilmer van der Gaast <wilmer@gaast.net> * +* * +* 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 along * +* with this program; if not, write to the Free Software Foundation, Inc., * +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * +* * +\***************************************************************************/ + +#include "jabber.h" +#include "ssl_client.h" + +static gboolean jabber_write_callback( gpointer data, gint fd, b_input_condition cond ); +static gboolean jabber_write_queue( struct im_connection *ic ); + +int jabber_write_packet( struct im_connection *ic, struct xt_node *node ) +{ + char *buf; + int st; + + buf = xt_to_string( node ); + st = jabber_write( ic, buf, strlen( buf ) ); + g_free( buf ); + + return st; +} + +int jabber_write( struct im_connection *ic, char *buf, int len ) +{ + struct jabber_data *jd = ic->proto_data; + gboolean ret; + + if( jd->tx_len == 0 ) + { + /* If the queue is empty, allocate a new buffer. */ + jd->tx_len = len; + jd->txq = g_memdup( buf, len ); + + /* Try if we can write it immediately so we don't have to do + it via the event handler. If not, add the handler. (In + most cases it probably won't be necessary.) */ + if( ( ret = jabber_write_queue( ic ) ) && jd->tx_len > 0 ) + jd->w_inpa = b_input_add( jd->fd, GAIM_INPUT_WRITE, jabber_write_callback, ic ); + } + else + { + /* Just add it to the buffer if it's already filled. The + event handler is already set. */ + jd->txq = g_renew( char, jd->txq, jd->tx_len + len ); + memcpy( jd->txq + jd->tx_len, buf, len ); + jd->tx_len += len; + + /* The return value for write() doesn't necessarily mean + that everything got sent, it mainly means that the + connection (officially) still exists and can still + be accessed without hitting SIGSEGV. IOW: */ + ret = TRUE; + } + + return ret; +} + +/* Splitting up in two separate functions: One to use as a callback and one + to use in the function above to escape from having to wait for the event + handler to call us, if possible. + + Two different functions are necessary because of the return values: The + callback should only return TRUE if the write was successful AND if the + buffer is not empty yet (ie. if the handler has to be called again when + the socket is ready for more data). */ +static gboolean jabber_write_callback( gpointer data, gint fd, b_input_condition cond ) +{ + struct jabber_data *jd = ((struct im_connection *)data)->proto_data; + + return jd->fd != -1 && + jabber_write_queue( data ) && + jd->tx_len > 0; +} + +static gboolean jabber_write_queue( struct im_connection *ic ) +{ + struct jabber_data *jd = ic->proto_data; + int st; + + if( jd->ssl ) + st = ssl_write( jd->ssl, jd->txq, jd->tx_len ); + else + st = write( jd->fd, jd->txq, jd->tx_len ); + + if( st == jd->tx_len ) + { + /* We wrote everything, clear the buffer. */ + g_free( jd->txq ); + jd->txq = NULL; + jd->tx_len = 0; + + return TRUE; + } + else if( st == 0 || ( st < 0 && !sockerr_again() ) ) + { + /* Set fd to -1 to make sure we won't write to it anymore. */ + closesocket( jd->fd ); /* Shouldn't be necessary after errors? */ + jd->fd = -1; + + imcb_error( ic, "Short write() to server" ); + imc_logout( ic, TRUE ); + return FALSE; + } + else if( st > 0 ) + { + char *s; + + s = g_memdup( jd->txq + st, jd->tx_len - st ); + jd->tx_len -= st; + g_free( jd->txq ); + jd->txq = s; + + return TRUE; + } + else + { + /* Just in case we had EINPROGRESS/EAGAIN: */ + + return TRUE; + } +} + +static gboolean jabber_read_callback( gpointer data, gint fd, b_input_condition cond ) +{ + struct im_connection *ic = data; + struct jabber_data *jd = ic->proto_data; + char buf[512]; + int st; + + if( jd->fd == -1 ) + return FALSE; + + if( jd->ssl ) + st = ssl_read( jd->ssl, buf, sizeof( buf ) ); + else + st = read( jd->fd, buf, sizeof( buf ) ); + + if( st > 0 ) + { + /* Parse. */ + if( xt_feed( jd->xt, buf, st ) < 0 ) + { + imcb_error( ic, "XML stream error" ); + imc_logout( ic, TRUE ); + return FALSE; + } + + /* Execute all handlers. */ + if( !xt_handle( jd->xt, NULL, 1 ) ) + { + /* Don't do anything, the handlers should have + aborted the connection already. */ + return FALSE; + } + + if( jd->flags & JFLAG_STREAM_RESTART ) + { + jd->flags &= ~JFLAG_STREAM_RESTART; + jabber_start_stream( ic ); + } + + /* Garbage collection. */ + xt_cleanup( jd->xt, NULL, 1 ); + + /* This is a bit hackish, unfortunately. Although xmltree + has nifty event handler stuff, it only calls handlers + when nodes are complete. Since the server should only + send an opening <stream:stream> tag, we have to check + this by hand. :-( */ + if( !( jd->flags & JFLAG_STREAM_STARTED ) && jd->xt && jd->xt->root ) + { + if( g_strcasecmp( jd->xt->root->name, "stream:stream" ) == 0 ) + { + jd->flags |= JFLAG_STREAM_STARTED; + + /* If there's no version attribute, assume + this is an old server that can't do SASL + authentication. */ + if( !sasl_supported( ic ) ) + { + /* If there's no version= tag, we suppose + this server does NOT implement: XMPP 1.0, + SASL and TLS. */ + if( set_getbool( &ic->acc->set, "tls" ) ) + { + imcb_error( ic, "TLS is turned on for this " + "account, but is not supported by this server" ); + imc_logout( ic, FALSE ); + return FALSE; + } + else + { + return jabber_init_iq_auth( ic ); + } + } + } + else + { + imcb_error( ic, "XML stream error" ); + imc_logout( ic, TRUE ); + return FALSE; + } + } + } + else if( st == 0 || ( st < 0 && !sockerr_again() ) ) + { + closesocket( jd->fd ); + jd->fd = -1; + + imcb_error( ic, "Error while reading from server" ); + imc_logout( ic, TRUE ); + return FALSE; + } + + /* EAGAIN/etc or a successful read. */ + return TRUE; +} + +gboolean jabber_connected_plain( gpointer data, gint source, b_input_condition cond ) +{ + struct im_connection *ic = data; + + if( source == -1 ) + { + imcb_error( ic, "Could not connect to server" ); + imc_logout( ic, TRUE ); + return FALSE; + } + + imcb_log( ic, "Connected to server, logging in" ); + + return jabber_start_stream( ic ); +} + +gboolean jabber_connected_ssl( gpointer data, void *source, b_input_condition cond ) +{ + struct im_connection *ic = data; + struct jabber_data *jd = ic->proto_data; + + if( source == NULL ) + { + /* The SSL connection will be cleaned up by the SSL lib + already, set it to NULL here to prevent a double cleanup: */ + jd->ssl = NULL; + + imcb_error( ic, "Could not connect to server" ); + imc_logout( ic, TRUE ); + return FALSE; + } + + imcb_log( ic, "Connected to server, logging in" ); + + return jabber_start_stream( ic ); +} + +static xt_status jabber_end_of_stream( struct xt_node *node, gpointer data ) +{ + imc_logout( data, TRUE ); + return XT_ABORT; +} + +static xt_status jabber_pkt_features( struct xt_node *node, gpointer data ) +{ + struct im_connection *ic = data; + struct jabber_data *jd = ic->proto_data; + struct xt_node *c, *reply; + int trytls; + + trytls = g_strcasecmp( set_getstr( &ic->acc->set, "tls" ), "try" ) == 0; + c = xt_find_node( node->children, "starttls" ); + if( c && !jd->ssl ) + { + /* If the server advertises the STARTTLS feature and if we're + not in a secure connection already: */ + + c = xt_find_node( c->children, "required" ); + + if( c && ( !trytls && !set_getbool( &ic->acc->set, "tls" ) ) ) + { + imcb_error( ic, "Server requires TLS connections, but TLS is turned off for this account" ); + imc_logout( ic, FALSE ); + + return XT_ABORT; + } + + /* Only run this if the tls setting is set to true or try: */ + if( ( trytls || set_getbool( &ic->acc->set, "tls" ) ) ) + { + reply = xt_new_node( "starttls", NULL, NULL ); + xt_add_attr( reply, "xmlns", XMLNS_TLS ); + if( !jabber_write_packet( ic, reply ) ) + { + xt_free_node( reply ); + return XT_ABORT; + } + xt_free_node( reply ); + + return XT_HANDLED; + } + } + else if( !c && !jd->ssl ) + { + /* If the server does not advertise the STARTTLS feature and + we're not in a secure connection already: (Servers have a + habit of not advertising <starttls/> anymore when already + using SSL/TLS. */ + + if( !trytls && set_getbool( &ic->acc->set, "tls" ) ) + { + imcb_error( ic, "TLS is turned on for this account, but is not supported by this server" ); + imc_logout( ic, FALSE ); + + return XT_ABORT; + } + } + + /* This one used to be in jabber_handlers[], but it has to be done + from here to make sure the TLS session will be initialized + properly before we attempt SASL authentication. */ + if( ( c = xt_find_node( node->children, "mechanisms" ) ) ) + { + if( sasl_pkt_mechanisms( c, data ) == XT_ABORT ) + return XT_ABORT; + } + /* If the server *SEEMS* to support SASL authentication but doesn't + support it after all, we should try to do authentication the + other way. jabber.com doesn't seem to do SASL while it pretends + to be XMPP 1.0 compliant! */ + else if( !( jd->flags & JFLAG_AUTHENTICATED ) && sasl_supported( ic ) ) + { + if( !jabber_init_iq_auth( ic ) ) + return XT_ABORT; + } + + if( ( c = xt_find_node( node->children, "bind" ) ) ) + { + reply = xt_new_node( "bind", NULL, xt_new_node( "resource", set_getstr( &ic->acc->set, "resource" ), NULL ) ); + xt_add_attr( reply, "xmlns", XMLNS_BIND ); + reply = jabber_make_packet( "iq", "set", NULL, reply ); + jabber_cache_add( ic, reply, jabber_pkt_bind_sess ); + + if( !jabber_write_packet( ic, reply ) ) + return XT_ABORT; + + jd->flags |= JFLAG_WAIT_BIND; + } + + if( ( c = xt_find_node( node->children, "session" ) ) ) + { + reply = xt_new_node( "session", NULL, NULL ); + xt_add_attr( reply, "xmlns", XMLNS_SESSION ); + reply = jabber_make_packet( "iq", "set", NULL, reply ); + jabber_cache_add( ic, reply, jabber_pkt_bind_sess ); + + if( !jabber_write_packet( ic, reply ) ) + return XT_ABORT; + + jd->flags |= JFLAG_WAIT_SESSION; + } + + /* This flag is already set if we authenticated via SASL, so now + we can resume the session in the new stream, if we don't have + to bind/initialize the session. */ + if( jd->flags & JFLAG_AUTHENTICATED && ( jd->flags & ( JFLAG_WAIT_BIND | JFLAG_WAIT_SESSION ) ) == 0 ) + { + if( !jabber_get_roster( ic ) ) + return XT_ABORT; + } + + return XT_HANDLED; +} + +static xt_status jabber_pkt_proceed_tls( struct xt_node *node, gpointer data ) +{ + struct im_connection *ic = data; + struct jabber_data *jd = ic->proto_data; + char *xmlns; + + xmlns = xt_find_attr( node, "xmlns" ); + + /* Just ignore it when it doesn't seem to be TLS-related (is that at + all possible??). */ + if( !xmlns || strcmp( xmlns, XMLNS_TLS ) != 0 ) + return XT_HANDLED; + + /* We don't want event handlers to touch our TLS session while it's + still initializing! */ + b_event_remove( jd->r_inpa ); + if( jd->tx_len > 0 ) + { + /* Actually the write queue should be empty here, but just + to be sure... */ + b_event_remove( jd->w_inpa ); + g_free( jd->txq ); + jd->txq = NULL; + jd->tx_len = 0; + } + jd->w_inpa = jd->r_inpa = 0; + + imcb_log( ic, "Converting stream to TLS" ); + + jd->ssl = ssl_starttls( jd->fd, jabber_connected_ssl, ic ); + + return XT_HANDLED; +} + +static xt_status jabber_pkt_stream_error( struct xt_node *node, gpointer data ) +{ + struct im_connection *ic = data; + struct xt_node *c; + char *s, *type = NULL, *text = NULL; + int allow_reconnect = TRUE; + + for( c = node->children; c; c = c->next ) + { + if( !( s = xt_find_attr( c, "xmlns" ) ) || + strcmp( s, XMLNS_STREAM_ERROR ) != 0 ) + continue; + + if( strcmp( c->name, "text" ) != 0 ) + { + type = c->name; + } + /* Only use the text if it doesn't have an xml:lang attribute, + if it's empty or if it's set to something English. */ + else if( !( s = xt_find_attr( c, "xml:lang" ) ) || + !*s || strncmp( s, "en", 2 ) == 0 ) + { + text = c->text; + } + } + + /* Tssk... */ + if( type == NULL ) + { + imcb_error( ic, "Unknown stream error reported by server" ); + imc_logout( ic, allow_reconnect ); + return XT_ABORT; + } + + /* We know that this is a fatal error. If it's a "conflict" error, we + should turn off auto-reconnect to make sure we won't get some nasty + infinite loop! */ + if( strcmp( type, "conflict" ) == 0 ) + { + imcb_error( ic, "Account and resource used from a different location" ); + allow_reconnect = FALSE; + } + else + { + imcb_error( ic, "Stream error: %s%s%s", type, text ? ": " : "", text ? text : "" ); + } + + imc_logout( ic, allow_reconnect ); + + return XT_ABORT; +} + +static xt_status jabber_pkt_misc( struct xt_node *node, gpointer data ) +{ + printf( "Received unknown packet:\n" ); + xt_print( node ); + + return XT_HANDLED; +} + +static const struct xt_handler_entry jabber_handlers[] = { + { "stream:stream", "<root>", jabber_end_of_stream }, + { "message", "stream:stream", jabber_pkt_message }, + { "presence", "stream:stream", jabber_pkt_presence }, + { "iq", "stream:stream", jabber_pkt_iq }, + { "stream:features", "stream:stream", jabber_pkt_features }, + { "stream:error", "stream:stream", jabber_pkt_stream_error }, + { "proceed", "stream:stream", jabber_pkt_proceed_tls }, + { "challenge", "stream:stream", sasl_pkt_challenge }, + { "success", "stream:stream", sasl_pkt_result }, + { "failure", "stream:stream", sasl_pkt_result }, + { NULL, "stream:stream", jabber_pkt_misc }, + { NULL, NULL, NULL } +}; + +gboolean jabber_start_stream( struct im_connection *ic ) +{ + struct jabber_data *jd = ic->proto_data; + int st; + char *greet; + + /* We'll start our stream now, so prepare everything to receive one + from the server too. */ + xt_free( jd->xt ); /* In case we're RE-starting. */ + jd->xt = xt_new( ic ); + jd->xt->handlers = (struct xt_handler_entry*) jabber_handlers; + + if( jd->r_inpa <= 0 ) + jd->r_inpa = b_input_add( jd->fd, GAIM_INPUT_READ, jabber_read_callback, ic ); + + greet = g_strdup_printf( "<?xml version='1.0' ?>" + "<stream:stream to=\"%s\" xmlns=\"jabber:client\" " + "xmlns:stream=\"http://etherx.jabber.org/streams\" version=\"1.0\">", jd->server ); + + st = jabber_write( ic, greet, strlen( greet ) ); + + g_free( greet ); + + return st; +} + +void jabber_end_stream( struct im_connection *ic ) +{ + struct jabber_data *jd = ic->proto_data; + + /* Let's only do this if the queue is currently empty, otherwise it'd + take too long anyway. */ + if( jd->tx_len == 0 ) + { + char eos[] = "</stream:stream>"; + struct xt_node *node; + int st = 1; + + if( ic->flags & OPT_LOGGED_IN ) + { + node = jabber_make_packet( "presence", "unavailable", NULL, NULL ); + st = jabber_write_packet( ic, node ); + xt_free_node( node ); + } + + if( st ) + jabber_write( ic, eos, strlen( eos ) ); + } +} diff --git a/protocols/jabber/iq.c b/protocols/jabber/iq.c new file mode 100644 index 00000000..2aa9d432 --- /dev/null +++ b/protocols/jabber/iq.c @@ -0,0 +1,577 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Jabber module - IQ packets * +* * +* Copyright 2006 Wilmer van der Gaast <wilmer@gaast.net> * +* * +* 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 along * +* with this program; if not, write to the Free Software Foundation, Inc., * +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * +* * +\***************************************************************************/ + +#include "jabber.h" + +static xt_status jabber_parse_roster( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ); +static xt_status jabber_iq_display_vcard( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ); + +xt_status jabber_pkt_iq( struct xt_node *node, gpointer data ) +{ + struct im_connection *ic = data; + struct jabber_data *jd = ic->proto_data; + struct xt_node *c, *reply = NULL; + char *type, *s; + int st, pack = 1; + + type = xt_find_attr( node, "type" ); + + if( !type ) + { + imcb_error( ic, "Received IQ packet without type." ); + imc_logout( ic, TRUE ); + return XT_ABORT; + } + + if( strcmp( type, "result" ) == 0 || strcmp( type, "error" ) == 0 ) + { + struct jabber_cache_entry *entry; + + if( ( s = xt_find_attr( node, "id" ) ) == NULL || + strncmp( s, JABBER_CACHED_ID, strlen( JABBER_CACHED_ID ) ) != 0 ) + { + /* Silently ignore it, without an ID (or a non-cache + ID) we don't know how to handle the packet and we + probably don't have to. */ + return XT_HANDLED; + } + + entry = g_hash_table_lookup( jd->node_cache, s ); + + if( entry == NULL ) + imcb_log( ic, "WARNING: Received IQ-%s packet with unknown/expired ID %s!", type, s ); + else if( entry->func ) + return entry->func( ic, node, entry->node ); + } + else if( strcmp( type, "get" ) == 0 ) + { + if( !( c = xt_find_node( node->children, "query" ) ) || + !( s = xt_find_attr( c, "xmlns" ) ) ) + { + imcb_log( ic, "WARNING: Received incomplete IQ-%s packet", type ); + return XT_HANDLED; + } + + reply = xt_new_node( "query", NULL, NULL ); + xt_add_attr( reply, "xmlns", s ); + + /* Of course this is a very essential query to support. ;-) */ + if( strcmp( s, XMLNS_VERSION ) == 0 ) + { + xt_add_child( reply, xt_new_node( "name", "BitlBee", NULL ) ); + xt_add_child( reply, xt_new_node( "version", BITLBEE_VERSION, NULL ) ); + xt_add_child( reply, xt_new_node( "os", ARCH, NULL ) ); + } + else if( strcmp( s, XMLNS_TIME ) == 0 ) + { + time_t time_ep; + char buf[1024]; + + buf[sizeof(buf)-1] = 0; + time_ep = time( NULL ); + + strftime( buf, sizeof( buf ) - 1, "%Y%m%dT%H:%M:%S", gmtime( &time_ep ) ); + xt_add_child( reply, xt_new_node( "utc", buf, NULL ) ); + + strftime( buf, sizeof( buf ) - 1, "%Z", localtime( &time_ep ) ); + xt_add_child( reply, xt_new_node( "tz", buf, NULL ) ); + } + else if( strcmp( s, XMLNS_DISCOVER ) == 0 ) + { + c = xt_new_node( "identity", NULL, NULL ); + xt_add_attr( c, "category", "client" ); + xt_add_attr( c, "type", "pc" ); + xt_add_attr( c, "name", "BitlBee" ); + xt_add_child( reply, c ); + + c = xt_new_node( "feature", NULL, NULL ); + xt_add_attr( c, "var", XMLNS_VERSION ); + xt_add_child( reply, c ); + + c = xt_new_node( "feature", NULL, NULL ); + xt_add_attr( c, "var", XMLNS_TIME ); + xt_add_child( reply, c ); + + c = xt_new_node( "feature", NULL, NULL ); + xt_add_attr( c, "var", XMLNS_CHATSTATES ); + xt_add_child( reply, c ); + + /* Later this can be useful to announce things like + MUC support. */ + } + else + { + xt_free_node( reply ); + reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel" ); + pack = 0; + } + } + else if( strcmp( type, "set" ) == 0 ) + { + if( !( c = xt_find_node( node->children, "query" ) ) || + !( s = xt_find_attr( c, "xmlns" ) ) ) + { + imcb_log( ic, "WARNING: Received incomplete IQ-%s packet", type ); + return XT_HANDLED; + } + + /* This is a roster push. XMPP servers send this when someone + was added to (or removed from) the buddy list. AFAIK they're + sent even if we added this buddy in our own session. */ + if( strcmp( s, XMLNS_ROSTER ) == 0 ) + { + int bare_len = strlen( ic->acc->user ); + + if( ( s = xt_find_attr( node, "from" ) ) == NULL || + ( strncmp( s, ic->acc->user, bare_len ) == 0 && + ( s[bare_len] == 0 || s[bare_len] == '/' ) ) ) + { + jabber_parse_roster( ic, node, NULL ); + + /* Should we generate a reply here? Don't think it's + very important... */ + } + else + { + imcb_log( ic, "WARNING: %s tried to fake a roster push!", s ? s : "(unknown)" ); + + xt_free_node( reply ); + reply = jabber_make_error_packet( node, "not-allowed", "cancel" ); + pack = 0; + } + } + else + { + xt_free_node( reply ); + reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel" ); + pack = 0; + } + } + + /* If we recognized the xmlns and managed to generate a reply, + finish and send it. */ + if( reply ) + { + /* Normally we still have to pack it into an iq-result + packet, but for errors, for example, we don't. */ + if( pack ) + { + reply = jabber_make_packet( "iq", "result", xt_find_attr( node, "from" ), reply ); + if( ( s = xt_find_attr( node, "id" ) ) ) + xt_add_attr( reply, "id", s ); + } + + st = jabber_write_packet( ic, reply ); + xt_free_node( reply ); + if( !st ) + return XT_ABORT; + } + + return XT_HANDLED; +} + +static xt_status jabber_do_iq_auth( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ); +static xt_status jabber_finish_iq_auth( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ); + +int jabber_init_iq_auth( struct im_connection *ic ) +{ + struct jabber_data *jd = ic->proto_data; + struct xt_node *node; + int st; + + node = xt_new_node( "query", NULL, xt_new_node( "username", jd->username, NULL ) ); + xt_add_attr( node, "xmlns", XMLNS_AUTH ); + node = jabber_make_packet( "iq", "get", NULL, node ); + + jabber_cache_add( ic, node, jabber_do_iq_auth ); + st = jabber_write_packet( ic, node ); + + return st; +} + +static xt_status jabber_do_iq_auth( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ) +{ + struct jabber_data *jd = ic->proto_data; + struct xt_node *reply, *query; + xt_status st; + char *s; + + if( !( query = xt_find_node( node->children, "query" ) ) ) + { + imcb_log( ic, "WARNING: Received incomplete IQ packet while authenticating" ); + imc_logout( ic, FALSE ); + return XT_HANDLED; + } + + /* Time to authenticate ourselves! */ + reply = xt_new_node( "query", NULL, NULL ); + xt_add_attr( reply, "xmlns", XMLNS_AUTH ); + xt_add_child( reply, xt_new_node( "username", jd->username, NULL ) ); + xt_add_child( reply, xt_new_node( "resource", set_getstr( &ic->acc->set, "resource" ), NULL ) ); + + if( xt_find_node( query->children, "digest" ) && ( s = xt_find_attr( jd->xt->root, "id" ) ) ) + { + /* We can do digest authentication, it seems, and of + course we prefer that. */ + SHA_CTX sha; + char hash_hex[41]; + unsigned char hash[20]; + int i; + + shaInit( &sha ); + shaUpdate( &sha, (unsigned char*) s, strlen( s ) ); + shaUpdate( &sha, (unsigned char*) ic->acc->pass, strlen( ic->acc->pass ) ); + shaFinal( &sha, hash ); + + for( i = 0; i < 20; i ++ ) + sprintf( hash_hex + i * 2, "%02x", hash[i] ); + + xt_add_child( reply, xt_new_node( "digest", hash_hex, NULL ) ); + } + else if( xt_find_node( query->children, "password" ) ) + { + /* We'll have to stick with plaintext. Let's hope we're using SSL/TLS... */ + xt_add_child( reply, xt_new_node( "password", ic->acc->pass, NULL ) ); + } + else + { + xt_free_node( reply ); + + imcb_error( ic, "Can't find suitable authentication method" ); + imc_logout( ic, FALSE ); + return XT_ABORT; + } + + reply = jabber_make_packet( "iq", "set", NULL, reply ); + jabber_cache_add( ic, reply, jabber_finish_iq_auth ); + st = jabber_write_packet( ic, reply ); + + return st ? XT_HANDLED : XT_ABORT; +} + +static xt_status jabber_finish_iq_auth( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ) +{ + struct jabber_data *jd = ic->proto_data; + char *type; + + if( !( type = xt_find_attr( node, "type" ) ) ) + { + imcb_log( ic, "WARNING: Received incomplete IQ packet while authenticating" ); + imc_logout( ic, FALSE ); + return XT_HANDLED; + } + + if( strcmp( type, "error" ) == 0 ) + { + imcb_error( ic, "Authentication failure" ); + imc_logout( ic, FALSE ); + return XT_ABORT; + } + else if( strcmp( type, "result" ) == 0 ) + { + /* This happens when we just successfully authenticated the + old (non-SASL) way. */ + jd->flags |= JFLAG_AUTHENTICATED; + if( !jabber_get_roster( ic ) ) + return XT_ABORT; + } + + return XT_HANDLED; +} + +xt_status jabber_pkt_bind_sess( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ) +{ + struct jabber_data *jd = ic->proto_data; + struct xt_node *c; + char *s; + + if( ( c = xt_find_node( node->children, "bind" ) ) ) + { + c = xt_find_node( c->children, "jid" ); + if( c && c->text_len && ( s = strchr( c->text, '/' ) ) && + strcmp( s + 1, set_getstr( &ic->acc->set, "resource" ) ) != 0 ) + imcb_log( ic, "Server changed session resource string to `%s'", s + 1 ); + + jd->flags &= ~JFLAG_WAIT_BIND; + } + else + { + jd->flags &= ~JFLAG_WAIT_SESSION; + } + + if( ( jd->flags & ( JFLAG_WAIT_BIND | JFLAG_WAIT_SESSION ) ) == 0 ) + { + if( !jabber_get_roster( ic ) ) + return XT_ABORT; + } + + return XT_HANDLED; +} + +int jabber_get_roster( struct im_connection *ic ) +{ + struct xt_node *node; + int st; + + imcb_log( ic, "Authenticated, requesting buddy list" ); + + node = xt_new_node( "query", NULL, NULL ); + xt_add_attr( node, "xmlns", XMLNS_ROSTER ); + node = jabber_make_packet( "iq", "get", NULL, node ); + + jabber_cache_add( ic, node, jabber_parse_roster ); + st = jabber_write_packet( ic, node ); + + return st; +} + +static xt_status jabber_parse_roster( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ) +{ + struct xt_node *query, *c; + int initial = ( orig != NULL ); + + if( !( query = xt_find_node( node->children, "query" ) ) ) + { + imcb_log( ic, "WARNING: Received NULL roster packet" ); + return XT_HANDLED; + } + + c = query->children; + while( ( c = xt_find_node( c, "item" ) ) ) + { + struct xt_node *group = xt_find_node( node->children, "group" ); + char *jid = xt_find_attr( c, "jid" ); + char *name = xt_find_attr( c, "name" ); + char *sub = xt_find_attr( c, "subscription" ); + + if( jid && sub ) + { + if( ( strcmp( sub, "both" ) == 0 || strcmp( sub, "to" ) == 0 ) ) + { + if( initial || imcb_find_buddy( ic, jid ) == NULL ) + imcb_add_buddy( ic, jid, ( group && group->text_len ) ? + group->text : NULL ); + + imcb_rename_buddy( ic, jid, name ); + } + else if( strcmp( sub, "remove" ) == 0 ) + { + /* Don't have any API call for this yet! So let's + just try to handle this as well as we can. */ + jabber_buddy_remove_bare( ic, jid ); + imcb_buddy_status( ic, jid, 0, NULL, NULL ); + /* FIXME! */ + } + } + + c = c->next; + } + + if( initial ) + imcb_connected( ic ); + + return XT_HANDLED; +} + +int jabber_get_vcard( struct im_connection *ic, char *bare_jid ) +{ + struct xt_node *node; + + if( strchr( bare_jid, '/' ) ) + return 1; /* This was an error, but return 0 should only be done if the connection died... */ + + node = xt_new_node( "vCard", NULL, NULL ); + xt_add_attr( node, "xmlns", XMLNS_VCARD ); + node = jabber_make_packet( "iq", "get", bare_jid, node ); + + jabber_cache_add( ic, node, jabber_iq_display_vcard ); + return jabber_write_packet( ic, node ); +} + +static xt_status jabber_iq_display_vcard( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ) +{ + struct xt_node *vc, *c, *sc; /* subchild, ic is already in use ;-) */ + GString *reply; + char *s; + + if( ( s = xt_find_attr( node, "type" ) ) == NULL || + strcmp( s, "result" ) != 0 || + ( vc = xt_find_node( node->children, "vCard" ) ) == NULL ) + { + s = xt_find_attr( orig, "to" ); /* If this returns NULL something's wrong.. */ + imcb_log( ic, "Could not retrieve vCard of %s", s ? s : "(NULL)" ); + return XT_HANDLED; + } + + s = xt_find_attr( orig, "to" ); + reply = g_string_new( "vCard information for " ); + reply = g_string_append( reply, s ? s : "(NULL)" ); + reply = g_string_append( reply, ":\n" ); + + /* I hate this format, I really do... */ + + if( ( c = xt_find_node( vc->children, "FN" ) ) && c->text_len ) + g_string_append_printf( reply, "Name: %s\n", c->text ); + + if( ( c = xt_find_node( vc->children, "N" ) ) && c->children ) + { + reply = g_string_append( reply, "Full name:" ); + + if( ( sc = xt_find_node( c->children, "PREFIX" ) ) && sc->text_len ) + g_string_append_printf( reply, " %s", sc->text ); + if( ( sc = xt_find_node( c->children, "GIVEN" ) ) && sc->text_len ) + g_string_append_printf( reply, " %s", sc->text ); + if( ( sc = xt_find_node( c->children, "MIDDLE" ) ) && sc->text_len ) + g_string_append_printf( reply, " %s", sc->text ); + if( ( sc = xt_find_node( c->children, "FAMILY" ) ) && sc->text_len ) + g_string_append_printf( reply, " %s", sc->text ); + if( ( sc = xt_find_node( c->children, "SUFFIX" ) ) && sc->text_len ) + g_string_append_printf( reply, " %s", sc->text ); + + reply = g_string_append_c( reply, '\n' ); + } + + if( ( c = xt_find_node( vc->children, "NICKNAME" ) ) && c->text_len ) + g_string_append_printf( reply, "Nickname: %s\n", c->text ); + + if( ( c = xt_find_node( vc->children, "BDAY" ) ) && c->text_len ) + g_string_append_printf( reply, "Date of birth: %s\n", c->text ); + + /* Slightly alternative use of for... ;-) */ + for( c = vc->children; ( c = xt_find_node( c, "EMAIL" ) ); c = c->next ) + { + if( ( sc = xt_find_node( c->children, "USERID" ) ) == NULL || sc->text_len == 0 ) + continue; + + if( xt_find_node( c->children, "HOME" ) ) + s = "Home"; + else if( xt_find_node( c->children, "WORK" ) ) + s = "Work"; + else + s = "Misc."; + + g_string_append_printf( reply, "%s e-mail address: %s\n", s, sc->text ); + } + + if( ( c = xt_find_node( vc->children, "URL" ) ) && c->text_len ) + g_string_append_printf( reply, "Homepage: %s\n", c->text ); + + /* Slightly alternative use of for... ;-) */ + for( c = vc->children; ( c = xt_find_node( c, "ADR" ) ); c = c->next ) + { + if( xt_find_node( c->children, "HOME" ) ) + s = "Home"; + else if( xt_find_node( c->children, "WORK" ) ) + s = "Work"; + else + s = "Misc."; + + g_string_append_printf( reply, "%s address: ", s ); + + if( ( sc = xt_find_node( c->children, "STREET" ) ) && sc->text_len ) + g_string_append_printf( reply, "%s ", sc->text ); + if( ( sc = xt_find_node( c->children, "EXTADR" ) ) && sc->text_len ) + g_string_append_printf( reply, "%s, ", sc->text ); + if( ( sc = xt_find_node( c->children, "PCODE" ) ) && sc->text_len ) + g_string_append_printf( reply, "%s, ", sc->text ); + if( ( sc = xt_find_node( c->children, "LOCALITY" ) ) && sc->text_len ) + g_string_append_printf( reply, "%s, ", sc->text ); + if( ( sc = xt_find_node( c->children, "REGION" ) ) && sc->text_len ) + g_string_append_printf( reply, "%s, ", sc->text ); + if( ( sc = xt_find_node( c->children, "CTRY" ) ) && sc->text_len ) + g_string_append_printf( reply, "%s", sc->text ); + + if( reply->str[reply->len-2] == ',' ) + reply = g_string_truncate( reply, reply->len-2 ); + + reply = g_string_append_c( reply, '\n' ); + } + + for( c = vc->children; ( c = xt_find_node( c, "TEL" ) ); c = c->next ) + { + if( ( sc = xt_find_node( c->children, "NUMBER" ) ) == NULL || sc->text_len == 0 ) + continue; + + if( xt_find_node( c->children, "HOME" ) ) + s = "Home"; + else if( xt_find_node( c->children, "WORK" ) ) + s = "Work"; + else + s = "Misc."; + + g_string_append_printf( reply, "%s phone number: %s\n", s, sc->text ); + } + + if( ( c = xt_find_node( vc->children, "DESC" ) ) && c->text_len ) + g_string_append_printf( reply, "Other information:\n%s", c->text ); + + /* *sigh* */ + + imcb_log( ic, "%s", reply->str ); + g_string_free( reply, TRUE ); + + return XT_HANDLED; +} + +int jabber_add_to_roster( struct im_connection *ic, char *handle, char *name ) +{ + struct xt_node *node; + int st; + + /* Build the item entry */ + node = xt_new_node( "item", NULL, NULL ); + xt_add_attr( node, "jid", handle ); + if( name ) + xt_add_attr( node, "name", name ); + + /* And pack it into a roster-add packet */ + node = xt_new_node( "query", NULL, node ); + xt_add_attr( node, "xmlns", XMLNS_ROSTER ); + node = jabber_make_packet( "iq", "set", NULL, node ); + + st = jabber_write_packet( ic, node ); + + xt_free_node( node ); + return st; +} + +int jabber_remove_from_roster( struct im_connection *ic, char *handle ) +{ + struct xt_node *node; + int st; + + /* Build the item entry */ + node = xt_new_node( "item", NULL, NULL ); + xt_add_attr( node, "jid", handle ); + xt_add_attr( node, "subscription", "remove" ); + + /* And pack it into a roster-add packet */ + node = xt_new_node( "query", NULL, node ); + xt_add_attr( node, "xmlns", XMLNS_ROSTER ); + node = jabber_make_packet( "iq", "set", NULL, node ); + + st = jabber_write_packet( ic, node ); + + xt_free_node( node ); + return st; +} diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index e765a475..edad5dbd 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -1,2392 +1,405 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * gaim - * - * Some code copyright (C) 1998-1999, Mark Spencer <markster@marko.net> - * libfaim code copyright 1998, 1999 Adam Fritzler <afritz@auk.cx> - * - * 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 - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef _WIN32 -#include <sys/utsname.h> -#endif -#include <errno.h> +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Jabber module - Main file * +* * +* Copyright 2006 Wilmer van der Gaast <wilmer@gaast.net> * +* * +* 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 along * +* with this program; if not, write to the Free Software Foundation, Inc., * +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * +* * +\***************************************************************************/ + +#include <glib.h> #include <string.h> -#include <stdlib.h> +#include <unistd.h> +#include <ctype.h> #include <stdio.h> -#include <time.h> -#include <sys/stat.h> -#include "jabber.h" -#include "nogaim.h" -#include "bitlbee.h" -#include "proxy.h" -#include "ssl_client.h" - -/* The priv member of gjconn's is a gaim_connection for now. */ -#define GJ_GC(x) ((struct gaim_connection *)(x)->priv) - -#define IQID_AUTH "__AUTH__" - -#define IQ_NONE -1 -#define IQ_AUTH 0 -#define IQ_ROSTER 1 - -#define UC_AWAY (0x02 | UC_UNAVAILABLE) -#define UC_CHAT 0x04 -#define UC_XA (0x08 | UC_UNAVAILABLE) -#define UC_DND (0x10 | UC_UNAVAILABLE) - -#define DEFAULT_SERVER "jabber.org" -#define DEFAULT_GROUPCHAT "conference.jabber.org" -#define DEFAULT_PORT 5222 -#define DEFAULT_PORT_SSL 5223 -#define JABBER_PORT_MIN 5220 -#define JABBER_PORT_MAX 5229 - -#define JABBER_GROUP "Friends" - -/* i18n disabled - Bitlbee */ -#define N_(String) String - -/* - * Note: "was_connected" may seem redundant, but it was needed and I - * didn't want to touch the Jabber state stuff not specific to Gaim. - */ -typedef struct gjconn_struct { - /* Core structure */ - pool p; /* Memory allocation pool */ - int state; /* Connection state flag */ - int was_connected; /* We were once connected */ - int fd; /* Connection file descriptor */ - void *ssl; /* SSL connection */ - jid user; /* User info */ - char *pass; /* User passwd */ - - /* Stream stuff */ - int id; /* id counter for jab_getid() function */ - char idbuf[9]; /* temporary storage for jab_getid() */ - char *sid; /* stream id from server, for digest auth */ - XML_Parser parser; /* Parser instance */ - xmlnode current; /* Current node in parsing instance.. */ - - /* Event callback ptrs */ - void (*on_state)(struct gjconn_struct *gjc, int state); - void (*on_packet)(struct gjconn_struct *gjc, jpacket p); - - GHashTable *queries; /* query tracker */ - - void *priv; -} *gjconn, gjconn_struct; - -typedef void (*gjconn_state_h)(gjconn gjc, int state); -typedef void (*gjconn_packet_h)(gjconn gjc, jpacket p); - -static gjconn gjab_new(char *user, char *pass, void *priv); -static void gjab_delete(gjconn gjc); -static void gjab_state_handler(gjconn gjc, gjconn_state_h h); -static void gjab_packet_handler(gjconn gjc, gjconn_packet_h h); -static void gjab_start(gjconn gjc); -static void gjab_stop(gjconn gjc); -/* -static int gjab_getfd(gjconn gjc); -static jid gjab_getjid(gjconn gjc); -static char *gjab_getsid(gjconn gjc); -*/ -static char *gjab_getid(gjconn gjc); -static void gjab_send(gjconn gjc, xmlnode x); -static void gjab_send_raw(gjconn gjc, const char *str); -static void gjab_recv(gjconn gjc); -static void gjab_auth(gjconn gjc); - -/* - * It is *this* to which we point the gaim_connection proto_data - */ -struct jabber_data { - gjconn gjc; - gboolean did_import; - GSList *chats; - GHashTable *hash; - time_t idle; - gboolean die; -}; - -/* - * Jabber "chat group" info. Pointers to these go in jabber_data - * pending and existing chats lists. - */ -struct jabber_chat { - jid Jid; - struct gaim_connection *gc; - struct conversation *b; - int id; - int state; -}; - -/* - * Jabber chat states... - * - * Note: due to a bug in one version of the Jabber server, subscriptions - * to chat groups aren't (always?) properly removed at the server. The - * result is clients receive Jabber "presence" notifications for JIDs - * they no longer care about. The problem with such vestigial notifies is - * that we really have no way of telling if it's vestigial or if it's a - * valid "buddy" presence notification. So we keep jabber_chat structs - * around after leaving a chat group and simply mark them "closed." That - * way we can test for such errant presence notifications. I.e.: if we - * get a presence notfication from a JID that matches a chat group JID, - * we disregard it. - */ -#define JCS_PENDING 1 /* pending */ -#define JCS_ACTIVE 2 /* active */ -#define JCS_CLOSED 3 /* closed */ - - -#define STATE_EVT(arg) if(gjc->on_state) { (gjc->on_state)(gjc, (arg) ); } - -static void jabber_remove_buddy(struct gaim_connection *gc, char *name, char *group); -static void jabber_handlevcard(gjconn gjc, xmlnode querynode, char *from); - -static char *create_valid_jid(const char *given, char *server, char *resource) -{ - char *valid; - - if (!strchr(given, '@')) - valid = g_strdup_printf("%s@%s/%s", given, server, resource); - else if (!strchr(strchr(given, '@'), '/')) - valid = g_strdup_printf("%s/%s", given, resource); - else - valid = g_strdup(given); - - return valid; -} - -static gjconn gjab_new(char *user, char *pass, void *priv) -{ - pool p; - gjconn gjc; - - if (!user) - return (NULL); - - p = pool_new(); - if (!p) - return (NULL); - gjc = pmalloc_x(p, sizeof(gjconn_struct), 0); - if (!gjc) { - pool_free(p); /* no need for this anymore! */ - return (NULL); - } - gjc->p = p; - - if((gjc->user = jid_new(p, user)) == NULL) { - pool_free(p); /* no need for this anymore! */ - return (NULL); - } - gjc->pass = pstrdup(p, pass); - - gjc->state = JCONN_STATE_OFF; - gjc->was_connected = 0; - gjc->id = 1; - gjc->fd = -1; - - gjc->priv = priv; - - return gjc; -} - -static void gjab_delete(gjconn gjc) -{ - if (!gjc) - return; - - gjab_stop(gjc); - pool_free(gjc->p); -} - -static void gjab_state_handler(gjconn gjc, gjconn_state_h h) -{ - if (!gjc) - return; - - gjc->on_state = h; -} - -static void gjab_packet_handler(gjconn gjc, gjconn_packet_h h) -{ - if (!gjc) - return; - - gjc->on_packet = h; -} - -static void gjab_stop(gjconn gjc) -{ - if (!gjc || gjc->state == JCONN_STATE_OFF) - return; - - gjab_send_raw(gjc, "</stream:stream>"); - gjc->state = JCONN_STATE_OFF; - gjc->was_connected = 0; - if (gjc->ssl) { - ssl_disconnect(gjc->ssl); - gjc->ssl = NULL; - } else { - closesocket(gjc->fd); - } - gjc->fd = -1; - XML_ParserFree(gjc->parser); - gjc->parser = NULL; -} - -/* -static int gjab_getfd(gjconn gjc) -{ - if (gjc) - return gjc->fd; - else - return -1; -} - -static jid gjab_getjid(gjconn gjc) -{ - if (gjc) - return (gjc->user); - else - return NULL; -} - -static char *gjab_getsid(gjconn gjc) -{ - if (gjc) - return (gjc->sid); - else - return NULL; -} -*/ - -static char *gjab_getid(gjconn gjc) -{ - g_snprintf(gjc->idbuf, 8, "%d", gjc->id++); - return &gjc->idbuf[0]; -} - -static void gjab_send(gjconn gjc, xmlnode x) -{ - if (gjc && gjc->state != JCONN_STATE_OFF) { - char *buf = xmlnode2str(x); - if (!buf) - return; - else if (gjc->ssl) - ssl_write(gjc->ssl, buf, strlen(buf)); - else - write(gjc->fd, buf, strlen(buf)); - } -} -static void gjab_send_raw(gjconn gjc, const char *str) -{ - if (gjc && gjc->state != JCONN_STATE_OFF) { - int len; - - /* - * JFIXME: No error detection?!?! - */ - if (gjc->ssl) - len = ssl_write(gjc->ssl, str, strlen(str)); - else - len = write(gjc->fd, str, strlen(str)); - - if(len < 0) { - /* Do NOT write to stdout/stderr directly, IRC clients - might get confused, and we don't want that... - fprintf(stderr, "DBG: Problem sending. Error: %d\n", errno); - fflush(stderr); */ - } - } -} - -static void gjab_reqroster(gjconn gjc) -{ - xmlnode x; - - x = jutil_iqnew(JPACKET__GET, NS_ROSTER); - xmlnode_put_attrib(x, "id", gjab_getid(gjc)); - - gjab_send(gjc, x); - xmlnode_free(x); -} - -static void gjab_reqauth(gjconn gjc) -{ - xmlnode x, y, z; - char *user; - - if (!gjc) - return; - - x = jutil_iqnew(JPACKET__GET, NS_AUTH); - xmlnode_put_attrib(x, "id", IQID_AUTH); - y = xmlnode_get_tag(x, "query"); - - user = gjc->user->user; - - if (user) { - z = xmlnode_insert_tag(y, "username"); - xmlnode_insert_cdata(z, user, -1); - } - - gjab_send(gjc, x); - xmlnode_free(x); -} - -static void gjab_auth(gjconn gjc) -{ - xmlnode x, y, z; - char *hash, *user; - - if (!gjc) - return; - - x = jutil_iqnew(JPACKET__SET, NS_AUTH); - xmlnode_put_attrib(x, "id", IQID_AUTH); - y = xmlnode_get_tag(x, "query"); - - user = gjc->user->user; - - if (user) { - z = xmlnode_insert_tag(y, "username"); - xmlnode_insert_cdata(z, user, -1); - } - - z = xmlnode_insert_tag(y, "resource"); - xmlnode_insert_cdata(z, gjc->user->resource, -1); - - if (gjc->sid) { - z = xmlnode_insert_tag(y, "digest"); - hash = pmalloc(x->p, strlen(gjc->sid) + strlen(gjc->pass) + 1); - strcpy(hash, gjc->sid); - strcat(hash, gjc->pass); - hash = shahash(hash); - xmlnode_insert_cdata(z, hash, 40); - } else { - z = xmlnode_insert_tag(y, "password"); - xmlnode_insert_cdata(z, gjc->pass, -1); - } - - gjab_send(gjc, x); - xmlnode_free(x); - - return; -} +#include "ssl_client.h" +#include "xmltree.h" +#include "bitlbee.h" +#include "jabber.h" -static void gjab_recv(gjconn gjc) +static void jabber_init( account_t *acc ) { - static char buf[4096]; - int len; - - if (!gjc || gjc->state == JCONN_STATE_OFF) - return; + set_t *s; - if (gjc->ssl) - len = ssl_read(gjc->ssl, buf, sizeof(buf) - 1); - else - len = read(gjc->fd, buf, sizeof(buf) - 1); + s = set_add( &acc->set, "port", JABBER_PORT_DEFAULT, set_eval_int, acc ); + s->flags |= ACC_SET_OFFLINE_ONLY; - if (len > 0) { - struct jabber_data *jd = GJ_GC(gjc)->proto_data; - buf[len] = '\0'; - XML_Parse(gjc->parser, buf, len, 0); - if (jd->die) - signoff(GJ_GC(gjc)); - } else if (len == 0 || (len < 0 && (!sockerr_again() || gjc->ssl))) { - STATE_EVT(JCONN_STATE_OFF) - } -} - -static void startElement(void *userdata, const char *name, const char **attribs) -{ - xmlnode x; - gjconn gjc = (gjconn) userdata; - - if (gjc->current) { - /* Append the node to the current one */ - x = xmlnode_insert_tag(gjc->current, name); - xmlnode_put_expat_attribs(x, attribs); - - gjc->current = x; - } else { - x = xmlnode_new_tag(name); - xmlnode_put_expat_attribs(x, attribs); - if (strcmp(name, "stream:stream") == 0) { - /* special case: name == stream:stream */ - /* id attrib of stream is stored for digest auth */ - gjc->sid = g_strdup(xmlnode_get_attrib(x, "id")); - /* STATE_EVT(JCONN_STATE_AUTH) */ - xmlnode_free(x); - } else { - gjc->current = x; - } - } -} - -static void endElement(void *userdata, const char *name) -{ - gjconn gjc = (gjconn) userdata; - xmlnode x; - jpacket p; - - if (gjc->current == NULL) { - /* we got </stream:stream> */ - STATE_EVT(JCONN_STATE_OFF) - return; - } - - x = xmlnode_get_parent(gjc->current); - - if (!x) { - /* it is time to fire the event */ - p = jpacket_new(gjc->current); - - if (gjc->on_packet) - (gjc->on_packet) (gjc, p); - else - xmlnode_free(gjc->current); - } - - gjc->current = x; -} - -static gboolean jabber_callback(gpointer data, gint source, b_input_condition condition) -{ - struct gaim_connection *gc = (struct gaim_connection *)data; - struct jabber_data *jd = (struct jabber_data *)gc->proto_data; - - gjab_recv(jd->gjc); + s = set_add( &acc->set, "priority", "0", set_eval_priority, acc ); - return TRUE; -} - -static void charData(void *userdata, const char *s, int slen) -{ - gjconn gjc = (gjconn) userdata; - - if (gjc->current) - xmlnode_insert_cdata(gjc->current, s, slen); -} - -static gboolean gjab_connected(gpointer data, gint source, b_input_condition cond) -{ - xmlnode x; - char *t, *t2; - struct gaim_connection *gc = data; - struct jabber_data *jd; - gjconn gjc; - - if (!g_slist_find(get_connections(), gc)) { - closesocket(source); - return FALSE; - } - - jd = gc->proto_data; - gjc = jd->gjc; - - if (gjc->fd != source) - gjc->fd = source; - - if (source == -1) { - STATE_EVT(JCONN_STATE_OFF) - return FALSE; - } - - gjc->state = JCONN_STATE_CONNECTED; - STATE_EVT(JCONN_STATE_CONNECTED) - - /* start stream */ - x = jutil_header(NS_CLIENT, gjc->user->server); - t = xmlnode2str(x); - /* this is ugly, we can create the string here instead of jutil_header */ - /* what do you think about it? -madcat */ - t2 = strstr(t, "/>"); - *t2++ = '>'; - *t2 = '\0'; - gjab_send_raw(gjc, "<?xml version='1.0'?>"); - gjab_send_raw(gjc, t); - xmlnode_free(x); - - gjc->state = JCONN_STATE_ON; - STATE_EVT(JCONN_STATE_ON); - - gc = GJ_GC(gjc); - gc->inpa = b_input_add(gjc->fd, GAIM_INPUT_READ, jabber_callback, gc); - - return FALSE; -} - -static gboolean gjab_connected_ssl(gpointer data, void *source, b_input_condition cond) -{ - struct gaim_connection *gc = data; - struct jabber_data *jd; - gjconn gjc; + s = set_add( &acc->set, "resource", "BitlBee", NULL, acc ); + s->flags |= ACC_SET_OFFLINE_ONLY; - jd = gc->proto_data; - gjc = jd->gjc; + s = set_add( &acc->set, "resource_select", "priority", NULL, acc ); - if (source == NULL) { - STATE_EVT(JCONN_STATE_OFF) - return FALSE; - } + s = set_add( &acc->set, "server", NULL, set_eval_account, acc ); + s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY; - if (!g_slist_find(get_connections(), gc)) { - ssl_disconnect(source); - return FALSE; - } + s = set_add( &acc->set, "ssl", "false", set_eval_bool, acc ); + s->flags |= ACC_SET_OFFLINE_ONLY; - return gjab_connected(data, gjc->fd, cond); + s = set_add( &acc->set, "tls", "try", set_eval_tls, acc ); + s->flags |= ACC_SET_OFFLINE_ONLY; } -static void gjab_start(gjconn gjc) +static void jabber_login( account_t *acc ) { - account_t *acc; - int port = -1, ssl = 0; - char *server = NULL; - - if (!gjc || gjc->state != JCONN_STATE_OFF) - return; - - acc = GJ_GC(gjc)->acc; - server = acc->server; - port = set_getint(&acc->set, "port"); - ssl = set_getbool(&acc->set, "ssl"); + struct im_connection *ic = imcb_new( acc ); + struct jabber_data *jd = g_new0( struct jabber_data, 1 ); + struct ns_srv_reply *srv = NULL; + char *connect_to, *s; - if (port < JABBER_PORT_MIN || port > JABBER_PORT_MAX) { - serv_got_crap(GJ_GC(gjc), "For security reasons, the Jabber port number must be in the %d-%d range.", JABBER_PORT_MIN, JABBER_PORT_MAX); - STATE_EVT(JCONN_STATE_OFF) - return; - } + jd->ic = ic; + ic->proto_data = jd; - if (server == NULL) - server = g_strdup(gjc->user->server); - - gjc->parser = XML_ParserCreate(NULL); - XML_SetUserData(gjc->parser, (void *)gjc); - XML_SetElementHandler(gjc->parser, startElement, endElement); - XML_SetCharacterDataHandler(gjc->parser, charData); + jd->username = g_strdup( acc->user ); + jd->server = strchr( jd->username, '@' ); - if (ssl) { - if ((gjc->ssl = ssl_connect(server, port, gjab_connected_ssl, GJ_GC(gjc)))) - gjc->fd = ssl_getfd(gjc->ssl); - else - gjc->fd = -1; - } else { - gjc->fd = proxy_connect(server, port, gjab_connected, GJ_GC(gjc)); - } - - if (!acc->gc || (gjc->fd < 0)) { - STATE_EVT(JCONN_STATE_OFF) + if( jd->server == NULL ) + { + imcb_error( ic, "Incomplete account name (format it like <username@jabberserver.name>)" ); + imc_logout( ic, FALSE ); return; } -} - -/* - * Find existing/active Jabber chat - */ -static struct jabber_chat *find_existing_chat(struct gaim_connection *gc, jid chat) -{ - GSList *jcs = ((struct jabber_data *)gc->proto_data)->chats; - struct jabber_chat *jc = NULL; - - while (jcs) { - jc = jcs->data; - if (jc->state == JCS_ACTIVE && !jid_cmpx(chat, jc->Jid, JID_USER | JID_SERVER)) - break; - jc = NULL; - jcs = jcs->next; - } - - return jc; -} - -/* - * Find pending chat - */ -static struct jabber_chat *find_pending_chat(struct gaim_connection *gc, jid chat) -{ - GSList *jcs = ((struct jabber_data *)gc->proto_data)->chats; - struct jabber_chat *jc = NULL; - - while (jcs) { - jc = jcs->data; - if (jc->state == JCS_PENDING && !jid_cmpx(chat, jc->Jid, JID_USER | JID_SERVER)) - break; - jc = NULL; - jcs = jcs->next; - } - - return jc; -} - -static gboolean find_chat_buddy(struct conversation *b, char *name) -{ - GList *m = b->in_room; - - while (m) { - if (!strcmp(m->data, name)) - return TRUE; - m = m->next; - } - - return FALSE; -} - -/* - * Remove a buddy from the (gaim) buddylist (if he's on it) - */ -static void jabber_remove_gaim_buddy(struct gaim_connection *gc, char *buddyname) -{ - struct buddy *b; - - if ((b = find_buddy(gc, buddyname)) != NULL) { - /* struct group *group; - - group = find_group_by_buddy(gc, buddyname); - remove_buddy(gc, group, b); */ - jabber_remove_buddy(gc, b->name, JABBER_GROUP); - } -} - -/* - * keep track of away msg same as yahoo plugin - */ -static void jabber_track_away(gjconn gjc, jpacket p, char *name, char *type) -{ - struct jabber_data *jd = GJ_GC(gjc)->proto_data; - gpointer val = g_hash_table_lookup(jd->hash, name); - char *show; - char *vshow = NULL; - char *status = NULL; - char *msg = NULL; - - if (type && (g_strcasecmp(type, "unavailable") == 0)) { - vshow = _("Unavailable"); - } else { - if((show = xmlnode_get_tag_data(p->x, "show")) != NULL) { - if (!g_strcasecmp(show, "away")) { - vshow = _("Away"); - } else if (!g_strcasecmp(show, "chat")) { - vshow = _("Online"); - } else if (!g_strcasecmp(show, "xa")) { - vshow = _("Extended Away"); - } else if (!g_strcasecmp(show, "dnd")) { - vshow = _("Do Not Disturb"); - } - } - } - - status = xmlnode_get_tag_data(p->x, "status"); - - if(vshow != NULL || status != NULL ) { - /* kinda hokey, but it works :-) */ - msg = g_strdup_printf("%s%s%s", - (vshow == NULL? "" : vshow), - (vshow == NULL || status == NULL? "" : ": "), - (status == NULL? "" : status)); - } else { - msg = g_strdup(_("Online")); - } - - if (val) { - g_free(val); - g_hash_table_insert(jd->hash, name, msg); - } else { - g_hash_table_insert(jd->hash, g_strdup(name), msg); - } -} - -static time_t iso8601_to_time(char *timestamp) -{ - struct tm t; - time_t retval = 0; - - if(sscanf(timestamp,"%04d%02d%02dT%02d:%02d:%02d", - &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec)) + + /* So don't think of free()ing jd->server.. :-) */ + *jd->server = 0; + jd->server ++; + + if( ( s = strchr( jd->server, '/' ) ) ) { - t.tm_year -= 1900; - t.tm_mon -= 1; - t.tm_isdst = 0; - retval = mktime(&t); -# ifdef HAVE_TM_GMTOFF - retval += t.tm_gmtoff; -# else -# ifdef HAVE_TIMEZONE - tzset(); /* making sure */ - retval -= timezone; -# endif -# endif + *s = 0; + set_setstr( &acc->set, "resource", s + 1 ); + + /* Also remove the /resource from the original variable so we + won't have to do this again every time. */ + s = strchr( acc->user, '/' ); + *s = 0; } - - return retval; -} - -static void jabber_handlemessage(gjconn gjc, jpacket p) -{ - xmlnode y, xmlns, z; - time_t time_sent = time(NULL); - - char *from = NULL, *msg = NULL, *type = NULL; - char m[BUF_LONG * 2]; - - type = xmlnode_get_attrib(p->x, "type"); - - z = xmlnode_get_firstchild(p->x); - - while(z) + + /* This code isn't really pretty. Backwards compatibility never is... */ + s = acc->server; + while( s ) { - if(NSCHECK(z,NS_DELAY)) - { - char *timestamp = xmlnode_get_attrib(z,"stamp"); - time_sent = iso8601_to_time(timestamp); - } - z = xmlnode_get_nextsibling(z); - } - - if (!type || !g_strcasecmp(type, "normal") || !g_strcasecmp(type, "chat")) { - - /* XXX namespaces could be handled better. (mid) */ - if ((xmlns = xmlnode_get_tag(p->x, "x"))) - type = xmlnode_get_attrib(xmlns, "xmlns"); - - from = jid_full(p->from); - /* - if ((y = xmlnode_get_tag(p->x, "html"))) { - msg = xmlnode_get_data(y); - } else - */ - if ((y = xmlnode_get_tag(p->x, "body"))) { - msg = xmlnode_get_data(y); - } - - - if (!from) - return; - - if (type && !g_strcasecmp(type, "jabber:x:conference")) { - /* do nothing */ - } else if (msg) { /* whisper */ - struct jabber_chat *jc; - g_snprintf(m, sizeof(m), "%s", msg); - if (((jc = find_existing_chat(GJ_GC(gjc), p->from)) != NULL) && jc->b) - serv_got_chat_in(GJ_GC(gjc), jc->b->id, p->from->resource, 1, m, time_sent); - else { - int flags = 0; - - if(p->from->user) { - from = g_strdup_printf("%s@%s", p->from->user, p->from->server); - } else { - /* server message? */ - from = g_strdup(p->from->server); - } - serv_got_im(GJ_GC(gjc), from, m, flags, time_sent, -1); - g_free(from); - } - } - - } else if (!g_strcasecmp(type, "error")) { - if ((y = xmlnode_get_tag(p->x, "error"))) { - type = xmlnode_get_attrib(y, "code"); - msg = xmlnode_get_data(y); - } - - if (msg) { - from = g_strdup_printf("Error %s", type ? type : ""); - do_error_dialog(GJ_GC(gjc), msg, from); - g_free(from); - } - } else if (!g_strcasecmp(type, "headline")) { - char *subject, *body, *url; - - y = xmlnode_get_tag( p->x, "body" ); - body = y ? g_strdup( xmlnode_get_data( y ) ) : NULL; - - y = xmlnode_get_tag( p->x, "subject" ); - subject = y ? g_strdup( xmlnode_get_data( y ) ) : NULL; + static int had_port = 0; - url = NULL; - z = xmlnode_get_firstchild(p->x); - while( z ) + if( strncmp( s, "ssl", 3 ) == 0 ) { - char *xtype = xmlnode_get_attrib( z, "xmlns" ); + set_setstr( &acc->set, "ssl", "true" ); - if( xtype && g_strcasecmp( xtype, "jabber:x:oob" ) == 0 && - ( y = xmlnode_get_tag( z, "url" ) ) ) - { - url = g_strdup( xmlnode_get_data( y ) ); - break; - } + /* Flush this part so that (if this was the first + part of the server string) acc->server gets + flushed. We don't want to have to do this another + time. :-) */ + *s = 0; + s ++; - z = xmlnode_get_nextsibling( z ); + /* Only set this if the user didn't specify a custom + port number already... */ + if( !had_port ) + set_setint( &acc->set, "port", 5223 ); } - - g_snprintf( m, BUF_LONG, "Subject: %s\nURL: %s\nMessage:\n%s", subject ? subject : "(none)", - url ? url : "(none)", body ? body : "(none)" ); - - if( p->from->user ) - from = g_strdup_printf( "%s@%s", p->from->user, p->from->server ); - else - from = g_strdup( p->from->server ); - - serv_got_im( GJ_GC(gjc), from, m, 0, time_sent, -1 ); - - g_free( from ); - g_free( subject ); - g_free( body ); - g_free( url ); - } -} - -static void jabber_handlepresence(gjconn gjc, jpacket p) -{ - char *to, *from, *type; - struct buddy *b = NULL; - jid who; - char *buddy; - xmlnode y; - char *show; - int state = 0; - GSList *resources; - char *res; - struct conversation *cnv = NULL; - struct jabber_chat *jc = NULL; - - to = xmlnode_get_attrib(p->x, "to"); - from = xmlnode_get_attrib(p->x, "from"); - type = xmlnode_get_attrib(p->x, "type"); - - if (type && g_strcasecmp(type, "error") == 0) { - return; - } - else if ((y = xmlnode_get_tag(p->x, "show"))) { - show = xmlnode_get_data(y); - if (!show) { - state = 0; - } else if (!g_strcasecmp(show, "away")) { - state = UC_AWAY; - } else if (!g_strcasecmp(show, "chat")) { - state = UC_CHAT; - } else if (!g_strcasecmp(show, "xa")) { - state = UC_XA; - } else if (!g_strcasecmp(show, "dnd")) { - state = UC_DND; - } - } else { - state = 0; - } - - who = jid_new(gjc->p, from); - if (who->user == NULL) { - /* FIXME: transport */ - return; - } - - buddy = g_strdup_printf("%s@%s", who->user, who->server); - - /* um. we're going to check if it's a chat. if it isn't, and there are pending - * chats, create the chat. if there aren't pending chats and we don't have the - * buddy on our list, simply bail out. */ - if ((cnv = NULL) == NULL) { - static int i = 0x70; - if ((jc = find_pending_chat(GJ_GC(gjc), who)) != NULL) { - jc->b = cnv = serv_got_joined_chat(GJ_GC(gjc), i++, who->user); - jc->id = jc->b->id; - jc->state = JCS_ACTIVE; - } else if ((b = find_buddy(GJ_GC(gjc), buddy)) == NULL) { - g_free(buddy); - return; - } - } - - if (!cnv) { - resources = b->proto_data; - res = who->resource; - if (res) - while (resources) { - if (!strcmp(res, resources->data)) - break; - resources = resources->next; - } - - /* keep track of away msg same as yahoo plugin */ - jabber_track_away(gjc, p, normalize(b->name), type); - - if (type && (g_strcasecmp(type, "unavailable") == 0)) { - if (resources) { - g_free(resources->data); - b->proto_data = g_slist_remove(b->proto_data, resources->data); - } - if (!b->proto_data) { - serv_got_update(GJ_GC(gjc), buddy, 0, 0, 0, 0, 0, 0); - } - } else { - if (!resources) { - b->proto_data = g_slist_append(b->proto_data, g_strdup(res)); - } - - serv_got_update(GJ_GC(gjc), buddy, 1, 0, b->signon, b->idle, state, 0); - - } - } else { - if (who->resource) { - char *buf; - - buf = g_strdup_printf("%s@%s/%s", who->user, who->server, who->resource); - jabber_track_away(gjc, p, buf, type); - g_free(buf); - - if (type && !g_strcasecmp(type, "unavailable")) { - struct jabber_data *jd; - if (!jc && !(jc = find_existing_chat(GJ_GC(gjc), who))) { - g_free(buddy); - return; - } - jd = jc->gc->proto_data; - /* if it's not ourselves...*/ - if (strcmp(who->resource, jc->Jid->resource) && jc->b) { - remove_chat_buddy(jc->b, who->resource, NULL); - g_free(buddy); - return; - } - - jc->state = JCS_CLOSED; - serv_got_chat_left(GJ_GC(gjc), jc->id); - /* - * TBD: put back some day? - jd->chats = g_slist_remove(jd->chats, jc); - g_free(jc); - */ - } else { - if ((!jc && !(jc = find_existing_chat(GJ_GC(gjc), who))) || !jc->b) { - g_free(buddy); - return; - } - if (!find_chat_buddy(jc->b, who->resource)) { - add_chat_buddy(jc->b, who->resource); - } - } - } - } - - g_free(buddy); - - return; -} - -/* - * Used only by Jabber accept/deny add stuff just below - */ -struct jabber_add_permit { - gjconn gjc; - gchar *user; -}; - -/* - * Common part for Jabber accept/deny adds - * - * "type" says whether we'll permit/deny the subscribe request - */ -static void jabber_accept_deny_add(struct jabber_add_permit *jap, const char *type) -{ - xmlnode g = xmlnode_new_tag("presence"); - - xmlnode_put_attrib(g, "to", jap->user); - xmlnode_put_attrib(g, "type", type); - gjab_send(jap->gjc, g); - - xmlnode_free(g); -} - -/* - * Callback from "accept" in do_ask_dialog() invoked by jabber_handles10n() - */ -static void jabber_accept_add(gpointer w, struct jabber_add_permit *jap) -{ - jabber_accept_deny_add(jap, "subscribed"); - /* - * If we don't already have the buddy on *our* buddylist, - * 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), jap->user, NULL); - } - g_free(jap->user); - g_free(jap); -} - -/* - * Callback from "deny/cancel" in do_ask_dialog() invoked by jabber_handles10n() - */ -static void jabber_deny_add(gpointer w, struct jabber_add_permit *jap) -{ - jabber_accept_deny_add(jap, "unsubscribed"); - g_free(jap->user); - g_free(jap); -} - -/* - * Handle subscription requests - */ -static void jabber_handles10n(gjconn gjc, jpacket p) -{ - xmlnode g; - char *Jid = xmlnode_get_attrib(p->x, "from"); - char *type = xmlnode_get_attrib(p->x, "type"); - - g = xmlnode_new_tag("presence"); - xmlnode_put_attrib(g, "to", Jid); - - if (!strcmp(type, "subscribe")) { - /* - * A "subscribe to us" request was received - put up the approval dialog - */ - struct jabber_add_permit *jap = g_new0(struct jabber_add_permit, 1); - gchar *msg = g_strdup_printf(_("The user %s wants to add you to his/her buddy list."), - Jid); - - jap->gjc = gjc; - jap->user = g_strdup(Jid); - do_ask_dialog(GJ_GC(gjc), msg, jap, jabber_accept_add, jabber_deny_add); - - g_free(msg); - xmlnode_free(g); /* Never needed it here anyway */ - return; - - } else if (!strcmp(type, "unsubscribe")) { - /* - * An "unsubscribe to us" was received - simply "approve" it - */ - xmlnode_put_attrib(g, "type", "unsubscribed"); - } else { - /* - * Did we attempt to subscribe to somebody and they do not exist? - */ - if (!strcmp(type, "unsubscribed")) { - xmlnode y; - char *status; - if((y = xmlnode_get_tag(p->x, "status")) && (status = xmlnode_get_data(y)) && - !strcmp(status, "Not Found")) { - char *msg = g_strdup_printf("%s: \"%s\"", _("No such user"), - xmlnode_get_attrib(p->x, "from")); - do_error_dialog(GJ_GC(gjc), msg, _("Jabber Error")); - g_free(msg); - } - } - - xmlnode_free(g); - return; - } - - gjab_send(gjc, g); - xmlnode_free(g); -} - -/* - * Pending subscription to a buddy? - */ -#define BUD_SUB_TO_PEND(sub, ask) ((!g_strcasecmp((sub), "none") || !g_strcasecmp((sub), "from")) && \ - (ask) != NULL && !g_strcasecmp((ask), "subscribe")) - -/* - * Subscribed to a buddy? - */ -#define BUD_SUBD_TO(sub, ask) ((!g_strcasecmp((sub), "to") || !g_strcasecmp((sub), "both")) && \ - ((ask) == NULL || !g_strcasecmp((ask), "subscribe"))) - -/* - * Pending unsubscription to a buddy? - */ -#define BUD_USUB_TO_PEND(sub, ask) ((!g_strcasecmp((sub), "to") || !g_strcasecmp((sub), "both")) && \ - (ask) != NULL && !g_strcasecmp((ask), "unsubscribe")) - -/* - * Unsubscribed to a buddy? - */ -#define BUD_USUBD_TO(sub, ask) ((!g_strcasecmp((sub), "none") || !g_strcasecmp((sub), "from")) && \ - ((ask) == NULL || !g_strcasecmp((ask), "unsubscribe"))) - -/* - * If a buddy is added or removed from the roster on another resource - * jabber_handlebuddy is called - * - * Called with roster item node. - */ -static void jabber_handlebuddy(gjconn gjc, xmlnode x) -{ - xmlnode g; - char *Jid, *name, *sub, *ask; - jid who; - struct buddy *b = NULL; - char *buddyname, *groupname = NULL; - - Jid = xmlnode_get_attrib(x, "jid"); - name = xmlnode_get_attrib(x, "name"); - sub = xmlnode_get_attrib(x, "subscription"); - ask = xmlnode_get_attrib(x, "ask"); - who = jid_new(gjc->p, Jid); - - /* JFIXME: jabber_handleroster() had a "FIXME: transport" at this - * equivilent point. So... - * - * We haven't allocated any memory or done anything interesting to - * this point, so we'll violate Good Coding Structure here by - * simply bailing out. - */ - if (!who || !who->user) { - return; - } - - buddyname = g_strdup_printf("%s@%s", who->user, who->server); - - if((g = xmlnode_get_tag(x, "group")) != NULL) { - groupname = xmlnode_get_data(g); - } - - /* - * Add or remove a buddy? Change buddy's alias or group? - */ - if (BUD_SUB_TO_PEND(sub, ask) || BUD_SUBD_TO(sub, ask)) { - if ((b = find_buddy(GJ_GC(gjc), buddyname)) == NULL) { - add_buddy(GJ_GC(gjc), groupname ? groupname : _("Buddies"), buddyname, - name ? name : buddyname); - } else { - /* struct group *c_grp = find_group_by_buddy(GJ_GC(gjc), buddyname); */ - - /* - * If the buddy's in a new group or his/her alias is changed... - */ - if(groupname) { - int present = b->present; /* save presence state */ - int uc = b->uc; /* and away state (?) */ - int idle = b->idle; - int signon = b->signon; - - /* - * seems rude, but it seems to be the only way... - */ - /* remove_buddy(GJ_GC(gjc), c_grp, b); */ - jabber_remove_buddy(GJ_GC(gjc), b->name, JABBER_GROUP); + else if( isdigit( *s ) ) + { + int i; + + /* The first character is a digit. It could be an + IP address though. Only accept this as a port# + if there are only digits. */ + for( i = 0; isdigit( s[i] ); i ++ ); + + /* If the first non-digit character is a colon or + the end of the string, save the port number + where it should be. */ + if( s[i] == ':' || s[i] == 0 ) + { + sscanf( s, "%d", &i ); + set_setint( &acc->set, "port", i ); - add_buddy(GJ_GC(gjc), groupname, buddyname, - name ? name : buddyname); - if(present) { - serv_got_update(GJ_GC(gjc), buddyname, 1, 0, signon, idle, uc, 0); - } - } else if(name != NULL && strcmp(b->show, name)) { - strncpy(b->show, name, BUDDY_ALIAS_MAXLEN); - b->show[BUDDY_ALIAS_MAXLEN - 1] = '\0'; /* cheap safety feature */ - serv_buddy_rename(GJ_GC(gjc), buddyname, b->show); - } - } - } else if (BUD_USUB_TO_PEND(sub, ask) || BUD_USUBD_TO(sub, ask) || !g_strcasecmp(sub, "remove")) { - jabber_remove_gaim_buddy(GJ_GC(gjc), buddyname); - } - g_free(buddyname); - -} - -static void jabber_handleroster(gjconn gjc, xmlnode querynode) -{ - xmlnode x; - - x = xmlnode_get_firstchild(querynode); - while (x) { - jabber_handlebuddy(gjc, x); - x = xmlnode_get_nextsibling(x); - } - - account_online(GJ_GC(gjc)); -} - -static void jabber_handleauthresp(gjconn gjc, jpacket p) -{ - if (jpacket_subtype(p) == JPACKET__RESULT) { - if (xmlnode_has_children(p->x)) { - xmlnode query = xmlnode_get_tag(p->x, "query"); - set_login_progress(GJ_GC(gjc), 4, _("Authenticating")); - if (!xmlnode_get_tag(query, "digest")) { - g_free(gjc->sid); - gjc->sid = NULL; + /* See above. */ + *s = 0; + s ++; } - gjab_auth(gjc); - } else { - gjab_reqroster(gjc); - ((struct jabber_data *)GJ_GC(gjc)->proto_data)->did_import = TRUE; + had_port = 1; } - } else { - xmlnode xerr; - char *errmsg = NULL; - int errcode = 0; - struct jabber_data *jd = GJ_GC(gjc)->proto_data; - - xerr = xmlnode_get_tag(p->x, "error"); - if (xerr) { - char msg[BUF_LONG]; - errmsg = xmlnode_get_data(xerr); - if (xmlnode_get_attrib(xerr, "code")) { - errcode = atoi(xmlnode_get_attrib(xerr, "code")); - g_snprintf(msg, sizeof(msg), "Error %d: %s", errcode, errmsg ? errmsg : "Unknown error"); - } else - g_snprintf(msg, sizeof(msg), "%s", errmsg); - hide_login_progress(GJ_GC(gjc), msg); - } else { - hide_login_progress(GJ_GC(gjc), _("Unknown login error")); + + s = strchr( s, ':' ); + if( s ) + { + *s = 0; + s ++; } - - jd->die = TRUE; } -} - -static void jabber_handleversion(gjconn gjc, xmlnode iqnode) { - xmlnode querynode, x; - char *id, *from; - char os[1024]; -#ifndef _WIN32 - struct utsname osinfo; - - uname(&osinfo); - g_snprintf(os, sizeof os, "%s %s %s", osinfo.sysname, osinfo.release, osinfo.machine); -#else - g_snprintf(os, sizeof os, "Windows %d %d", _winmajor, _winminor); -#endif - - - id = xmlnode_get_attrib(iqnode, "id"); - from = xmlnode_get_attrib(iqnode, "from"); - - x = jutil_iqnew(JPACKET__RESULT, NS_VERSION); - - xmlnode_put_attrib(x, "to", from); - xmlnode_put_attrib(x, "id", id); - querynode = xmlnode_get_tag(x, "query"); - xmlnode_insert_cdata(xmlnode_insert_tag(querynode, "name"), PACKAGE, -1); - xmlnode_insert_cdata(xmlnode_insert_tag(querynode, "version"), BITLBEE_VERSION, -1); - xmlnode_insert_cdata(xmlnode_insert_tag(querynode, "os"), os, -1); - - gjab_send(gjc, x); - - xmlnode_free(x); -} - -static void jabber_handletime(gjconn gjc, xmlnode iqnode) { - xmlnode querynode, x; - char *id, *from; - time_t now_t; - struct tm *now; - char buf[1024]; - - time(&now_t); - now = localtime(&now_t); - - id = xmlnode_get_attrib(iqnode, "id"); - from = xmlnode_get_attrib(iqnode, "from"); - - x = jutil_iqnew(JPACKET__RESULT, NS_TIME); - - xmlnode_put_attrib(x, "to", from); - xmlnode_put_attrib(x, "id", id); - querynode = xmlnode_get_tag(x, "query"); - - strftime(buf, 1024, "%Y%m%dT%T", now); - xmlnode_insert_cdata(xmlnode_insert_tag(querynode, "utc"), buf, -1); - strftime(buf, 1024, "%Z", now); - xmlnode_insert_cdata(xmlnode_insert_tag(querynode, "tz"), buf, -1); - strftime(buf, 1024, "%d %b %Y %T", now); - xmlnode_insert_cdata(xmlnode_insert_tag(querynode, "display"), buf, -1); - gjab_send(gjc, x); - - xmlnode_free(x); -} - -static void jabber_handlelast(gjconn gjc, xmlnode iqnode) { - xmlnode x, querytag; - char *id, *from; - struct jabber_data *jd = GJ_GC(gjc)->proto_data; - char idle_time[32]; + jd->node_cache = g_hash_table_new_full( g_str_hash, g_str_equal, NULL, jabber_cache_entry_free ); + jd->buddies = g_hash_table_new( g_str_hash, g_str_equal ); - id = xmlnode_get_attrib(iqnode, "id"); - from = xmlnode_get_attrib(iqnode, "from"); - - x = jutil_iqnew(JPACKET__RESULT, "jabber:iq:last"); - - xmlnode_put_attrib(x, "to", from); - xmlnode_put_attrib(x, "id", id); - querytag = xmlnode_get_tag(x, "query"); - g_snprintf(idle_time, sizeof idle_time, "%ld", jd->idle ? time(NULL) - jd->idle : 0); - xmlnode_put_attrib(querytag, "seconds", idle_time); - - gjab_send(gjc, x); - xmlnode_free(x); -} - -/* - * delete == TRUE: delete found entry - * - * returns pointer to (local) copy of value if found, NULL otherwise - * - * Note: non-reentrant! Local static storage re-used on subsequent calls. - * If you're going to need to keep the returned value, make a copy! - */ -static gchar *jabber_track_queries(GHashTable *queries, gchar *key, gboolean delete) -{ - gpointer my_key, my_val; - static gchar *ret_val = NULL; - - if(ret_val != NULL) { - g_free(ret_val); - ret_val = NULL; + /* Figure out the hostname to connect to. */ + if( acc->server && *acc->server ) + connect_to = acc->server; + else if( ( srv = srv_lookup( "xmpp-client", "tcp", jd->server ) ) || + ( srv = srv_lookup( "jabber-client", "tcp", jd->server ) ) ) + connect_to = srv->name; + else + connect_to = jd->server; + + imcb_log( ic, "Connecting" ); + + if( set_getint( &acc->set, "port" ) < JABBER_PORT_MIN || + set_getint( &acc->set, "port" ) > JABBER_PORT_MAX ) + { + imcb_log( ic, "Incorrect port number, must be in the %d-%d range", + JABBER_PORT_MIN, JABBER_PORT_MAX ); + imc_logout( ic, FALSE ); + return; } - - /* self-protection */ - if(queries != NULL && key != NULL) { - if(g_hash_table_lookup_extended(queries, key, &my_key, &my_val)) { - ret_val = g_strdup((gchar *) my_val); - if(delete) { - g_hash_table_remove(queries, key); - g_free(my_key); - g_free(my_val); - } - } + + /* For non-SSL connections we can try to use the port # from the SRV + reply, but let's not do that when using SSL, SSL usually runs on + non-standard ports... */ + if( set_getbool( &acc->set, "ssl" ) ) + { + jd->ssl = ssl_connect( connect_to, set_getint( &acc->set, "port" ), jabber_connected_ssl, ic ); + jd->fd = jd->ssl ? ssl_getfd( jd->ssl ) : -1; } - - return(ret_val); -} - -static void jabber_handlepacket(gjconn gjc, jpacket p) -{ - char *id; - switch (p->type) { - case JPACKET_MESSAGE: - jabber_handlemessage(gjc, p); - break; - case JPACKET_PRESENCE: - jabber_handlepresence(gjc, p); - break; - case JPACKET_IQ: - id = xmlnode_get_attrib(p->x, "id"); - if (id != NULL && !strcmp(id, IQID_AUTH)) { - jabber_handleauthresp(gjc, p); - break; - } - - if (jpacket_subtype(p) == JPACKET__SET) { - xmlnode querynode; - querynode = xmlnode_get_tag(p->x, "query"); - if (NSCHECK(querynode, "jabber:iq:roster")) { - jabber_handlebuddy(gjc, xmlnode_get_firstchild(querynode)); - } - } else if (jpacket_subtype(p) == JPACKET__GET) { - xmlnode querynode; - querynode = xmlnode_get_tag(p->x, "query"); - if (NSCHECK(querynode, NS_VERSION)) { - jabber_handleversion(gjc, p->x); - } else if (NSCHECK(querynode, NS_TIME)) { - jabber_handletime(gjc, p->x); - } else if (NSCHECK(querynode, "jabber:iq:last")) { - jabber_handlelast(gjc, p->x); - } - } else if (jpacket_subtype(p) == JPACKET__RESULT) { - xmlnode querynode, vcard; - /* char *xmlns; */ - char *from; - - /* - * TBD: ISTM maybe this part could use a serious re-work? - */ - from = xmlnode_get_attrib(p->x, "from"); - querynode = xmlnode_get_tag(p->x, "query"); - vcard = xmlnode_get_tag(p->x, "vCard"); - if (!vcard) - vcard = xmlnode_get_tag(p->x, "VCARD"); - - if (NSCHECK(querynode, NS_ROSTER)) { - jabber_handleroster(gjc, querynode); - } else if (NSCHECK(querynode, NS_VCARD)) { - jabber_track_queries(gjc->queries, id, TRUE); /* delete query track */ - jabber_handlevcard(gjc, querynode, from); - } else if (vcard) { - jabber_track_queries(gjc->queries, id, TRUE); /* delete query track */ - jabber_handlevcard(gjc, vcard, from); - } else { - char *val; - - /* handle "null" query results */ - if((val = jabber_track_queries(gjc->queries, id, TRUE)) != NULL) { - if (!g_strncasecmp(val, "vcard", 5)) { - jabber_handlevcard(gjc, NULL, from); - } - - /* No-op */ - } - } - - } else if (jpacket_subtype(p) == JPACKET__ERROR) { - xmlnode xerr; - char *from, *errmsg = NULL; - int errcode = 0; - - from = xmlnode_get_attrib(p->x, "from"); - xerr = xmlnode_get_tag(p->x, "error"); - if (xerr) { - errmsg = xmlnode_get_data(xerr); - if (xmlnode_get_attrib(xerr, "code")) - errcode = atoi(xmlnode_get_attrib(xerr, "code")); - } - - from = g_strdup_printf("Error %d (%s)", errcode, from); - do_error_dialog(GJ_GC(gjc), errmsg, from); - g_free(from); - - } - - break; - case JPACKET_S10N: - jabber_handles10n(gjc, p); - break; + else + { + jd->fd = proxy_connect( connect_to, srv ? srv->port : set_getint( &acc->set, "port" ), jabber_connected_plain, ic ); } - - xmlnode_free(p->x); - - return; -} - -static void jabber_handlestate(gjconn gjc, int state) -{ - switch (state) { - case JCONN_STATE_OFF: - if(gjc->was_connected) { - hide_login_progress_error(GJ_GC(gjc), _("Connection lost")); - } else { - hide_login_progress(GJ_GC(gjc), _("Unable to connect")); - } - signoff(GJ_GC(gjc)); - break; - case JCONN_STATE_CONNECTED: - gjc->was_connected = 1; - set_login_progress(GJ_GC(gjc), 2, _("Connected")); - break; - case JCONN_STATE_ON: - set_login_progress(GJ_GC(gjc), 3, _("Requesting Authentication Method")); - gjab_reqauth(gjc); - break; + g_free( srv ); + + if( jd->fd == -1 ) + { + imcb_error( ic, "Could not connect to server" ); + imc_logout( ic, TRUE ); } - return; } -static void jabber_acc_init(account_t *acc) +static void jabber_logout( struct im_connection *ic ) { - set_t *s; + struct jabber_data *jd = ic->proto_data; - s = set_add( &acc->set, "port", "5222", set_eval_int, acc ); - s->flags |= ACC_SET_OFFLINE_ONLY; + jabber_end_stream( ic ); - s = set_add( &acc->set, "resource", "BitlBee", NULL, acc ); - s->flags |= ACC_SET_OFFLINE_ONLY; + if( jd->r_inpa >= 0 ) + b_event_remove( jd->r_inpa ); + if( jd->w_inpa >= 0 ) + b_event_remove( jd->w_inpa ); - s = set_add( &acc->set, "server", NULL, set_eval_account, acc ); - s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY; + if( jd->ssl ) + ssl_disconnect( jd->ssl ); + if( jd->fd >= 0 ) + closesocket( jd->fd ); - s = set_add( &acc->set, "ssl", "false", set_eval_bool, acc ); - s->flags |= ACC_SET_OFFLINE_ONLY; + if( jd->tx_len ) + g_free( jd->txq ); + + g_hash_table_destroy( jd->node_cache ); + + xt_free( jd->xt ); + + g_free( jd->away_message ); + g_free( jd->username ); + g_free( jd ); } -static void jabber_login(account_t *acc) +static int jabber_buddy_msg( struct im_connection *ic, char *who, char *message, int flags ) { - struct gaim_connection *gc; - struct jabber_data *jd; - char *resource, *loginname; + struct jabber_data *jd = ic->proto_data; + struct jabber_buddy *bud; + struct xt_node *node; + int st; - /* Time to move some data/things from the old syntax to the new one: */ - if (acc->server) { - char *s, *tmp_server; - int port; - - if (g_strcasecmp(acc->server, "ssl") == 0) { - set_setstr(&acc->set, "server", ""); - set_setint(&acc->set, "port", DEFAULT_PORT_SSL); - set_setstr(&acc->set, "ssl", "true"); - - g_free(acc->server); - acc->server = NULL; - } else if ((s = strchr(acc->server, ':'))) { - if (strstr(acc->server, ":ssl")) { - set_setint(&acc->set, "port", DEFAULT_PORT_SSL); - set_setstr(&acc->set, "ssl", "true"); - } - if (isdigit(s[1])) { - if (sscanf(s + 1, "%d", &port) == 1) - set_setint(&acc->set, "port", port); - } - tmp_server = g_strndup(acc->server, s - acc->server); - set_setstr(&acc->set, "server", tmp_server); - g_free(tmp_server); - } - } + bud = jabber_buddy_by_jid( ic, who, 0 ); - gc = new_gaim_conn(acc); - jd = gc->proto_data = g_new0(struct jabber_data, 1); + node = xt_new_node( "body", message, NULL ); + node = jabber_make_packet( "message", "chat", bud ? bud->full_jid : who, node ); - if( strchr( acc->user, '@' ) == NULL ) + if( bud && ( jd->flags & JFLAG_WANT_TYPING ) && + ( ( bud->flags & JBFLAG_DOES_XEP85 ) || + !( bud->flags & JBFLAG_PROBED_XEP85 ) ) ) { - hide_login_progress( gc, "Invalid account name" ); - signoff( gc ); - return; + struct xt_node *act; + + /* If the user likes typing notification and if we don't know + (and didn't probe before) if this resource supports XEP85, + include a probe in this packet now. Also, if we know this + buddy does support XEP85, we have to send this <active/> + tag to tell that the user stopped typing (well, that's what + we guess when s/he pressed Enter...). */ + act = xt_new_node( "active", NULL, NULL ); + xt_add_attr( act, "xmlns", XMLNS_CHATSTATES ); + xt_add_child( node, act ); + + /* Just make sure we do this only once. */ + bud->flags |= JBFLAG_PROBED_XEP85; } - resource = set_getstr(&acc->set, "resource"); - loginname = create_valid_jid(acc->user, DEFAULT_SERVER, resource); + st = jabber_write_packet( ic, node ); + xt_free_node( node ); - jd->hash = g_hash_table_new(g_str_hash, g_str_equal); - jd->chats = NULL; /* we have no chats yet */ - - set_login_progress(gc, 1, _("Connecting")); - - if (!(jd->gjc = gjab_new(loginname, acc->pass, gc))) { - g_free(loginname); - hide_login_progress(gc, _("Unable to connect")); - signoff(gc); - return; - } - - g_free(loginname); - gjab_state_handler(jd->gjc, jabber_handlestate); - gjab_packet_handler(jd->gjc, jabber_handlepacket); - jd->gjc->queries = g_hash_table_new(g_str_hash, g_str_equal); - gjab_start(jd->gjc); -} - -static gboolean jabber_destroy_hash(gpointer key, gpointer val, gpointer data) { - g_free(key); - g_free(val); - return TRUE; -} - -static gboolean jabber_free(gpointer data, gint fd, b_input_condition cond) -{ - struct jabber_data *jd = 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); - - return FALSE; -} - -static void jabber_close(struct gaim_connection *gc) -{ - struct jabber_data *jd = gc->proto_data; - - if(jd) { - GSList *jcs = jd->chats; - - /* Free-up the jabber_chat struct allocs and the list */ - while (jcs) { - g_free(jcs->data); - jcs = jcs->next; - } - g_slist_free(jd->chats); - - /* Free-up the away status memories and the list */ - if(jd->hash != NULL) { - g_hash_table_foreach_remove(jd->hash, jabber_destroy_hash, NULL); - g_hash_table_destroy(jd->hash); - jd->hash = NULL; - } - - /* Free-up the pending queries memories and the list */ - if(jd->gjc != NULL && jd->gjc->queries != NULL) { - g_hash_table_foreach_remove(jd->gjc->queries, jabber_destroy_hash, NULL); - g_hash_table_destroy(jd->gjc->queries); - jd->gjc->queries = NULL; - } - } - if (gc->inpa) - b_event_remove(gc->inpa); - - if(jd) { - b_timeout_add(50, jabber_free, jd); - if(jd->gjc != NULL) - xmlnode_free(jd->gjc->current); - } - gc->proto_data = NULL; -} - -static int jabber_send_im(struct gaim_connection *gc, char *who, char *message, int len, int flags) -{ - xmlnode x, y; - char *realwho; - gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; - - if (!who || !message) - return 0; - - x = xmlnode_new_tag("message"); - /* Bare username and "username" not the server itself? */ - if (!strchr(who, '@') && strcmp(who, gjc->user->server) != 0) - realwho = g_strdup_printf("%s@%s", who, gjc->user->server); - else - realwho = g_strdup(who); - xmlnode_put_attrib(x, "to", realwho); - g_free(realwho); - - xmlnode_insert_tag(x, "bitlbee"); - xmlnode_put_attrib(x, "type", "chat"); - - if (message && strlen(message)) { - y = xmlnode_insert_tag(x, "body"); - xmlnode_insert_cdata(y, message, -1); - } - - gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x); - xmlnode_free(x); - return 1; + return st; } -/* - * Add/update buddy's roster entry on server - */ -static void jabber_roster_update(struct gaim_connection *gc, char *name) +static GList *jabber_away_states( struct im_connection *ic ) { - xmlnode x, y; - char *realwho; - gjconn gjc; - struct buddy *buddy = NULL; - /* struct group *buddy_group = NULL; */ + static GList *l = NULL; + int i; - if(gc && gc->proto_data && ((struct jabber_data *)gc->proto_data)->gjc && name) { - gjc = ((struct jabber_data *)gc->proto_data)->gjc; - - if (!strchr(name, '@')) - realwho = g_strdup_printf("%s@%s", name, gjc->user->server); - else { - jid who = jid_new(gjc->p, name); - if (who->user == NULL) { - /* FIXME: transport */ - return; - } - realwho = g_strdup_printf("%s@%s", who->user, who->server); - } - - - x = jutil_iqnew(JPACKET__SET, NS_ROSTER); - y = xmlnode_insert_tag(xmlnode_get_tag(x, "query"), "item"); - xmlnode_put_attrib(y, "jid", realwho); - - - /* If we can find the buddy, there's an alias for him, it's not 0-length - * and it doesn't match his JID, add the "name" attribute. - */ - if((buddy = find_buddy(gc, realwho)) != NULL && - buddy->show != NULL && buddy->show[0] != '\0' && strcmp(realwho, buddy->show)) { - - xmlnode_put_attrib(y, "name", buddy->show); - } - - /* - * Find out what group the buddy's in and send that along - * with the roster item. - */ - /* ** Bitlbee disabled ** - if((buddy_group = NULL) != NULL) { - xmlnode z; - z = xmlnode_insert_tag(y, "group"); - xmlnode_insert_cdata(z, buddy_group->name, -1); - } - ** End - Bitlbee ** */ - - gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x); - - xmlnode_free(x); - g_free(realwho); - } -} - -/* - * Change buddy's group on server roster - */ -static void jabber_group_change(struct gaim_connection *gc, char *name, char *old_group, char *new_group) -{ - if(strcmp(old_group, new_group)) { - jabber_roster_update(gc, name); - } -} - -static void jabber_add_buddy(struct gaim_connection *gc, char *name) -{ - xmlnode x; - char *realwho; - gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; - - if (!((struct jabber_data *)gc->proto_data)->did_import) - return; - - if (!name) - return; - - if (!strcmp(gc->username, name)) - return; - - if (!strchr(name, '@')) - realwho = g_strdup_printf("%s@%s", name, gjc->user->server); - else { - jid who; - - if((who = jid_new(gjc->p, name)) == NULL) { - char *msg = g_strdup_printf("%s: \"%s\"", _("Invalid Jabber I.D."), name); - do_error_dialog(GJ_GC(gjc), msg, _("Jabber Error")); - g_free(msg); - jabber_remove_gaim_buddy(gc, name); - return; - } - if (who->user == NULL) { - /* FIXME: transport */ - return; - } - realwho = g_strdup_printf("%s@%s", who->user, who->server); - } - - x = xmlnode_new_tag("presence"); - xmlnode_put_attrib(x, "to", realwho); - xmlnode_put_attrib(x, "type", "subscribe"); - gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x); - xmlnode_free(x); - - jabber_roster_update(gc, realwho); - - g_free(realwho); + if( l == NULL ) + for( i = 0; jabber_away_state_list[i].full_name; i ++ ) + l = g_list_append( l, (void*) jabber_away_state_list[i].full_name ); + + return l; } -static void jabber_remove_buddy(struct gaim_connection *gc, char *name, char *group) +static void jabber_get_info( struct im_connection *ic, char *who ) { - xmlnode x; - char *realwho; - gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; - - if (!name) - return; - - if (!strchr(name, '@')) - realwho = g_strdup_printf("%s@%s", name, gjc->user->server); + struct jabber_data *jd = ic->proto_data; + struct jabber_buddy *bud; + + if( strchr( who, '/' ) ) + bud = jabber_buddy_by_jid( ic, who, 0 ); else - realwho = g_strdup(name); - - x = xmlnode_new_tag("presence"); - xmlnode_put_attrib(x, "to", realwho); - xmlnode_put_attrib(x, "type", "unsubscribe"); - gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x); - g_free(realwho); - xmlnode_free(x); -} - -static void jabber_get_info(struct gaim_connection *gc, char *who) { - xmlnode x; - char *id; - char *realwho; - struct jabber_data *jd = gc->proto_data; - gjconn gjc = jd->gjc; - - x = jutil_iqnew(JPACKET__GET, NS_VCARD); - /* Bare username? */ - if (!strchr(who, '@')) { - realwho = g_strdup_printf("%s@%s", who, gjc->user->server); - } else { - realwho = g_strdup(who); + { + char *s = jabber_normalize( who ); + bud = g_hash_table_lookup( jd->buddies, s ); + g_free( s ); } - xmlnode_put_attrib(x, "to", realwho); - g_free(realwho); - - id = gjab_getid(gjc); - xmlnode_put_attrib(x, "id", id); - - g_hash_table_insert(jd->gjc->queries, g_strdup(id), g_strdup("vCard")); - - gjab_send(gjc, x); - - xmlnode_free(x); -} - -static void jabber_get_away_msg(struct gaim_connection *gc, char *who) { - struct jabber_data *jd = gc->proto_data; - gjconn gjc = jd->gjc; - char *status; - - /* space for all elements: Jabber I.D. + "status" + NULL (list terminator) */ - gchar **str_arr = (gchar **) g_new(gpointer, 3); - gchar **ap = str_arr; - gchar *realwho, *final; - - /* Bare username? */ - if (!strchr(who, '@')) { - realwho = g_strdup_printf("%s@%s", who, gjc->user->server); - } else { - realwho = g_strdup(who); - } - *ap++ = g_strdup_printf("<B>Jabber ID:</B> %s<BR>\n", realwho); - - if((status = g_hash_table_lookup(jd->hash, realwho)) == NULL) { - status = _("Unknown"); + while( bud ) + { + imcb_log( ic, "Buddy %s (%d) information:\nAway state: %s\nAway message: %s", + bud->full_jid, bud->priority, + bud->away_state ? bud->away_state->full_name : "(none)", + bud->away_message ? : "(none)" ); + bud = bud->next; } - *ap++ = g_strdup_printf("<B>Status:</B> %s<BR>\n", status); - - *ap = NULL; - - final= g_strjoinv(NULL, str_arr); - g_strfreev(str_arr); - - g_free(realwho); - g_free(final); + jabber_get_vcard( ic, bud ? bud->full_jid : who ); } -static GList *jabber_away_states(struct gaim_connection *gc) { - GList *m = NULL; - - m = g_list_append(m, "Online"); - m = g_list_append(m, "Chatty"); - m = g_list_append(m, "Away"); - m = g_list_append(m, "Extended Away"); - m = g_list_append(m, "Do Not Disturb"); - - return m; -} - -static void jabber_set_away(struct gaim_connection *gc, char *state, char *message) -{ - xmlnode x, y; - struct jabber_data *jd = gc->proto_data; - gjconn gjc = jd->gjc; - - gc->away = NULL; /* never send an auto-response */ - - x = xmlnode_new_tag("presence"); - - if (!strcmp(state, GAIM_AWAY_CUSTOM)) { - /* oh goody. Gaim is telling us what to do. */ - if (message) { - /* Gaim wants us to be away */ - y = xmlnode_insert_tag(x, "show"); - xmlnode_insert_cdata(y, "away", -1); - y = xmlnode_insert_tag(x, "status"); - xmlnode_insert_cdata(y, message, -1); - gc->away = ""; - } else { - /* Gaim wants us to not be away */ - /* but for Jabber, we can just send presence with no other information. */ - } - } else { - /* state is one of our own strings. it won't be NULL. */ - if (!g_strcasecmp(state, "Online")) { - /* once again, we don't have to put anything here */ - } else if (!g_strcasecmp(state, "Chatty")) { - y = xmlnode_insert_tag(x, "show"); - xmlnode_insert_cdata(y, "chat", -1); - } else if (!g_strcasecmp(state, "Away")) { - y = xmlnode_insert_tag(x, "show"); - xmlnode_insert_cdata(y, "away", -1); - gc->away = ""; - } else if (!g_strcasecmp(state, "Extended Away")) { - y = xmlnode_insert_tag(x, "show"); - xmlnode_insert_cdata(y, "xa", -1); - gc->away = ""; - } else if (!g_strcasecmp(state, "Do Not Disturb")) { - y = xmlnode_insert_tag(x, "show"); - xmlnode_insert_cdata(y, "dnd", -1); - gc->away = ""; - } - } - - gjab_send(gjc, x); - xmlnode_free(x); -} - -static void jabber_keepalive(struct gaim_connection *gc) { - struct jabber_data *jd = (struct jabber_data *)gc->proto_data; - gjab_send_raw(jd->gjc, " \t "); -} - -/*---------------------------------------*/ -/* Jabber "set info" (vCard) support */ -/*---------------------------------------*/ - -/* - * V-Card format: - * - * <vCard prodid='' version='' xmlns=''> - * <FN></FN> - * <N> - * <FAMILY/> - * <GIVEN/> - * </N> - * <NICKNAME/> - * <URL/> - * <ADR> - * <STREET/> - * <EXTADD/> - * <LOCALITY/> - * <REGION/> - * <PCODE/> - * <COUNTRY/> - * </ADR> - * <TEL/> - * <EMAIL/> - * <ORG> - * <ORGNAME/> - * <ORGUNIT/> - * </ORG> - * <TITLE/> - * <ROLE/> - * <DESC/> - * <BDAY/> - * </vCard> - * - * See also: - * - * http://docs.jabber.org/proto/html/vcard-temp.html - * http://www.vcard-xml.org/dtd/vCard-XML-v2-20010520.dtd - */ - -/* - * Cross-reference user-friendly V-Card entry labels to vCard XML tags - * and attributes. - * - * Order is (or should be) unimportant. For example: we have no way of - * knowing in what order real data will arrive. - * - * Format: Label, Pre-set text, "visible" flag, "editable" flag, XML tag - * name, XML tag's parent tag "path" (relative to vCard node). - * - * List is terminated by a NULL label pointer. - * - * Entries with no label text, but with XML tag and parent tag - * entries, are used by V-Card XML construction routines to - * "automagically" construct the appropriate XML node tree. - * - * Thoughts on future direction/expansion - * - * This is a "simple" vCard. - * - * It is possible for nodes other than the "vCard" node to have - * attributes. Should that prove necessary/desirable, add an - * "attributes" pointer to the vcard_template struct, create the - * necessary tag_attr structs, and add 'em to the vcard_dflt_data - * array. - * - * The above changes will (obviously) require changes to the vCard - * construction routines. - */ - -static struct vcard_template { - char *label; /* label text pointer */ - char *text; /* entry text pointer */ - int visible; /* should entry field be "visible?" */ - int editable; /* should entry field be editable? */ - char *tag; /* tag text */ - char *ptag; /* parent tag "path" text */ - char *url; /* vCard display format if URL */ -} vcard_template_data[] = { - {N_("Full Name"), NULL, TRUE, TRUE, "FN", NULL, NULL}, - {N_("Family Name"), NULL, TRUE, TRUE, "FAMILY", "N", NULL}, - {N_("Given Name"), NULL, TRUE, TRUE, "GIVEN", "N", NULL}, - {N_("Nickname"), NULL, TRUE, TRUE, "NICKNAME", NULL, NULL}, - {N_("URL"), NULL, TRUE, TRUE, "URL", NULL, "<A HREF=\"%s\">%s</A>"}, - {N_("Street Address"), NULL, TRUE, TRUE, "STREET", "ADR", NULL}, - {N_("Extended Address"), NULL, TRUE, TRUE, "EXTADD", "ADR", NULL}, - {N_("Locality"), NULL, TRUE, TRUE, "LOCALITY", "ADR", NULL}, - {N_("Region"), NULL, TRUE, TRUE, "REGION", "ADR", NULL}, - {N_("Postal Code"), NULL, TRUE, TRUE, "PCODE", "ADR", NULL}, - {N_("Country"), NULL, TRUE, TRUE, "COUNTRY", "ADR", NULL}, - {N_("Telephone"), NULL, TRUE, TRUE, "TELEPHONE", NULL, NULL}, - {N_("Email"), NULL, TRUE, TRUE, "EMAIL", NULL, "<A HREF=\"mailto:%s\">%s</A>"}, - {N_("Organization Name"), NULL, TRUE, TRUE, "ORGNAME", "ORG", NULL}, - {N_("Organization Unit"), NULL, TRUE, TRUE, "ORGUNIT", "ORG", NULL}, - {N_("Title"), NULL, TRUE, TRUE, "TITLE", NULL, NULL}, - {N_("Role"), NULL, TRUE, TRUE, "ROLE", NULL, NULL}, - {N_("Birthday"), NULL, TRUE, TRUE, "BDAY", NULL, NULL}, - {N_("Description"), NULL, TRUE, TRUE, "DESC", NULL, NULL}, - {"", NULL, TRUE, TRUE, "N", NULL, NULL}, - {"", NULL, TRUE, TRUE, "ADR", NULL, NULL}, - {"", NULL, TRUE, TRUE, "ORG", NULL, NULL}, - {NULL, NULL, 0, 0, NULL, NULL, NULL} -}; - -/* - * Used by routines to parse an XML-encoded string into an xmlnode tree - */ -typedef struct { - XML_Parser parser; - xmlnode current; -} *xmlstr2xmlnode_parser, xmlstr2xmlnode_parser_struct; - - -/* - * Used by XML_Parse on parsing CDATA - */ -static void xmlstr2xmlnode_charData(void *userdata, const char *s, int slen) -{ - xmlstr2xmlnode_parser xmlp = (xmlstr2xmlnode_parser) userdata; - - if (xmlp->current) - xmlnode_insert_cdata(xmlp->current, s, slen); -} - -/* - * Used by XML_Parse to start or append to an xmlnode - */ -static void xmlstr2xmlnode_startElement(void *userdata, const char *name, const char **attribs) +static void jabber_set_away( struct im_connection *ic, char *state_txt, char *message ) { - xmlnode x; - xmlstr2xmlnode_parser xmlp = (xmlstr2xmlnode_parser) userdata; - - if (xmlp->current) { - /* Append the node to the current one */ - x = xmlnode_insert_tag(xmlp->current, name); - xmlnode_put_expat_attribs(x, attribs); - - xmlp->current = x; - } else { - x = xmlnode_new_tag(name); - xmlnode_put_expat_attribs(x, attribs); - xmlp->current = x; - } -} - -/* - * Used by XML_Parse to end an xmlnode - */ -static void xmlstr2xmlnode_endElement(void *userdata, const char *name) -{ - xmlstr2xmlnode_parser xmlp = (xmlstr2xmlnode_parser) userdata; - xmlnode x; - - if (xmlp->current != NULL && (x = xmlnode_get_parent(xmlp->current)) != NULL) { - xmlp->current = x; - } + struct jabber_data *jd = ic->proto_data; + struct jabber_away_state *state; + + /* Save all this info. We need it, for example, when changing the priority setting. */ + state = (void *) jabber_away_state_by_name( state_txt ); + jd->away_state = state ? state : (void *) jabber_away_state_list; /* Fall back to "Away" if necessary. */ + g_free( jd->away_message ); + jd->away_message = ( message && *message ) ? g_strdup( message ) : NULL; + + presence_send_update( ic ); } -/* - * Parse an XML-encoded string into an xmlnode tree - * - * Caller is responsible for freeing the returned xmlnode - */ -static xmlnode xmlstr2xmlnode(char *xmlstring) +static void jabber_add_buddy( struct im_connection *ic, char *who, char *group ) { - xmlstr2xmlnode_parser my_parser = g_new(xmlstr2xmlnode_parser_struct, 1); - xmlnode x = NULL; - - my_parser->parser = XML_ParserCreate(NULL); - my_parser->current = NULL; - - XML_SetUserData(my_parser->parser, (void *)my_parser); - XML_SetElementHandler(my_parser->parser, xmlstr2xmlnode_startElement, xmlstr2xmlnode_endElement); - XML_SetCharacterDataHandler(my_parser->parser, xmlstr2xmlnode_charData); - XML_Parse(my_parser->parser, xmlstring, strlen(xmlstring), 0); - - x = my_parser->current; - - XML_ParserFree(my_parser->parser); - g_free(my_parser); - - return(x); + if( jabber_add_to_roster( ic, who, NULL ) ) + presence_send_request( ic, who, "subscribe" ); } -/* - * Insert a tag node into an xmlnode tree, recursively inserting parent tag - * nodes as necessary - * - * Returns pointer to inserted node - * - * Note to hackers: this code is designed to be re-entrant (it's recursive--it - * calls itself), so don't put any "static"s in here! - */ -static xmlnode insert_tag_to_parent_tag(xmlnode start, const char *parent_tag, const char *new_tag) +static void jabber_remove_buddy( struct im_connection *ic, char *who, char *group ) { - xmlnode x = NULL; - - /* - * If the parent tag wasn't specified, see if we can get it - * from the vCard template struct. - */ - if(parent_tag == NULL) { - struct vcard_template *vc_tp = vcard_template_data; - - while(vc_tp->label != NULL) { - if(strcmp(vc_tp->tag, new_tag) == 0) { - parent_tag = vc_tp->ptag; - break; - } - ++vc_tp; - } - } - - /* - * If we have a parent tag... - */ - if(parent_tag != NULL ) { - /* - * Try to get the parent node for a tag - */ - if((x = xmlnode_get_tag(start, parent_tag)) == NULL) { - /* - * Descend? - */ - char *grand_parent = strcpy(g_malloc(strlen(parent_tag) + 1), parent_tag); - char *parent; - - if((parent = strrchr(grand_parent, '/')) != NULL) { - *(parent++) = '\0'; - x = insert_tag_to_parent_tag(start, grand_parent, parent); - } else { - x = xmlnode_insert_tag(start, grand_parent); - } - g_free(grand_parent); - } else { - /* - * We found *something* to be the parent node. - * Note: may be the "root" node! - */ - xmlnode y; - if((y = xmlnode_get_tag(x, new_tag)) != NULL) { - return(y); - } - } - } - - /* - * insert the new tag into its parent node - */ - return(xmlnode_insert_tag((x == NULL? start : x), new_tag)); + /* We should always do this part. Clean up our administration a little bit. */ + jabber_buddy_remove_bare( ic, who ); + + if( jabber_remove_from_roster( ic, who ) ) + presence_send_request( ic, who, "unsubscribe" ); } -/* - * Send vCard info to Jabber server - */ -static void jabber_set_info(struct gaim_connection *gc, char *info) +static void jabber_keepalive( struct im_connection *ic ) { - xmlnode x, vc_node; - char *id; - struct jabber_data *jd = gc->proto_data; - gjconn gjc = jd->gjc; - - x = xmlnode_new_tag("iq"); - xmlnode_put_attrib(x,"type","set"); - - id = gjab_getid(gjc); + /* Just any whitespace character is enough as a keepalive for XMPP sessions. */ + jabber_write( ic, "\n", 1 ); - xmlnode_put_attrib(x, "id", id); - - /* - * Send only if there's actually any *information* to send - */ - if((vc_node = xmlstr2xmlnode(info)) != NULL && xmlnode_get_name(vc_node) != NULL && - g_strncasecmp(xmlnode_get_name(vc_node), "vcard", 5) == 0) { - xmlnode_insert_tag_node(x, vc_node); - gjab_send(gjc, x); - } - - xmlnode_free(x); + /* This runs the garbage collection every minute, which means every packet + is in the cache for about a minute (which should be enough AFAIK). */ + jabber_cache_clean( ic ); } -/* - * displays a Jabber vCard - */ -static void jabber_handlevcard(gjconn gjc, xmlnode querynode, char *from) +static int jabber_send_typing( struct im_connection *ic, char *who, int typing ) { - struct jabber_data *jd = GJ_GC(gjc)->proto_data; - jid who = jid_new(gjc->p, from); - char *status = NULL, *text = NULL; - GString *str = g_string_sized_new(100); - xmlnode child; - - gchar *buddy = NULL; + struct jabber_data *jd = ic->proto_data; + struct jabber_buddy *bud; - if(querynode == NULL) { - serv_got_crap(GJ_GC(gjc), "%s - Received empty info reply from %s", _("User Info"), from); - return; - } - - if(who->resource != NULL && (who->resource)[0] != '\0') { - buddy = g_strdup_printf("%s@%s/%s", who->user, who->server, who->resource); - } else { - buddy = g_strdup_printf("%s@%s", who->user, who->server); - } - - if((status = g_hash_table_lookup(jd->hash, buddy)) == NULL) { - status = _("Unknown"); + /* Enable typing notification related code from now. */ + jd->flags |= JFLAG_WANT_TYPING; + + if( ( bud = jabber_buddy_by_jid( ic, who, 0 ) ) == NULL ) + { + /* Sending typing notifications to unknown buddies is + unsupported for now. Shouldn't be a problem, I think. */ + return 0; } - - g_string_sprintfa(str, "%s: %s - %s: %s", _("Jabber ID"), buddy, _("Status"), - status); - - for(child = querynode->firstchild; child; child = child->next) + + if( bud->flags & JBFLAG_DOES_XEP85 ) { - xmlnode child2; - - if(child->type != NTYPE_TAG) - continue; - - text = xmlnode_get_data(child); - if(text && !strcmp(child->name, "FN")) { - info_string_append(str, "\n", _("Full Name"), text); - } else if (!strcmp(child->name, "N")) { - for (child2 = child->firstchild; child2; child2 = child2->next) { - char *text2 = NULL; - - if (child2->type != NTYPE_TAG) - continue; - - text2 = xmlnode_get_data(child2); - if (text2 && !strcmp(child2->name, "FAMILY")) { - info_string_append(str, "\n", _("Family Name"), text2); - } else if (text2 && !strcmp(child2->name, "GIVEN")) { - info_string_append(str, "\n", _("Given Name"), text2); - } else if (text2 && !strcmp(child2->name, "MIDDLE")) { - info_string_append(str, "\n", _("Middle Name"), text2); - } - } - } else if (text && !strcmp(child->name, "NICKNAME")) { - info_string_append(str, "\n", _("Nickname"), text); - } else if (text && !strcmp(child->name, "BDAY")) { - info_string_append(str, "\n", _("Birthday"), text); - } else if (!strcmp(child->name, "ADR")) { - /* show wich address it is */ - /* Just for the beauty of bitlbee - if (child->firstchild) - g_string_sprintfa(str, "%s:\n", _("Address")); - */ - for(child2 = child->firstchild; child2; child2 = child2->next) { - char *text2 = NULL; - - if(child2->type != NTYPE_TAG) - continue; - - text2 = xmlnode_get_data(child2); - if(text2 && !strcmp(child2->name, "POBOX")) { - info_string_append(str, "\n", - _("P.O. Box"), text2); - } else if(text2 && !strcmp(child2->name, "EXTADR")) { - info_string_append(str, "\n", - _("Extended Address"), text2); - } else if(text2 && !strcmp(child2->name, "STREET")) { - info_string_append(str, "\n", - _("Street Address"), text2); - } else if(text2 && !strcmp(child2->name, "LOCALITY")) { - info_string_append(str, "\n", - _("Locality"), text2); - } else if(text2 && !strcmp(child2->name, "REGION")) { - info_string_append(str, "\n", - _("Region"), text2); - } else if(text2 && !strcmp(child2->name, "PCODE")) { - info_string_append(str, "\n", - _("Postal Code"), text2); - } else if(text2 && (!strcmp(child2->name, "CTRY") - || !strcmp(child2->name, "COUNTRY"))) { - info_string_append(str, "\n", _("Country"), text2); - } - } - } else if(!strcmp(child->name, "TEL")) { - char *number = NULL; - if ((child2 = xmlnode_get_tag(child, "NUMBER"))) { - /* show what kind of number it is */ - number = xmlnode_get_data(child2); - if(number) { - info_string_append(str, "\n", _("Telephone"), number); - } - } else if((number = xmlnode_get_data(child))) { - /* lots of clients (including gaim) do this, - * but it's out of spec */ - info_string_append(str, "\n", _("Telephone"), number); - } - } else if(!strcmp(child->name, "EMAIL")) { - char *userid = NULL; - if((child2 = xmlnode_get_tag(child, "USERID"))) { - /* show what kind of email it is */ - userid = xmlnode_get_data(child2); - if(userid) { - info_string_append(str, "\n", _("Email"), userid); - } - } else if((userid = xmlnode_get_data(child))) { - /* lots of clients (including gaim) do this, - * but it's out of spec */ - info_string_append(str, "\n", _("Email"), userid); - } - } else if(!strcmp(child->name, "ORG")) { - for(child2 = child->firstchild; child2; child2 = child2->next) { - char *text2 = NULL; - - if(child2->type != NTYPE_TAG) - continue; - - text2 = xmlnode_get_data(child2); - if(text2 && !strcmp(child2->name, "ORGNAME")) { - info_string_append(str, "\n", _("Organization Name"), text2); - } else if(text2 && !strcmp(child2->name, "ORGUNIT")) { - info_string_append(str, "\n", _("Organization Unit"), text2); - } - } - } else if(text && !strcmp(child->name, "TITLE")) { - info_string_append(str, "\n", _("Title"), text); - } else if(text && !strcmp(child->name, "ROLE")) { - info_string_append(str, "\n", _("Role"), text); - } else if(text && !strcmp(child->name, "DESC")) { - g_string_sprintfa(str, "\n%s:\n%s\n%s", _("Description"), - text, _("End of Description")); - } + /* We're only allowed to send this stuff if we know the other + side supports it. */ + + struct xt_node *node; + char *type; + int st; + + if( typing & OPT_TYPING ) + type = "composing"; + else if( typing & OPT_THINKING ) + type = "paused"; + else + type = "active"; + + node = xt_new_node( type, NULL, NULL ); + xt_add_attr( node, "xmlns", XMLNS_CHATSTATES ); + node = jabber_make_packet( "message", "chat", bud->full_jid, node ); + + st = jabber_write_packet( ic, node ); + xt_free_node( node ); + + return st; } - - serv_got_crap(GJ_GC(gjc), "%s\n%s", _("User Info"), str->str); - - g_free(buddy); - g_string_free(str, TRUE); + + return 1; } -void jabber_init() +void jabber_initmodule() { - struct prpl *ret = g_new0(struct prpl, 1); - + struct prpl *ret = g_new0( struct prpl, 1 ); + ret->name = "jabber"; - ret->away_states = jabber_away_states; - ret->acc_init = jabber_acc_init; ret->login = jabber_login; - ret->close = jabber_close; - ret->send_im = jabber_send_im; - ret->set_info = jabber_set_info; - ret->get_info = jabber_get_info; + ret->init = jabber_init; + ret->logout = jabber_logout; + ret->buddy_msg = jabber_buddy_msg; + ret->away_states = jabber_away_states; +// ret->get_status_string = jabber_get_status_string; ret->set_away = jabber_set_away; - ret->get_away = jabber_get_away_msg; +// ret->set_info = jabber_set_info; + ret->get_info = jabber_get_info; ret->add_buddy = jabber_add_buddy; ret->remove_buddy = jabber_remove_buddy; +// ret->chat_msg = jabber_chat_msg; +// ret->chat_invite = jabber_chat_invite; +// ret->chat_leave = jabber_chat_leave; +// ret->chat_open = jabber_chat_open; ret->keepalive = jabber_keepalive; - ret->alias_buddy = jabber_roster_update; - ret->group_buddy = jabber_group_change; + ret->send_typing = jabber_send_typing; ret->handle_cmp = g_strcasecmp; - register_protocol (ret); + register_protocol( ret ); } diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h index 0b907500..42f57ae1 100644 --- a/protocols/jabber/jabber.h +++ b/protocols/jabber/jabber.h @@ -1,315 +1,195 @@ -/* - * 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 - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Jabber - * Copyright (C) 1998-1999 The Jabber Team http://jabber.org/ - */ - -#include <string.h> -#include <stdlib.h> -#include <sys/types.h> -#include <stdio.h> -#include <setjmp.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <errno.h> -#include <signal.h> -#include <stdarg.h> -#include <time.h> -#include <ctype.h> -#ifdef _WIN32 -#undef DATADIR -#include "sock.h" -#endif - -#include "lib.h" - - -#ifndef INCL_JABBER_H -#define INCL_JABBER_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* --------------------------------------------------------- */ -/* */ -/* JID structures & constants */ -/* */ -/* --------------------------------------------------------- */ -#define JID_RESOURCE 1 -#define JID_USER 2 -#define JID_SERVER 4 - -typedef struct jid_struct -{ - pool p; - char* resource; - char* user; - char* server; - char* full; - struct jid_struct *next; /* for lists of jids */ -} *jid; - -jid jid_new(pool p, char *idstr); /* Creates a jabber id from the idstr */ -void jid_set(jid id, char *str, int item); /* Individually sets jid components */ -char* jid_full(jid id); /* Builds a string type=user/resource@server from the jid data */ -int jid_cmp(jid a, jid b); /* Compares two jid's, returns 0 for perfect match */ -int jid_cmpx(jid a, jid b, int parts); /* Compares just the parts specified as JID_|JID_ */ -jid jid_append(jid a, jid b); /* Appending b to a (list), no dups */ -xmlnode jid_xres(jid id); /* Returns xmlnode representation of the resource?query=string */ -xmlnode jid_nodescan(jid id, xmlnode x); /* Scans the children of the node for a matching jid attribute */ -jid jid_user(jid a); /* returns the same jid but just of the user@host part */ - - -/* --------------------------------------------------------- */ -/* */ -/* JPacket structures & constants */ -/* */ -/* --------------------------------------------------------- */ -#define JPACKET_UNKNOWN 0x00 -#define JPACKET_MESSAGE 0x01 -#define JPACKET_PRESENCE 0x02 -#define JPACKET_IQ 0x04 -#define JPACKET_S10N 0x08 - -#define JPACKET__UNKNOWN 0 -#define JPACKET__NONE 1 -#define JPACKET__ERROR 2 -#define JPACKET__CHAT 3 -#define JPACKET__GROUPCHAT 4 -#define JPACKET__GET 5 -#define JPACKET__SET 6 -#define JPACKET__RESULT 7 -#define JPACKET__SUBSCRIBE 8 -#define JPACKET__SUBSCRIBED 9 -#define JPACKET__UNSUBSCRIBE 10 -#define JPACKET__UNSUBSCRIBED 11 -#define JPACKET__AVAILABLE 12 -#define JPACKET__UNAVAILABLE 13 -#define JPACKET__PROBE 14 -#define JPACKET__HEADLINE 15 -#define JPACKET__INVISIBLE 16 - -typedef struct jpacket_struct +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Jabber module - Main file * +* * +* Copyright 2006 Wilmer van der Gaast <wilmer@gaast.net> * +* * +* 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 along * +* with this program; if not, write to the Free Software Foundation, Inc., * +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * +* * +\***************************************************************************/ + +#ifndef _JABBER_H +#define _JABBER_H + +#include <glib.h> + +#include "xmltree.h" +#include "bitlbee.h" + +typedef enum { - unsigned char type; - int subtype; - int flag; - void* aux1; - xmlnode x; - jid to; - jid from; - char* iqns; - xmlnode iq; - pool p; -} *jpacket, _jpacket; - -jpacket jpacket_new(xmlnode x); /* Creates a jabber packet from the xmlnode */ -int jpacket_subtype(jpacket p); /* Returns the subtype value (looks at xmlnode for it) */ - - -/* --------------------------------------------------------- */ -/* */ -/* Presence Proxy DB structures & constants */ -/* */ -/* --------------------------------------------------------- */ -typedef struct ppdb_struct -{ - jid id; /* entry data */ - int pri; - xmlnode x; - struct ppdb_struct* user; /* linked list for user@server */ - pool p; /* db-level data */ - struct ppdb_struct* next; -} _ppdb, *ppdb; - -ppdb ppdb_insert(ppdb db, jid id, xmlnode x); /* Inserts presence into the proxy */ -xmlnode ppdb_primary(ppdb db, jid id); /* Fetches the matching primary presence for the id */ -void ppdb_free(ppdb db); /* Frees the db and all entries */ -xmlnode ppdb_get(ppdb db, jid id); /* Called successively to return each presence xmlnode */ - /* for the id and children, returns NULL at the end */ - - -/* --------------------------------------------------------- */ -/* */ -/* Simple Jabber Rate limit functions */ -/* */ -/* --------------------------------------------------------- */ -typedef struct jlimit_struct + JFLAG_STREAM_STARTED = 1, /* Set when we detected the beginning of the stream + and want to do auth. */ + JFLAG_AUTHENTICATED = 2, /* Set when we're successfully authenticatd. */ + JFLAG_STREAM_RESTART = 4, /* Set when we want to restart the stream (after + SASL or TLS). */ + JFLAG_WAIT_SESSION = 8, /* Set if we sent a <session> tag and need a reply + before we continue. */ + JFLAG_WAIT_BIND = 16, /* ... for <bind> tag. */ + JFLAG_WANT_TYPING = 32, /* Set if we ever sent a typing notification, this + activates all XEP-85 related code. */ +} jabber_flags_t; + +typedef enum { - char *key; - int start; - int points; - int maxt, maxp; - pool p; -} *jlimit, _jlimit; - -jlimit jlimit_new(int maxt, int maxp); -void jlimit_free(jlimit r); -int jlimit_check(jlimit r, char *key, int points); + JBFLAG_PROBED_XEP85 = 1, /* Set this when we sent our probe packet to make + sure it gets sent only once. */ + JBFLAG_DOES_XEP85 = 2, /* Set this when the resource seems to support + XEP85 (typing notification shite). */ +} jabber_buddy_flags_t; +#define JABBER_PORT_DEFAULT "5222" +#define JABBER_PORT_MIN 5220 +#define JABBER_PORT_MAX 5229 -/* --------------------------------------------------------- */ -/* */ -/* Error structures & constants */ -/* */ -/* --------------------------------------------------------- */ -typedef struct terror_struct +struct jabber_data { - int code; - char msg[64]; -} terror; - -#define TERROR_BAD (terror){400,"Bad Request"} -#define TERROR_AUTH (terror){401,"Unauthorized"} -#define TERROR_PAY (terror){402,"Payment Required"} -#define TERROR_FORBIDDEN (terror){403,"Forbidden"} -#define TERROR_NOTFOUND (terror){404,"Not Found"} -#define TERROR_NOTALLOWED (terror){405,"Not Allowed"} -#define TERROR_NOTACCEPTABLE (terror){406,"Not Acceptable"} -#define TERROR_REGISTER (terror){407,"Registration Required"} -#define TERROR_REQTIMEOUT (terror){408,"Request Timeout"} -#define TERROR_CONFLICT (terror){409,"Conflict"} - -#define TERROR_INTERNAL (terror){500,"Internal Server Error"} -#define TERROR_NOTIMPL (terror){501,"Not Implemented"} -#define TERROR_EXTERNAL (terror){502,"Remote Server Error"} -#define TERROR_UNAVAIL (terror){503,"Service Unavailable"} -#define TERROR_EXTTIMEOUT (terror){504,"Remote Server Timeout"} -#define TERROR_DISCONNECTED (terror){510,"Disconnected"} - -/* --------------------------------------------------------- */ -/* */ -/* Namespace constants */ -/* */ -/* --------------------------------------------------------- */ -#define NSCHECK(x,n) (j_strcmp(xmlnode_get_attrib(x,"xmlns"),n) == 0) - -#define NS_CLIENT "jabber:client" -#define NS_SERVER "jabber:server" -#define NS_AUTH "jabber:iq:auth" -#define NS_REGISTER "jabber:iq:register" -#define NS_ROSTER "jabber:iq:roster" -#define NS_OFFLINE "jabber:x:offline" -#define NS_AGENT "jabber:iq:agent" -#define NS_AGENTS "jabber:iq:agents" -#define NS_DELAY "jabber:x:delay" -#define NS_VERSION "jabber:iq:version" -#define NS_TIME "jabber:iq:time" -#define NS_VCARD "vcard-temp" -#define NS_PRIVATE "jabber:iq:private" -#define NS_SEARCH "jabber:iq:search" -#define NS_OOB "jabber:iq:oob" -#define NS_XOOB "jabber:x:oob" -#define NS_ADMIN "jabber:iq:admin" -#define NS_FILTER "jabber:iq:filter" -#define NS_AUTH_0K "jabber:iq:auth:0k" - - -/* --------------------------------------------------------- */ -/* */ -/* Message Types */ -/* */ -/* --------------------------------------------------------- */ -#define TMSG_NORMAL "normal" -#define TMSG_ERROR "error" -#define TMSG_CHAT "chat" -#define TMSG_GROUPCHAT "groupchat" -#define TMSG_HEADLINE "headline" - - -/* --------------------------------------------------------- */ -/* */ -/* JUtil functions */ -/* */ -/* --------------------------------------------------------- */ -xmlnode jutil_presnew(int type, char *to, char *status); /* Create a skeleton presence packet */ -xmlnode jutil_iqnew(int type, char *ns); /* Create a skeleton iq packet */ -xmlnode jutil_msgnew(char *type, char *to, char *subj, char *body); - /* Create a skeleton message packet */ -xmlnode jutil_header(char* xmlns, char* server); /* Create a skeleton stream packet */ -int jutil_priority(xmlnode x); /* Determine priority of this packet */ -void jutil_tofrom(xmlnode x); /* Swaps to/from fields on a packet */ -xmlnode jutil_iqresult(xmlnode x); /* Generate a skeleton iq/result, given a iq/query */ -char* jutil_timestamp(void); /* Get stringified timestamp */ -void jutil_error(xmlnode x, terror E); /* Append an <error> node to x */ -void jutil_delay(xmlnode msg, char *reason); /* Append a delay packet to msg */ -char* jutil_regkey(char *key, char *seed); /* pass a seed to generate a key, pass the key again to validate (returns it) */ - - -/* --------------------------------------------------------- */ -/* */ -/* JConn structures & functions */ -/* */ -/* --------------------------------------------------------- */ -#define JCONN_STATE_OFF 0 -#define JCONN_STATE_CONNECTED 1 -#define JCONN_STATE_ON 2 -#define JCONN_STATE_AUTH 3 - -typedef struct jconn_struct + struct im_connection *ic; + + int fd; + void *ssl; + char *txq; + int tx_len; + int r_inpa, w_inpa; + + struct xt_parser *xt; + jabber_flags_t flags; + + char *username; /* USERNAME@server */ + char *server; /* username@SERVER -=> server/domain, not hostname */ + + /* After changing one of these two (or the priority setting), call + presence_send_update() to inform the server about the changes. */ + struct jabber_away_state *away_state; + char *away_message; + + GHashTable *node_cache; + GHashTable *buddies; +}; + +struct jabber_away_state { - /* Core structure */ - pool p; /* Memory allocation pool */ - int state; /* Connection state flag */ - int fd; /* Connection file descriptor */ - jid user; /* User info */ - char *pass; /* User passwd */ - - /* Stream stuff */ - int id; /* id counter for jab_getid() function */ - char idbuf[9]; /* temporary storage for jab_getid() */ - char *sid; /* stream id from server, for digest auth */ - XML_Parser parser; /* Parser instance */ - xmlnode current; /* Current node in parsing instance.. */ - - /* Event callback ptrs */ - void (*on_state)(struct jconn_struct *j, int state); - void (*on_packet)(struct jconn_struct *j, jpacket p); + char code[5]; + char *full_name; +}; -} *jconn, jconn_struct; - -typedef void (*jconn_state_h)(jconn j, int state); -typedef void (*jconn_packet_h)(jconn j, jpacket p); - - -jconn jab_new(char *user, char *pass); -void jab_delete(jconn j); -void jab_state_handler(jconn j, jconn_state_h h); -void jab_packet_handler(jconn j, jconn_packet_h h); -void jab_start(jconn j); -void jab_stop(jconn j); - -int jab_getfd(jconn j); -jid jab_getjid(jconn j); -char *jab_getsid(jconn j); -char *jab_getid(jconn j); - -void jab_send(jconn j, xmlnode x); -void jab_send_raw(jconn j, const char *str); -void jab_recv(jconn j); -void jab_poll(jconn j, int timeout); - -char *jab_auth(jconn j); -char *jab_reg(jconn j); +typedef xt_status (*jabber_cache_event) ( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ); +struct jabber_cache_entry +{ + struct xt_node *node; + jabber_cache_event func; +}; +struct jabber_buddy +{ + char *bare_jid; + char *full_jid; + char *resource; + + int priority; + struct jabber_away_state *away_state; + char *away_message; + + time_t last_act; + jabber_buddy_flags_t flags; + + struct jabber_buddy *next; +}; + +/* Prefixes to use for packet IDs (mainly for IQ packets ATM). Usually the + first one should be used, but when storing a packet in the cache, a + "special" kind of ID is assigned to make it easier later to figure out + if we have to do call an event handler for the response packet. */ +#define JABBER_PACKET_ID "BeeP" +#define JABBER_CACHED_ID "BeeC" + +/* RFC 392[01] stuff */ +#define XMLNS_TLS "urn:ietf:params:xml:ns:xmpp-tls" +#define XMLNS_SASL "urn:ietf:params:xml:ns:xmpp-sasl" +#define XMLNS_BIND "urn:ietf:params:xml:ns:xmpp-bind" +#define XMLNS_SESSION "urn:ietf:params:xml:ns:xmpp-session" +#define XMLNS_STANZA_ERROR "urn:ietf:params:xml:ns:xmpp-stanzas" +#define XMLNS_STREAM_ERROR "urn:ietf:params:xml:ns:xmpp-streams" +#define XMLNS_ROSTER "jabber:iq:roster" + +/* Some supported extensions/legacy stuff */ +#define XMLNS_AUTH "jabber:iq:auth" /* XEP-0078 */ +#define XMLNS_VERSION "jabber:iq:version" /* XEP-0092 */ +#define XMLNS_TIME "jabber:iq:time" /* XEP-0090 */ +#define XMLNS_VCARD "vcard-temp" /* XEP-0054 */ +#define XMLNS_CHATSTATES "http://jabber.org/protocol/chatstates" /* 0085 */ +#define XMLNS_DISCOVER "http://jabber.org/protocol/disco#info" /* 0030 */ + +/* iq.c */ +xt_status jabber_pkt_iq( struct xt_node *node, gpointer data ); +int jabber_init_iq_auth( struct im_connection *ic ); +xt_status jabber_pkt_bind_sess( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ); +int jabber_get_roster( struct im_connection *ic ); +int jabber_get_vcard( struct im_connection *ic, char *bare_jid ); +int jabber_add_to_roster( struct im_connection *ic, char *handle, char *name ); +int jabber_remove_from_roster( struct im_connection *ic, char *handle ); + +/* message.c */ +xt_status jabber_pkt_message( struct xt_node *node, gpointer data ); + +/* presence.c */ +xt_status jabber_pkt_presence( struct xt_node *node, gpointer data ); +int presence_send_update( struct im_connection *ic ); +int presence_send_request( struct im_connection *ic, char *handle, char *request ); + +/* jabber_util.c */ +char *set_eval_priority( set_t *set, char *value ); +char *set_eval_tls( set_t *set, char *value ); +struct xt_node *jabber_make_packet( char *name, char *type, char *to, struct xt_node *children ); +struct xt_node *jabber_make_error_packet( struct xt_node *orig, char *err_cond, char *err_type ); +void jabber_cache_add( struct im_connection *ic, struct xt_node *node, jabber_cache_event func ); +struct xt_node *jabber_cache_get( struct im_connection *ic, char *id ); +void jabber_cache_entry_free( gpointer entry ); +void jabber_cache_clean( struct im_connection *ic ); +const struct jabber_away_state *jabber_away_state_by_code( char *code ); +const struct jabber_away_state *jabber_away_state_by_name( char *name ); +void jabber_buddy_ask( struct im_connection *ic, char *handle ); +char *jabber_normalize( char *orig ); + +typedef enum +{ + GET_BUDDY_CREAT = 1, /* Try to create it, if necessary. */ + GET_BUDDY_EXACT = 2, /* Get an exact message (only makes sense with bare JIDs). */ +} get_buddy_flags_t; + +struct jabber_buddy *jabber_buddy_add( struct im_connection *ic, char *full_jid ); +struct jabber_buddy *jabber_buddy_by_jid( struct im_connection *ic, char *jid, get_buddy_flags_t flags ); +int jabber_buddy_remove( struct im_connection *ic, char *full_jid ); +int jabber_buddy_remove_bare( struct im_connection *ic, char *bare_jid ); + +extern const struct jabber_away_state jabber_away_state_list[]; + +/* io.c */ +int jabber_write_packet( struct im_connection *ic, struct xt_node *node ); +int jabber_write( struct im_connection *ic, char *buf, int len ); +gboolean jabber_connected_plain( gpointer data, gint source, b_input_condition cond ); +gboolean jabber_connected_ssl( gpointer data, void *source, b_input_condition cond ); +gboolean jabber_start_stream( struct im_connection *ic ); +void jabber_end_stream( struct im_connection *ic ); + +/* sasl.c */ +xt_status sasl_pkt_mechanisms( struct xt_node *node, gpointer data ); +xt_status sasl_pkt_challenge( struct xt_node *node, gpointer data ); +xt_status sasl_pkt_result( struct xt_node *node, gpointer data ); +gboolean sasl_supported( struct im_connection *ic ); -#ifdef __cplusplus -} #endif - -#endif /* INCL_JABBER_H */ diff --git a/protocols/jabber/jabber_util.c b/protocols/jabber/jabber_util.c new file mode 100644 index 00000000..3c0e71f4 --- /dev/null +++ b/protocols/jabber/jabber_util.c @@ -0,0 +1,532 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Jabber module - Misc. stuff * +* * +* Copyright 2006 Wilmer van der Gaast <wilmer@gaast.net> * +* * +* 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 along * +* with this program; if not, write to the Free Software Foundation, Inc., * +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * +* * +\***************************************************************************/ + +#include "jabber.h" + +static unsigned int next_id = 1; + +char *set_eval_priority( set_t *set, char *value ) +{ + account_t *acc = set->data; + int i; + + if( sscanf( value, "%d", &i ) == 1 ) + { + /* Priority is a signed 8-bit integer, according to RFC 3921. */ + if( i < -128 || i > 127 ) + return NULL; + } + else + return NULL; + + /* Only run this stuff if the account is online ATM, + and if the setting seems to be acceptable. */ + if( acc->ic ) + { + /* Although set_eval functions usually are very nice and + convenient, they have one disadvantage: If I would just + call p_s_u() now to send the new prio setting, it would + send the old setting because the set->value gets changed + when the eval returns a non-NULL value. + + So now I can choose between implementing post-set + functions next to evals, or just do this little hack: */ + + g_free( set->value ); + set->value = g_strdup( value ); + + /* (Yes, sorry, I prefer the hack. :-P) */ + + presence_send_update( acc->ic ); + } + + return value; +} + +char *set_eval_tls( set_t *set, char *value ) +{ + if( g_strcasecmp( value, "try" ) == 0 ) + return value; + else + return set_eval_bool( set, value ); +} + +struct xt_node *jabber_make_packet( char *name, char *type, char *to, struct xt_node *children ) +{ + struct xt_node *node; + + node = xt_new_node( name, NULL, children ); + + if( type ) + xt_add_attr( node, "type", type ); + if( to ) + xt_add_attr( node, "to", to ); + + /* IQ packets should always have an ID, so let's generate one. It + might get overwritten by jabber_cache_add() if this packet has + to be saved until we receive a response. Cached packets get + slightly different IDs so we can recognize them. */ + if( strcmp( name, "iq" ) == 0 ) + { + char *id = g_strdup_printf( "%s%05x", JABBER_PACKET_ID, ( next_id++ ) & 0xfffff ); + xt_add_attr( node, "id", id ); + g_free( id ); + } + + return node; +} + +struct xt_node *jabber_make_error_packet( struct xt_node *orig, char *err_cond, char *err_type ) +{ + struct xt_node *node, *c; + char *to; + + /* Create the "defined-condition" tag. */ + c = xt_new_node( err_cond, NULL, NULL ); + xt_add_attr( c, "xmlns", XMLNS_STANZA_ERROR ); + + /* Put it in an <error> tag. */ + c = xt_new_node( "error", NULL, c ); + xt_add_attr( c, "type", err_type ); + + /* To make the actual error packet, we copy the original packet and + add our <error>/type="error" tag. Including the original packet + is recommended, so let's just do it. */ + node = xt_dup( orig ); + xt_add_child( node, c ); + xt_add_attr( node, "type", "error" ); + + /* Return to sender. */ + if( ( to = xt_find_attr( node, "from" ) ) ) + { + xt_add_attr( node, "to", to ); + xt_remove_attr( node, "from" ); + } + + return node; +} + +/* Cache a node/packet for later use. Mainly useful for IQ packets if you need + them when you receive the response. Use this BEFORE sending the packet so + it'll get a new id= tag, and do NOT free() the packet after writing it! */ +void jabber_cache_add( struct im_connection *ic, struct xt_node *node, jabber_cache_event func ) +{ + struct jabber_data *jd = ic->proto_data; + char *id = g_strdup_printf( "%s%05x", JABBER_CACHED_ID, ( next_id++ ) & 0xfffff ); + struct jabber_cache_entry *entry = g_new0( struct jabber_cache_entry, 1 ); + + xt_add_attr( node, "id", id ); + g_free( id ); + + entry->node = node; + entry->func = func; + g_hash_table_insert( jd->node_cache, xt_find_attr( node, "id" ), entry ); +} + +void jabber_cache_entry_free( gpointer data ) +{ + struct jabber_cache_entry *entry = data; + + xt_free_node( entry->node ); + g_free( entry ); +} + +gboolean jabber_cache_clean_entry( gpointer key, gpointer entry, gpointer nullpointer ); + +/* This one should be called from time to time (from keepalive, in this case) + to make sure things don't stay in the node cache forever. By marking nodes + during the first run and deleting marked nodes during a next run, every + node should be available in the cache for at least a minute (assuming the + function is indeed called every minute). */ +void jabber_cache_clean( struct im_connection *ic ) +{ + struct jabber_data *jd = ic->proto_data; + + g_hash_table_foreach_remove( jd->node_cache, jabber_cache_clean_entry, NULL ); +} + +gboolean jabber_cache_clean_entry( gpointer key, gpointer entry_, gpointer nullpointer ) +{ + struct jabber_cache_entry *entry = entry_; + struct xt_node *node = entry->node; + + if( node->flags & XT_SEEN ) + return TRUE; + else + { + node->flags |= XT_SEEN; + return FALSE; + } +} + +const struct jabber_away_state jabber_away_state_list[] = +{ + { "away", "Away" }, + { "chat", "Free for Chat" }, + { "dnd", "Do not Disturb" }, + { "xa", "Extended Away" }, + { "", "Online" }, + { "", NULL } +}; + +const struct jabber_away_state *jabber_away_state_by_code( char *code ) +{ + int i; + + for( i = 0; jabber_away_state_list[i].full_name; i ++ ) + if( g_strcasecmp( jabber_away_state_list[i].code, code ) == 0 ) + return jabber_away_state_list + i; + + return NULL; +} + +const struct jabber_away_state *jabber_away_state_by_name( char *name ) +{ + int i; + + for( i = 0; jabber_away_state_list[i].full_name; i ++ ) + if( g_strcasecmp( jabber_away_state_list[i].full_name, name ) == 0 ) + return jabber_away_state_list + i; + + return NULL; +} + +struct jabber_buddy_ask_data +{ + struct im_connection *ic; + char *handle; + char *realname; +}; + +static void jabber_buddy_ask_yes( gpointer w, struct jabber_buddy_ask_data *bla ) +{ + presence_send_request( bla->ic, bla->handle, "subscribed" ); + + if( imcb_find_buddy( bla->ic, bla->handle ) == NULL ) + imcb_ask_add( bla->ic, bla->handle, NULL ); + + g_free( bla->handle ); + g_free( bla ); +} + +static void jabber_buddy_ask_no( gpointer w, struct jabber_buddy_ask_data *bla ) +{ + presence_send_request( bla->ic, bla->handle, "subscribed" ); + + g_free( bla->handle ); + g_free( bla ); +} + +void jabber_buddy_ask( struct im_connection *ic, char *handle ) +{ + struct jabber_buddy_ask_data *bla = g_new0( struct jabber_buddy_ask_data, 1 ); + char *buf; + + bla->ic = ic; + bla->handle = g_strdup( handle ); + + buf = g_strdup_printf( "The user %s wants to add you to his/her buddy list.", handle ); + imcb_ask( ic, buf, bla, jabber_buddy_ask_yes, jabber_buddy_ask_no ); + g_free( buf ); +} + +/* Returns a new string. Don't leak it! */ +char *jabber_normalize( char *orig ) +{ + int len, i; + char *new; + + len = strlen( orig ); + new = g_new( char, len + 1 ); + for( i = 0; i < len; i ++ ) + new[i] = tolower( orig[i] ); + + new[i] = 0; + return new; +} + +/* Adds a buddy/resource to our list. Returns NULL if full_jid is not really a + FULL jid or if we already have this buddy/resource. XXX: No, great, actually + buddies from transports don't (usually) have resources. So we'll really have + to deal with that properly. Set their ->resource property to NULL. Do *NOT* + allow to mix this stuff, though... */ +struct jabber_buddy *jabber_buddy_add( struct im_connection *ic, char *full_jid_ ) +{ + struct jabber_data *jd = ic->proto_data; + struct jabber_buddy *bud, *new, *bi; + char *s, *full_jid; + + full_jid = jabber_normalize( full_jid_ ); + + if( ( s = strchr( full_jid, '/' ) ) ) + *s = 0; + + new = g_new0( struct jabber_buddy, 1 ); + + if( ( bud = g_hash_table_lookup( jd->buddies, full_jid ) ) ) + { + /* If this is a transport buddy or whatever, it can't have more + than one instance, so this is always wrong: */ + if( s == NULL || bud->resource == NULL ) + { + if( s ) *s = '/'; + g_free( new ); + g_free( full_jid ); + return NULL; + } + + new->bare_jid = bud->bare_jid; + + /* We already have another resource for this buddy, add the + new one to the list. */ + for( bi = bud; bi; bi = bi->next ) + { + /* Check for dupes. */ + if( g_strcasecmp( bi->resource, s + 1 ) == 0 ) + { + *s = '/'; + g_free( new ); + g_free( full_jid ); + return NULL; + } + /* Append the new item to the list. */ + else if( bi->next == NULL ) + { + bi->next = new; + break; + } + } + } + else + { + new->bare_jid = g_strdup( full_jid ); + g_hash_table_insert( jd->buddies, new->bare_jid, new ); + } + + if( s ) + { + *s = '/'; + new->full_jid = full_jid; + new->resource = strchr( new->full_jid, '/' ) + 1; + } + else + { + /* Let's waste some more bytes of RAM instead of to make + memory management a total disaster here.. */ + new->full_jid = full_jid; + } + + return new; +} + +/* Finds a buddy from our structures. Can find both full- and bare JIDs. When + asked for a bare JID, it uses the "resource_select" setting to see which + resource to pick. */ +struct jabber_buddy *jabber_buddy_by_jid( struct im_connection *ic, char *jid_, get_buddy_flags_t flags ) +{ + struct jabber_data *jd = ic->proto_data; + struct jabber_buddy *bud; + char *s, *jid; + + jid = jabber_normalize( jid_ ); + + if( ( s = strchr( jid, '/' ) ) ) + { + *s = 0; + if( ( bud = g_hash_table_lookup( jd->buddies, jid ) ) ) + { + /* Is this one of those no-resource buddies? */ + if( bud->resource == NULL ) + { + g_free( jid ); + return NULL; + } + else + { + /* See if there's an exact match. */ + for( ; bud; bud = bud->next ) + if( g_strcasecmp( bud->resource, s + 1 ) == 0 ) + break; + } + } + + if( bud == NULL && ( flags & GET_BUDDY_CREAT ) && imcb_find_buddy( ic, jid ) ) + { + *s = '/'; + bud = jabber_buddy_add( ic, jid ); + } + + g_free( jid ); + return bud; + } + else + { + struct jabber_buddy *best_prio, *best_time; + char *set; + + bud = g_hash_table_lookup( jd->buddies, jid ); + + g_free( jid ); + + if( bud == NULL ) + /* No match. Create it now? */ + return ( ( flags & GET_BUDDY_CREAT ) && imcb_find_buddy( ic, jid_ ) ) ? + jabber_buddy_add( ic, jid_ ) : NULL; + else if( bud->resource && ( flags & GET_BUDDY_EXACT ) ) + /* We want an exact match, so in thise case there shouldn't be a /resource. */ + return NULL; + else if( ( bud->resource == NULL || bud->next == NULL ) ) + /* No need for selection if there's only one option. */ + return bud; + + best_prio = best_time = bud; + for( ; bud; bud = bud->next ) + { + if( bud->priority > best_prio->priority ) + best_prio = bud; + if( bud->last_act > best_time->last_act ) + best_time = bud; + } + + if( ( set = set_getstr( &ic->acc->set, "resource_select" ) ) == NULL ) + return NULL; + else if( strcmp( set, "activity" ) == 0 ) + return best_time; + else /* if( strcmp( set, "priority" ) == 0 ) */ + return best_prio; + } +} + +/* Remove one specific full JID from our list. Use this when a buddy goes + off-line (because (s)he can still be online from a different location. + XXX: See above, we should accept bare JIDs too... */ +int jabber_buddy_remove( struct im_connection *ic, char *full_jid_ ) +{ + struct jabber_data *jd = ic->proto_data; + struct jabber_buddy *bud, *prev, *bi; + char *s, *full_jid; + + full_jid = jabber_normalize( full_jid_ ); + + if( ( s = strchr( full_jid, '/' ) ) ) + *s = 0; + + if( ( bud = g_hash_table_lookup( jd->buddies, full_jid ) ) ) + { + /* If there's only one item in the list (and if the resource + matches), removing it is simple. (And the hash reference + should be removed too!) */ + if( bud->next == NULL && ( ( s == NULL || bud->resource == NULL ) || g_strcasecmp( bud->resource, s + 1 ) == 0 ) ) + { + g_hash_table_remove( jd->buddies, bud->bare_jid ); + g_free( bud->bare_jid ); + g_free( bud->full_jid ); + g_free( bud->away_message ); + g_free( bud ); + + g_free( full_jid ); + + return 1; + } + else if( s == NULL || bud->resource == NULL ) + { + /* Tried to remove a bare JID while this JID does seem + to have resources... (Or the opposite.) *sigh* */ + g_free( full_jid ); + return 0; + } + else + { + for( bi = bud, prev = NULL; bi; bi = (prev=bi)->next ) + if( g_strcasecmp( bi->resource, s + 1 ) == 0 ) + break; + + g_free( full_jid ); + + if( bi ) + { + if( prev ) + prev->next = bi->next; + else + /* The hash table should point at the second + item, because we're removing the first. */ + g_hash_table_replace( jd->buddies, bi->bare_jid, bi->next ); + + g_free( bi->full_jid ); + g_free( bi->away_message ); + g_free( bi ); + + return 1; + } + else + { + return 0; + } + } + } + else + { + g_free( full_jid ); + return 0; + } +} + +/* Remove a buddy completely; removes all resources that belong to the + specified bare JID. Use this when removing someone from the contact + list, for example. */ +int jabber_buddy_remove_bare( struct im_connection *ic, char *bare_jid_ ) +{ + struct jabber_data *jd = ic->proto_data; + struct jabber_buddy *bud, *next; + char *bare_jid; + + if( strchr( bare_jid_, '/' ) ) + return 0; + + bare_jid = jabber_normalize( bare_jid_ ); + + if( ( bud = g_hash_table_lookup( jd->buddies, bare_jid ) ) ) + { + /* Most important: Remove the hash reference. We don't know + this buddy anymore. */ + g_hash_table_remove( jd->buddies, bud->bare_jid ); + + /* Deallocate the linked list of resources. */ + while( bud ) + { + next = bud->next; + g_free( bud->full_jid ); + g_free( bud->away_message ); + g_free( bud ); + bud = next; + } + + g_free( bare_jid ); + return 1; + } + else + { + g_free( bare_jid ); + return 0; + } +} diff --git a/protocols/jabber/jid.c b/protocols/jabber/jid.c deleted file mode 100644 index ed2b9ba1..00000000 --- a/protocols/jabber/jid.c +++ /dev/null @@ -1,170 +0,0 @@ -/* -------------------------------------------------------------------------- - * - * License - * - * The contents of this file are subject to the Jabber Open Source License - * Version 1.0 (the "JOSL"). You may not copy or use this file, in either - * source code or executable form, except in compliance with the JOSL. You - * may obtain a copy of the JOSL at http://www.jabber.org/ or at - * http://www.opensource.org/. - * - * Software distributed under the JOSL is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the JOSL - * for the specific language governing rights and limitations under the - * JOSL. - * - * Copyrights - * - * Portions created by or assigned to Jabber.com, Inc. are - * Copyright (c) 1999-2002 Jabber.com, Inc. All Rights Reserved. Contact - * information for Jabber.com, Inc. is available at http://www.jabber.com/. - * - * Portions Copyright (c) 1998-1999 Jeremie Miller. - * - * Acknowledgements - * - * Special thanks to the Jabber Open Source Contributors for their - * suggestions and support of Jabber. - * - * Alternatively, the contents of this file may be used under the terms of the - * GNU General Public License Version 2 or later (the "GPL"), in which case - * the provisions of the GPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * GPL and not to allow others to use your version of this file under the JOSL, - * indicate your decision by deleting the provisions above and replace them - * with the notice and other provisions required by the GPL. If you do not - * delete the provisions above, a recipient may use your version of this file - * under either the JOSL or the GPL. - * - * - * --------------------------------------------------------------------------*/ - -#include "jabber.h" -#include <glib.h> - -static jid jid_safe(jid id) -{ - char *str; - - if(strlen(id->server) == 0 || strlen(id->server) > 255) - return NULL; - - /* lowercase the hostname, make sure it's valid characters */ - for(str = id->server; *str != '\0'; str++) - { - *str = tolower(*str); - if(!(isalnum(*str) || *str == '.' || *str == '-' || *str == '_')) return NULL; - } - - /* cut off the user */ - if(id->user != NULL && strlen(id->user) > 64) - id->user[64] = '\0'; - - /* check for low and invalid ascii characters in the username */ - if(id->user != NULL) - for(str = id->user; *str != '\0'; str++) - if(*str <= 32 || *str == ':' || *str == '@' || *str == '<' || *str == '>' || *str == '\'' || *str == '"' || *str == '&') return NULL; - - return id; -} - -jid jid_new(pool p, char *idstr) -{ - char *server, *resource, *type, *str; - jid id; - - if(p == NULL || idstr == NULL || strlen(idstr) == 0) - return NULL; - - /* user@server/resource */ - - str = pstrdup(p, idstr); - - id = pmalloco(p,sizeof(struct jid_struct)); - id->p = p; - - resource = strstr(str,"/"); - if(resource != NULL) - { - *resource = '\0'; - ++resource; - if(strlen(resource) > 0) - id->resource = resource; - }else{ - resource = str + strlen(str); /* point to end */ - } - - type = strstr(str,":"); - if(type != NULL && type < resource) - { - *type = '\0'; - ++type; - str = type; /* ignore the type: prefix */ - } - - server = strstr(str,"@"); - if(server == NULL || server > resource) - { /* if there's no @, it's just the server address */ - id->server = str; - }else{ - *server = '\0'; - ++server; - id->server = server; - if(strlen(str) > 0) - id->user = str; - } - - return jid_safe(id); -} - -char *jid_full(jid id) -{ - spool s; - - if(id == NULL) - return NULL; - - /* use cached copy */ - if(id->full != NULL) - return id->full; - - s = spool_new(id->p); - - if(id->user != NULL) - spooler(s, id->user,"@",s); - - spool_add(s, id->server); - - if(id->resource != NULL) - spooler(s, "/",id->resource,s); - - id->full = spool_print(s); - return id->full; -} - -/* local utils */ -static int _jid_nullstrcmp(char *a, char *b) -{ - if(a == NULL && b == NULL) return 0; - if(a == NULL || b == NULL) return -1; - return strcmp(a,b); -} -static int _jid_nullstrcasecmp(char *a, char *b) -{ - if(a == NULL && b == NULL) return 0; - if(a == NULL || b == NULL) return -1; - return g_strcasecmp(a,b); -} - -/* suggested by Anders Qvist <quest@valdez.netg.se> */ -int jid_cmpx(jid a, jid b, int parts) -{ - if(a == NULL || b == NULL) - return -1; - - if(parts & JID_RESOURCE && _jid_nullstrcmp(a->resource, b->resource) != 0) return -1; - if(parts & JID_USER && _jid_nullstrcasecmp(a->user, b->user) != 0) return -1; - if(parts & JID_SERVER && _jid_nullstrcmp(a->server, b->server) != 0) return -1; - - return 0; -} diff --git a/protocols/jabber/jpacket.c b/protocols/jabber/jpacket.c deleted file mode 100644 index 9c7ce00d..00000000 --- a/protocols/jabber/jpacket.c +++ /dev/null @@ -1,159 +0,0 @@ -/* -------------------------------------------------------------------------- - * - * License - * - * The contents of this file are subject to the Jabber Open Source License - * Version 1.0 (the "JOSL"). You may not copy or use this file, in either - * source code or executable form, except in compliance with the JOSL. You - * may obtain a copy of the JOSL at http://www.jabber.org/ or at - * http://www.opensource.org/. - * - * Software distributed under the JOSL is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the JOSL - * for the specific language governing rights and limitations under the - * JOSL. - * - * Copyrights - * - * Portions created by or assigned to Jabber.com, Inc. are - * Copyright (c) 1999-2002 Jabber.com, Inc. All Rights Reserved. Contact - * information for Jabber.com, Inc. is available at http://www.jabber.com/. - * - * Portions Copyright (c) 1998-1999 Jeremie Miller. - * - * Acknowledgements - * - * Special thanks to the Jabber Open Source Contributors for their - * suggestions and support of Jabber. - * - * Alternatively, the contents of this file may be used under the terms of the - * GNU General Public License Version 2 or later (the "GPL"), in which case - * the provisions of the GPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * GPL and not to allow others to use your version of this file under the JOSL, - * indicate your decision by deleting the provisions above and replace them - * with the notice and other provisions required by the GPL. If you do not - * delete the provisions above, a recipient may use your version of this file - * under either the JOSL or the GPL. - * - * - * --------------------------------------------------------------------------*/ - -#include "jabber.h" -static jpacket jpacket_reset(jpacket p); - -jpacket jpacket_new(xmlnode x) -{ - jpacket p; - - if(x == NULL) - return NULL; - - p = pmalloc(xmlnode_pool(x),sizeof(_jpacket)); - p->x = x; - - return jpacket_reset(p); -} - -static jpacket jpacket_reset(jpacket p) -{ - char *val; - xmlnode x; - - x = p->x; - memset(p,0,sizeof(_jpacket)); - p->x = x; - p->p = xmlnode_pool(x); - - if(strncmp(xmlnode_get_name(x),"message",7) == 0) - { - p->type = JPACKET_MESSAGE; - }else if(strncmp(xmlnode_get_name(x),"presence",8) == 0) - { - p->type = JPACKET_PRESENCE; - val = xmlnode_get_attrib(x, "type"); - if(val == NULL) - p->subtype = JPACKET__AVAILABLE; - else if(strcmp(val,"unavailable") == 0) - p->subtype = JPACKET__UNAVAILABLE; - else if(strcmp(val,"probe") == 0) - p->subtype = JPACKET__PROBE; - else if(strcmp(val,"error") == 0) - p->subtype = JPACKET__ERROR; - else if(strcmp(val,"invisible") == 0) - p->subtype = JPACKET__INVISIBLE; - else if(*val == 's' || *val == 'u') - p->type = JPACKET_S10N; - else if(strcmp(val,"available") == 0) - { /* someone is using type='available' which is frowned upon */ - xmlnode_hide_attrib(x,"type"); - p->subtype = JPACKET__AVAILABLE; - }else - p->type = JPACKET_UNKNOWN; - }else if(strncmp(xmlnode_get_name(x),"iq",2) == 0) - { - p->type = JPACKET_IQ; - p->iq = xmlnode_get_tag(x,"?xmlns"); - p->iqns = xmlnode_get_attrib(p->iq,"xmlns"); - } - - /* set up the jids if any, flag packet as unknown if they are unparseable */ - val = xmlnode_get_attrib(x,"to"); - if(val != NULL) - if((p->to = jid_new(p->p, val)) == NULL) - p->type = JPACKET_UNKNOWN; - val = xmlnode_get_attrib(x,"from"); - if(val != NULL) - if((p->from = jid_new(p->p, val)) == NULL) - p->type = JPACKET_UNKNOWN; - - return p; -} - - -int jpacket_subtype(jpacket p) -{ - char *type; - int ret = p->subtype; - - if(ret != JPACKET__UNKNOWN) - return ret; - - ret = JPACKET__NONE; /* default, when no type attrib is specified */ - type = xmlnode_get_attrib(p->x, "type"); - if(j_strcmp(type,"error") == 0) - ret = JPACKET__ERROR; - else - switch(p->type) - { - case JPACKET_MESSAGE: - if(j_strcmp(type,"chat") == 0) - ret = JPACKET__CHAT; - else if(j_strcmp(type,"groupchat") == 0) - ret = JPACKET__GROUPCHAT; - else if(j_strcmp(type,"headline") == 0) - ret = JPACKET__HEADLINE; - break; - case JPACKET_S10N: - if(j_strcmp(type,"subscribe") == 0) - ret = JPACKET__SUBSCRIBE; - else if(j_strcmp(type,"subscribed") == 0) - ret = JPACKET__SUBSCRIBED; - else if(j_strcmp(type,"unsubscribe") == 0) - ret = JPACKET__UNSUBSCRIBE; - else if(j_strcmp(type,"unsubscribed") == 0) - ret = JPACKET__UNSUBSCRIBED; - break; - case JPACKET_IQ: - if(j_strcmp(type,"get") == 0) - ret = JPACKET__GET; - else if(j_strcmp(type,"set") == 0) - ret = JPACKET__SET; - else if(j_strcmp(type,"result") == 0) - ret = JPACKET__RESULT; - break; - } - - p->subtype = ret; - return ret; -} diff --git a/protocols/jabber/jutil.c b/protocols/jabber/jutil.c deleted file mode 100644 index dd367ac9..00000000 --- a/protocols/jabber/jutil.c +++ /dev/null @@ -1,122 +0,0 @@ -/* -------------------------------------------------------------------------- - * - * License - * - * The contents of this file are subject to the Jabber Open Source License - * Version 1.0 (the "JOSL"). You may not copy or use this file, in either - * source code or executable form, except in compliance with the JOSL. You - * may obtain a copy of the JOSL at http://www.jabber.org/ or at - * http://www.opensource.org/. - * - * Software distributed under the JOSL is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the JOSL - * for the specific language governing rights and limitations under the - * JOSL. - * - * Copyrights - * - * Portions created by or assigned to Jabber.com, Inc. are - * Copyright (c) 1999-2002 Jabber.com, Inc. All Rights Reserved. Contact - * information for Jabber.com, Inc. is available at http://www.jabber.com/. - * - * Portions Copyright (c) 1998-1999 Jeremie Miller. - * - * Acknowledgements - * - * Special thanks to the Jabber Open Source Contributors for their - * suggestions and support of Jabber. - * - * Alternatively, the contents of this file may be used under the terms of the - * GNU General Public License Version 2 or later (the "GPL"), in which case - * the provisions of the GPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * GPL and not to allow others to use your version of this file under the JOSL, - * indicate your decision by deleting the provisions above and replace them - * with the notice and other provisions required by the GPL. If you do not - * delete the provisions above, a recipient may use your version of this file - * under either the JOSL or the GPL. - * - * - * --------------------------------------------------------------------------*/ - -#include "jabber.h" -#include <glib.h> -#include "nogaim.h" - -/* util for making presence packets */ -xmlnode jutil_presnew(int type, char *to, char *status) -{ - xmlnode pres; - - pres = xmlnode_new_tag("presence"); - switch(type) - { - case JPACKET__SUBSCRIBE: - xmlnode_put_attrib(pres,"type","subscribe"); - break; - case JPACKET__UNSUBSCRIBE: - xmlnode_put_attrib(pres,"type","unsubscribe"); - break; - case JPACKET__SUBSCRIBED: - xmlnode_put_attrib(pres,"type","subscribed"); - break; - case JPACKET__UNSUBSCRIBED: - xmlnode_put_attrib(pres,"type","unsubscribed"); - break; - case JPACKET__PROBE: - xmlnode_put_attrib(pres,"type","probe"); - break; - case JPACKET__UNAVAILABLE: - xmlnode_put_attrib(pres,"type","unavailable"); - break; - case JPACKET__INVISIBLE: - xmlnode_put_attrib(pres,"type","invisible"); - break; - } - if(to != NULL) - xmlnode_put_attrib(pres,"to",to); - if(status != NULL) - xmlnode_insert_cdata(xmlnode_insert_tag(pres,"status"),status,strlen(status)); - - return pres; -} - -/* util for making IQ packets */ -xmlnode jutil_iqnew(int type, char *ns) -{ - xmlnode iq; - - iq = xmlnode_new_tag("iq"); - switch(type) - { - case JPACKET__GET: - xmlnode_put_attrib(iq,"type","get"); - break; - case JPACKET__SET: - xmlnode_put_attrib(iq,"type","set"); - break; - case JPACKET__RESULT: - xmlnode_put_attrib(iq,"type","result"); - break; - case JPACKET__ERROR: - xmlnode_put_attrib(iq,"type","error"); - break; - } - xmlnode_put_attrib(xmlnode_insert_tag(iq,"query"),"xmlns",ns); - - return iq; -} - -/* util for making stream packets */ -xmlnode jutil_header(char* xmlns, char* server) -{ - xmlnode result; - if ((xmlns == NULL)||(server == NULL)) - return NULL; - result = xmlnode_new_tag("stream:stream"); - xmlnode_put_attrib(result, "xmlns:stream", "http://etherx.jabber.org/streams"); - xmlnode_put_attrib(result, "xmlns", xmlns); - xmlnode_put_attrib(result, "to", server); - - return result; -} diff --git a/protocols/jabber/latin1tab.h b/protocols/jabber/latin1tab.h deleted file mode 100644 index 48609aa8..00000000 --- a/protocols/jabber/latin1tab.h +++ /dev/null @@ -1,62 +0,0 @@ -/* -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in -compliance with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" -basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -License for the specific language governing rights and limitations -under the License. - -The Original Code is expat. - -The Initial Developer of the Original Code is James Clark. -Portions created by James Clark are Copyright (C) 1998, 1999 -James Clark. All Rights Reserved. - -Contributor(s): - -Alternatively, the contents of this file may be used under the terms -of the GNU General Public License (the "GPL"), in which case the -provisions of the GPL are applicable instead of those above. If you -wish to allow use of your version of this file only under the terms of -the GPL and not to allow others to use your version of this file under -the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the -GPL. If you do not delete the provisions above, a recipient may use -your version of this file under either the MPL or the GPL. -*/ - -/* 0x80 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, -/* 0x84 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, -/* 0x88 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, -/* 0x8C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, -/* 0x90 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, -/* 0x94 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, -/* 0x98 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, -/* 0x9C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, -/* 0xA0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, -/* 0xA4 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, -/* 0xA8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER, -/* 0xAC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, -/* 0xB0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, -/* 0xB4 */ BT_OTHER, BT_NMSTRT, BT_OTHER, BT_NAME, -/* 0xB8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER, -/* 0xBC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, -/* 0xC0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0xC4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0xC8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0xCC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0xD0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0xD4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, -/* 0xD8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0xDC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0xE0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0xE4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0xE8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0xEC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0xF0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0xF4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, -/* 0xF8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0xFC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, diff --git a/protocols/jabber/lib.h b/protocols/jabber/lib.h deleted file mode 100644 index ce0669e5..00000000 --- a/protocols/jabber/lib.h +++ /dev/null @@ -1,343 +0,0 @@ - -#include <string.h> -#include <stdlib.h> -#include <sys/types.h> -#include <stdio.h> -#include <setjmp.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <errno.h> -#include <signal.h> -#include <stdarg.h> -#include <ctype.h> -#include <time.h> - -#include "xmlparse.h" - -int j_strcmp(const char *a, const char *b); - -/* -** Arrange to use either varargs or stdargs -*/ - -#define MAXSHORTSTR 203 /* max short string length */ -#define QUAD_T unsigned long long - -#if defined(__STDC__) || defined(_WIN32) - -#include <stdarg.h> - -# define VA_LOCAL_DECL va_list ap; -# define VA_START(f) va_start(ap, f) -# define VA_END va_end(ap) - -#else /* __STDC__ */ - -# include <varargs.h> - -# define VA_LOCAL_DECL va_list ap; -# define VA_START(f) va_start(ap) -# define VA_END va_end(ap) - -#endif /* __STDC__ */ - - -#ifndef INCL_LIB_H -#define INCL_LIB_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* --------------------------------------------------------- */ -/* */ -/* Pool-based memory management routines */ -/* */ -/* --------------------------------------------------------- */ - -#undef POOL_DEBUG -/* - flip these, this should be a prime number for top # of pools debugging -#define POOL_DEBUG 40009 -*/ - -/* pheap - singular allocation of memory */ -struct pheap -{ - void *block; - int size, used; -}; - -/* pool_cleaner - callback type which is associated - with a pool entry; invoked when the pool entry is - free'd */ -typedef void (*pool_cleaner)(void *arg); - -/* pfree - a linked list node which stores an - allocation chunk, plus a callback */ -struct pfree -{ - pool_cleaner f; - void *arg; - struct pheap *heap; - struct pfree *next; -}; - -/* pool - base node for a pool. Maintains a linked list - of pool entries (pfree) */ -typedef struct pool_struct -{ - int size; - struct pfree *cleanup; - struct pheap *heap; -#ifdef POOL_DEBUG - char name[8], zone[32]; - int lsize; -} _pool, *pool; -#define pool_new() _pool_new(ZONE) -#define pool_heap(i) _pool_new_heap(i,ZONE) -#else -} _pool, *pool; -#define pool_heap(i) _pool_new_heap(i,NULL) -#define pool_new() _pool_new(NULL) -#endif - -pool _pool_new(char *zone); /* new pool :) */ -pool _pool_new_heap(int size, char *zone); /* creates a new memory pool with an initial heap size */ -void *pmalloc(pool p, int size); /* wrapper around malloc, takes from the pool, cleaned up automatically */ -void *pmalloc_x(pool p, int size, char c); /* Wrapper around pmalloc which prefils buffer with c */ -void *pmalloco(pool p, int size); /* YAPW for zeroing the block */ -char *pstrdup(pool p, const char *src); /* wrapper around strdup, gains mem from pool */ -void pool_stat(int full); /* print to stderr the changed pools and reset */ -void pool_cleanup(pool p, pool_cleaner f, void *arg); /* calls f(arg) before the pool is freed during cleanup */ -void pool_free(pool p); /* calls the cleanup functions, frees all the data on the pool, and deletes the pool itself */ - - - - -/* --------------------------------------------------------- */ -/* */ -/* Socket helper stuff */ -/* */ -/* --------------------------------------------------------- */ -#ifndef MAXHOSTNAMELEN -#define MAXHOSTNAMELEN 64 -#endif - -#define NETSOCKET_SERVER 0 -#define NETSOCKET_CLIENT 1 -#define NETSOCKET_UDP 2 - -#ifndef WIN32 -int make_netsocket(u_short port, char *host, int type); -struct in_addr *make_addr(char *host); -int set_fd_close_on_exec(int fd, int flag); -#endif - - -/* --------------------------------------------------------- */ -/* */ -/* Hashtable functions */ -/* */ -/* --------------------------------------------------------- */ -typedef struct xhn_struct -{ - struct xhn_struct *next; - const char *key; - void *val; -} *xhn, _xhn; - -char *strescape(pool p, char *); - - -/* --------------------------------------------------------- */ -/* */ -/* String pools (spool) functions */ -/* */ -/* --------------------------------------------------------- */ -struct spool_node -{ - char *c; - struct spool_node *next; -}; - -typedef struct spool_struct -{ - pool p; - int len; - struct spool_node *last; - struct spool_node *first; -} *spool; - -spool spool_new(pool p); /* create a string pool */ -void spooler(spool s, ...); /* append all the char * args to the pool, terminate args with s again */ -char *spool_print(spool s); /* return a big string */ -void spool_add(spool s, char *str); /* add a single char to the pool */ - - -/* --------------------------------------------------------- */ -/* */ -/* xmlnodes - Document Object Model */ -/* */ -/* --------------------------------------------------------- */ -#define NTYPE_TAG 0 -#define NTYPE_ATTRIB 1 -#define NTYPE_CDATA 2 - -#define NTYPE_LAST 2 -#define NTYPE_UNDEF -1 - -/* -------------------------------------------------------------------------- - Node structure. Do not use directly! Always use accessor macros - and methods! - -------------------------------------------------------------------------- */ -typedef struct xmlnode_t -{ - char* name; - unsigned short type; - char* data; - int data_sz; - int complete; - pool p; - struct xmlnode_t* parent; - struct xmlnode_t* firstchild; - struct xmlnode_t* lastchild; - struct xmlnode_t* prev; - struct xmlnode_t* next; - struct xmlnode_t* firstattrib; - struct xmlnode_t* lastattrib; -} _xmlnode, *xmlnode; - -/* Node creation routines */ -xmlnode xmlnode_wrap(xmlnode x,const char* wrapper); -xmlnode xmlnode_new_tag(const char* name); -xmlnode xmlnode_new_tag_pool(pool p, const char* name); -xmlnode xmlnode_insert_tag(xmlnode parent, const char* name); -xmlnode xmlnode_insert_cdata(xmlnode parent, const char* CDATA, unsigned int size); -xmlnode xmlnode_insert_tag_node(xmlnode parent, xmlnode node); -xmlnode xmlnode_str(char *str, int len); -xmlnode xmlnode_dup(xmlnode x); /* duplicate x */ -xmlnode xmlnode_dup_pool(pool p, xmlnode x); - -/* Node Memory Pool */ -pool xmlnode_pool(xmlnode node); - -/* Node editing */ -void xmlnode_hide(xmlnode child); -void xmlnode_hide_attrib(xmlnode parent, const char *name); - -/* Node deletion routine, also frees the node pool! */ -void xmlnode_free(xmlnode node); - -/* Locates a child tag by name and returns it */ -xmlnode xmlnode_get_tag(xmlnode parent, const char* name); -char* xmlnode_get_tag_data(xmlnode parent, const char* name); - -/* Attribute accessors */ -void xmlnode_put_attrib(xmlnode owner, const char* name, const char* value); -char* xmlnode_get_attrib(xmlnode owner, const char* name); -void xmlnode_put_expat_attribs(xmlnode owner, const char** atts); - -/* Bastard am I, but these are fun for internal use ;-) */ -void xmlnode_put_vattrib(xmlnode owner, const char* name, void *value); -void* xmlnode_get_vattrib(xmlnode owner, const char* name); - -/* Node traversal routines */ -xmlnode xmlnode_get_firstchild(xmlnode parent); -xmlnode xmlnode_get_lastchild(xmlnode parent); -xmlnode xmlnode_get_nextsibling(xmlnode sibling); -xmlnode xmlnode_get_prevsibling(xmlnode sibling); -xmlnode xmlnode_get_parent(xmlnode node); - -/* Node information routines */ -char* xmlnode_get_name(xmlnode node); -char* xmlnode_get_data(xmlnode node); - -int xmlnode_has_children(xmlnode node); - -/* Node-to-string translation */ -char* xmlnode2str(xmlnode node); - -/********** END OLD libxode.h BEGIN OLD jabber.h *************/ - - -// #define KARMA_DEBUG -// default to disable karma -#define KARMA_READ_MAX(k) (abs(k)*100) /* how much you are allowed to read off the sock */ -#define KARMA_INIT 5 /* internal "init" value */ -#define KARMA_HEARTBEAT 2 /* seconds to register for heartbeat */ -#define KARMA_MAX 10 /* total max karma you can have */ -#define KARMA_INC 1 /* how much to increment every KARMA_HEARTBEAT seconds */ -#define KARMA_DEC 0 /* how much to penalize for reading KARMA_READ_MAX in - KARMA_HEARTBEAT seconds */ -#define KARMA_PENALTY -5 /* where you go when you hit 0 karma */ -#define KARMA_RESTORE 5 /* where you go when you payed your penelty or INIT */ -#define KARMA_RESETMETER 0 /* Reset byte meter on restore default is falst */ - -struct karma -{ - int init; /* struct initialized */ - int reset_meter; /* reset the byte meter on restore */ - int val; /* current karma value */ - long bytes; /* total bytes read (in that time period) */ - int max; /* max karma you can have */ - int inc,dec; /* how much to increment/decrement */ - int penalty,restore; /* what penalty (<0) or restore (>0) */ - time_t last_update; /* time this was last incremented */ -}; - -struct karma *karma_new(pool p); /* creates a new karma object, with default values */ -void karma_copy(struct karma *new, struct karma *old); /* makes a copy of old in new */ -void karma_increment(struct karma *k); /* inteligently increments karma */ -void karma_decrement(struct karma *k, long bytes_read); /* inteligently decrements karma */ -int karma_check(struct karma *k,long bytes_read); /* checks to see if we have good karma */ - - - -/* --------------------------------------------------------- */ -/* */ -/* Namespace constants */ -/* */ -/* --------------------------------------------------------- */ -#define NSCHECK(x,n) (j_strcmp(xmlnode_get_attrib(x,"xmlns"),n) == 0) - -#define NS_CLIENT "jabber:client" -#define NS_SERVER "jabber:server" -#define NS_AUTH "jabber:iq:auth" -#define NS_REGISTER "jabber:iq:register" -#define NS_ROSTER "jabber:iq:roster" -#define NS_OFFLINE "jabber:x:offline" -#define NS_AGENT "jabber:iq:agent" -#define NS_AGENTS "jabber:iq:agents" -#define NS_DELAY "jabber:x:delay" -#define NS_VERSION "jabber:iq:version" -#define NS_TIME "jabber:iq:time" -#define NS_VCARD "vcard-temp" -#define NS_PRIVATE "jabber:iq:private" -#define NS_SEARCH "jabber:iq:search" -#define NS_OOB "jabber:iq:oob" -#define NS_XOOB "jabber:x:oob" -#define NS_ADMIN "jabber:iq:admin" -#define NS_FILTER "jabber:iq:filter" -#define NS_AUTH_0K "jabber:iq:auth:0k" -#define NS_BROWSE "jabber:iq:browse" -#define NS_EVENT "jabber:x:event" -#define NS_CONFERENCE "jabber:iq:conference" -#define NS_SIGNED "jabber:x:signed" -#define NS_ENCRYPTED "jabber:x:encrypted" -#define NS_GATEWAY "jabber:iq:gateway" -#define NS_LAST "jabber:iq:last" -#define NS_ENVELOPE "jabber:x:envelope" -#define NS_EXPIRE "jabber:x:expire" -#define NS_XHTML "http://www.w3.org/1999/xhtml" - -#define NS_XDBGINSERT "jabber:xdb:ginsert" -#define NS_XDBNSLIST "jabber:xdb:nslist" - - - -#ifdef __cplusplus -} -#endif - -#endif /* INCL_LIB_H */ diff --git a/protocols/jabber/libxode.h b/protocols/jabber/libxode.h deleted file mode 100644 index 2ed3fd83..00000000 --- a/protocols/jabber/libxode.h +++ /dev/null @@ -1,398 +0,0 @@ -#include <string.h> -#include <stdlib.h> -#include <sys/types.h> -#include <stdio.h> -#include <setjmp.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <errno.h> -#include <signal.h> -#include <syslog.h> -#include <strings.h> -#include <unistd.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <netdb.h> -#include <arpa/inet.h> - -#ifndef __CYGWIN__ -#include <arpa/nameser.h> -#include <resolv.h> -#endif - -#include <sys/time.h> -#include <time.h> - -#include "xmlparse.h" -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif /* HAVE_CONFIG_H */ - -/* -** Arrange to use either varargs or stdargs -*/ - -#define MAXSHORTSTR 203 /* max short string length */ -#define QUAD_T unsigned long long - -#ifdef __STDC__ - -#include <stdarg.h> - -# define VA_LOCAL_DECL va_list ap; -# define VA_START(f) va_start(ap, f) -# define VA_END va_end(ap) - -#else /* __STDC__ */ - -# include <varargs.h> - -# define VA_LOCAL_DECL va_list ap; -# define VA_START(f) va_start(ap) -# define VA_END va_end(ap) - -#endif /* __STDC__ */ - - -#ifndef INCL_LIBXODE_H -#define INCL_LIBXODE_H - -#ifdef __cplusplus -extern "C" { -#endif - - -#ifndef HAVE_SNPRINTF -extern int ap_snprintf(char *, size_t, const char *, ...); -#define snprintf ap_snprintf -#endif - -#ifndef HAVE_VSNPRINTF -extern int ap_vsnprintf(char *, size_t, const char *, va_list ap); -#define vsnprintf ap_vsnprintf -#endif - -#define ZONE zonestr(__FILE__,__LINE__) -char *zonestr(char *file, int line); - -/* --------------------------------------------------------- */ -/* */ -/* Pool-based memory management routines */ -/* */ -/* --------------------------------------------------------- */ - -#undef POOL_DEBUG -/* - flip these, this should be a prime number for top # of pools debugging -#define POOL_DEBUG 40009 -*/ - -/* pheap - singular allocation of memory */ -struct pheap -{ - void *block; - int size, used; -}; - -/* pool_cleaner - callback type which is associated - with a pool entry; invoked when the pool entry is - free'd */ -typedef void (*pool_cleaner)(void *arg); - -/* pfree - a linked list node which stores an - allocation chunk, plus a callback */ -struct pfree -{ - pool_cleaner f; - void *arg; - struct pheap *heap; - struct pfree *next; -}; - -/* pool - base node for a pool. Maintains a linked list - of pool entries (pfree) */ -typedef struct pool_struct -{ - int size; - struct pfree *cleanup; - struct pheap *heap; -#ifdef POOL_DEBUG - char name[8], zone[32]; - int lsize; -} _pool, *pool; -#define pool_new() _pool_new(ZONE) -#define pool_heap(i) _pool_new_heap(i,ZONE) -#else -} _pool, *pool; -#define pool_heap(i) _pool_new_heap(i,NULL) -#define pool_new() _pool_new(NULL) -#endif - -pool _pool_new(char *zone); /* new pool :) */ -pool _pool_new_heap(int size, char *zone); /* creates a new memory pool with an initial heap size */ -void *pmalloc(pool p, int size); /* wrapper around malloc, takes from the pool, cleaned up automatically */ -void *pmalloc_x(pool p, int size, char c); /* Wrapper around pmalloc which prefils buffer with c */ -void *pmalloco(pool p, int size); /* YAPW for zeroing the block */ -char *pstrdup(pool p, const char *src); /* wrapper around strdup, gains mem from pool */ -void pool_stat(int full); /* print to stderr the changed pools and reset */ -void pool_cleanup(pool p, pool_cleaner f, void *arg); /* calls f(arg) before the pool is freed during cleanup */ -void pool_free(pool p); /* calls the cleanup functions, frees all the data on the pool, and deletes the pool itself */ - - - - -/* --------------------------------------------------------- */ -/* */ -/* Socket helper stuff */ -/* */ -/* --------------------------------------------------------- */ -#ifndef MAXHOSTNAMELEN -#define MAXHOSTNAMELEN 64 -#endif - -#define NETSOCKET_SERVER 0 -#define NETSOCKET_CLIENT 1 -#define NETSOCKET_UDP 2 - -#ifndef WIN32 -int make_netsocket(u_short port, char *host, int type); -struct in_addr *make_addr(char *host); -int set_fd_close_on_exec(int fd, int flag); -#endif - - -/* --------------------------------------------------------- */ -/* */ -/* SHA calculations */ -/* */ -/* --------------------------------------------------------- */ -#if (SIZEOF_INT == 4) -typedef unsigned int uint32; -#elif (SIZEOF_SHORT == 4) -typedef unsigned short uint32; -#else -typedef unsigned int uint32; -#endif /* HAVEUINT32 */ - -int sha_hash(int *data, int *hash); -int sha_init(int *hash); -char *shahash(char *str); /* NOT THREAD SAFE */ -void shahash_r(const char* str, char hashbuf[40]); /* USE ME */ - -int strprintsha(char *dest, int *hashval); - - -/* --------------------------------------------------------- */ -/* */ -/* Hashtable functions */ -/* */ -/* --------------------------------------------------------- */ -typedef int (*KEYHASHFUNC)(const void *key); -typedef int (*KEYCOMPAREFUNC)(const void *key1, const void *key2); -typedef int (*TABLEWALKFUNC)(void *user_data, const void *key, void *data); - -typedef void *HASHTABLE; - -HASHTABLE ghash_create(int buckets, KEYHASHFUNC hash, KEYCOMPAREFUNC cmp); -void ghash_destroy(HASHTABLE tbl); -void *ghash_get(HASHTABLE tbl, const void *key); -int ghash_put(HASHTABLE tbl, const void *key, void *value); -int ghash_remove(HASHTABLE tbl, const void *key); -int ghash_walk(HASHTABLE tbl, TABLEWALKFUNC func, void *user_data); -int str_hash_code(const char *s); - - -/* --------------------------------------------------------- */ -/* */ -/* XML escaping utils */ -/* */ -/* --------------------------------------------------------- */ -char *strescape(pool p, char *buf); /* Escape <>&'" chars */ - - -/* --------------------------------------------------------- */ -/* */ -/* String pools (spool) functions */ -/* */ -/* --------------------------------------------------------- */ -struct spool_node -{ - char *c; - struct spool_node *next; -}; - -typedef struct spool_struct -{ - pool p; - int len; - struct spool_node *last; - struct spool_node *first; -} *spool; - -spool spool_new(pool p); /* create a string pool */ -void spooler(spool s, ...); /* append all the char * args to the pool, terminate args with s again */ -char *spool_print(spool s); /* return a big string */ -void spool_add(spool s, char *str); /* add a single char to the pool */ -char *spools(pool p, ...); /* wrap all the spooler stuff in one function, the happy fun ball! */ - - -/* --------------------------------------------------------- */ -/* */ -/* xmlnodes - Document Object Model */ -/* */ -/* --------------------------------------------------------- */ -#define NTYPE_TAG 0 -#define NTYPE_ATTRIB 1 -#define NTYPE_CDATA 2 - -#define NTYPE_LAST 2 -#define NTYPE_UNDEF -1 - -/* -------------------------------------------------------------------------- - Node structure. Do not use directly! Always use accessor macros - and methods! - -------------------------------------------------------------------------- */ -typedef struct xmlnode_t -{ - char* name; - unsigned short type; - char* data; - int data_sz; - int complete; - pool p; - struct xmlnode_t* parent; - struct xmlnode_t* firstchild; - struct xmlnode_t* lastchild; - struct xmlnode_t* prev; - struct xmlnode_t* next; - struct xmlnode_t* firstattrib; - struct xmlnode_t* lastattrib; -} _xmlnode, *xmlnode; - -/* Node creation routines */ -xmlnode xmlnode_wrap(xmlnode x,const char* wrapper); -xmlnode xmlnode_new_tag(const char* name); -xmlnode xmlnode_new_tag_pool(pool p, const char* name); -xmlnode xmlnode_insert_tag(xmlnode parent, const char* name); -xmlnode xmlnode_insert_cdata(xmlnode parent, const char* CDATA, unsigned int size); -xmlnode xmlnode_insert_tag_node(xmlnode parent, xmlnode node); -void xmlnode_insert_node(xmlnode parent, xmlnode node); -xmlnode xmlnode_str(char *str, int len); -xmlnode xmlnode_file(char *file); -xmlnode xmlnode_dup(xmlnode x); /* duplicate x */ -xmlnode xmlnode_dup_pool(pool p, xmlnode x); - -/* Node Memory Pool */ -pool xmlnode_pool(xmlnode node); -xmlnode _xmlnode_new(pool p, const char *name, unsigned int type); - -/* Node editing */ -void xmlnode_hide(xmlnode child); -void xmlnode_hide_attrib(xmlnode parent, const char *name); - -/* Node deletion routine, also frees the node pool! */ -void xmlnode_free(xmlnode node); - -/* Locates a child tag by name and returns it */ -xmlnode xmlnode_get_tag(xmlnode parent, const char* name); -char* xmlnode_get_tag_data(xmlnode parent, const char* name); - -/* Attribute accessors */ -void xmlnode_put_attrib(xmlnode owner, const char* name, const char* value); -char* xmlnode_get_attrib(xmlnode owner, const char* name); -void xmlnode_put_expat_attribs(xmlnode owner, const char** atts); - -/* Bastard am I, but these are fun for internal use ;-) */ -void xmlnode_put_vattrib(xmlnode owner, const char* name, void *value); -void* xmlnode_get_vattrib(xmlnode owner, const char* name); - -/* Node traversal routines */ -xmlnode xmlnode_get_firstattrib(xmlnode parent); -xmlnode xmlnode_get_firstchild(xmlnode parent); -xmlnode xmlnode_get_lastchild(xmlnode parent); -xmlnode xmlnode_get_nextsibling(xmlnode sibling); -xmlnode xmlnode_get_prevsibling(xmlnode sibling); -xmlnode xmlnode_get_parent(xmlnode node); - -/* Node information routines */ -char* xmlnode_get_name(xmlnode node); -char* xmlnode_get_data(xmlnode node); -int xmlnode_get_datasz(xmlnode node); -int xmlnode_get_type(xmlnode node); - -int xmlnode_has_children(xmlnode node); -int xmlnode_has_attribs(xmlnode node); - -/* Node-to-string translation */ -char* xmlnode2str(xmlnode node); - -/* Node-to-terminated-string translation - -- useful for interfacing w/ scripting langs */ -char* xmlnode2tstr(xmlnode node); - -int xmlnode_cmp(xmlnode a, xmlnode b); /* compares a and b for equality */ - -int xmlnode2file(char *file, xmlnode node); /* writes node to file */ - -/* Expat callbacks */ -void expat_startElement(void* userdata, const char* name, const char** atts); -void expat_endElement(void* userdata, const char* name); -void expat_charData(void* userdata, const char* s, int len); - -/* SHA.H */ -/* - * The contents of this file are subject to the Mozilla Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is SHA 180-1 Header File - * - * The Initial Developer of the Original Code is Paul Kocher of - * Cryptography Research. Portions created by Paul Kocher are - * Copyright (C) 1995-9 by Cryptography Research, Inc. All - * Rights Reserved. - * - * Contributor(s): - * - * Paul Kocher - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License Version 2 or later (the - * "GPL"), in which case the provisions of the GPL are applicable - * instead of those above. If you wish to allow use of your - * version of this file only under the terms of the GPL and not to - * allow others to use your version of this file under the MPL, - * indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by - * the GPL. If you do not delete the provisions above, a recipient - * may use your version of this file under either the MPL or the - * GPL. - */ - -typedef struct { - unsigned long H[5]; - unsigned long W[80]; - int lenW; - unsigned long sizeHi,sizeLo; -} SHA_CTX; - - -void shaInit(SHA_CTX *ctx); -void shaUpdate(SHA_CTX *ctx, unsigned char *dataIn, int len); -void shaFinal(SHA_CTX *ctx, unsigned char hashout[20]); -void shaBlock(unsigned char *dataIn, int len, unsigned char hashout[20]); - - -/* END SHA.H */ - -#ifdef __cplusplus -} -#endif - -#endif /* INCL_LIBXODE_H */ diff --git a/protocols/jabber/log.c b/protocols/jabber/log.c deleted file mode 100644 index 86d19e1d..00000000 --- a/protocols/jabber/log.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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 - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Jabber - * Copyright (C) 1998-1999 The Jabber Team http://jabber.org/ - */ - -#include "jabber.h" -#include "log.h" - -#ifdef DEBUG - -void jdebug(char *zone, const char *msgfmt, ...) -{ - va_list ap; - static char loghdr[LOGSIZE_HDR]; - static char logmsg[LOGSIZE_TAIL]; - static int size; - - /* XXX: We may want to check the sizes eventually */ - size = g_snprintf(loghdr, LOGSIZE_HDR, "debug/%s %s\n", zone, msgfmt); - - va_start(ap, msgfmt); - size = vsnprintf(logmsg, LOGSIZE_TAIL, loghdr, ap); - - fprintf(stderr,"%s",logmsg); - - return; -} - - -#endif /* DEBUG */ diff --git a/protocols/jabber/log.h b/protocols/jabber/log.h deleted file mode 100644 index 9bce9e12..00000000 --- a/protocols/jabber/log.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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 - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Jabber - * Copyright (C) 1998-1999 The Jabber Team http://jabber.org/ - */ - -#ifndef INCL_LOG_H -#define INCL_LOG_H - -#define LOGSIZE_HDR 1024 -#define LOGSIZE_TAIL 2048 - - -#ifdef DEBUG - void jdebug(char *zone, const char *msgfmt, ...); -#else - #define jdebug if(0) warn -#endif - - - -#endif /* INCL_LOG_H */ - diff --git a/protocols/jabber/message.c b/protocols/jabber/message.c new file mode 100644 index 00000000..19edbdfd --- /dev/null +++ b/protocols/jabber/message.c @@ -0,0 +1,105 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Jabber module - Handling of message(s) (tags), etc * +* * +* Copyright 2006 Wilmer van der Gaast <wilmer@gaast.net> * +* * +* 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 along * +* with this program; if not, write to the Free Software Foundation, Inc., * +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * +* * +\***************************************************************************/ + +#include "jabber.h" + +xt_status jabber_pkt_message( struct xt_node *node, gpointer data ) +{ + struct im_connection *ic = data; + char *from = xt_find_attr( node, "from" ); + char *type = xt_find_attr( node, "type" ); + struct xt_node *body = xt_find_node( node->children, "body" ), *c; + char *s; + + if( type && strcmp( type, "error" ) == 0 ) + { + /* Handle type=error packet. */ + } + else if( type && strcmp( type, "groupchat" ) == 0 ) + { + /* TODO! */ + } + else /* "chat", "normal", "headline", no-type or whatever. Should all be pretty similar. */ + { + struct jabber_buddy *bud = NULL; + GString *fullmsg = g_string_new( "" ); + + if( ( s = strchr( from, '/' ) ) ) + { + if( ( bud = jabber_buddy_by_jid( ic, from, GET_BUDDY_EXACT ) ) ) + bud->last_act = time( NULL ); + else + *s = 0; /* We need to generate a bare JID now. */ + } + + if( type && strcmp( type, "headline" ) == 0 ) + { + c = xt_find_node( node->children, "subject" ); + g_string_append_printf( fullmsg, "Headline: %s\n", c && c->text_len > 0 ? c->text : "" ); + + /* <x xmlns="jabber:x:oob"><url>http://....</url></x> can contain a URL, it seems. */ + for( c = node->children; c; c = c->next ) + { + struct xt_node *url; + + if( ( url = xt_find_node( c->children, "url" ) ) && url->text_len > 0 ) + g_string_append_printf( fullmsg, "URL: %s\n", url->text ); + } + } + else if( ( c = xt_find_node( node->children, "subject" ) ) && c->text_len > 0 ) + { + g_string_append_printf( fullmsg, "<< \002BitlBee\002 - Message with subject: %s >>\n", c->text ); + } + + if( body && body->text_len > 0 ) /* Could be just a typing notification. */ + fullmsg = g_string_append( fullmsg, body->text ); + + if( fullmsg->len > 0 ) + imcb_buddy_msg( ic, bud ? bud->bare_jid : from, fullmsg->str, 0, 0 ); + + g_string_free( fullmsg, TRUE ); + + /* Handling of incoming typing notifications. */ + if( xt_find_node( node->children, "composing" ) ) + { + bud->flags |= JBFLAG_DOES_XEP85; + imcb_buddy_typing( ic, bud ? bud->bare_jid : from, OPT_TYPING ); + } + /* No need to send a "stopped typing" signal when there's a message. */ + else if( xt_find_node( node->children, "active" ) && ( body == NULL ) ) + { + bud->flags |= JBFLAG_DOES_XEP85; + imcb_buddy_typing( ic, bud ? bud->bare_jid : from, 0 ); + } + else if( xt_find_node( node->children, "paused" ) ) + { + bud->flags |= JBFLAG_DOES_XEP85; + imcb_buddy_typing( ic, bud ? bud->bare_jid : from, OPT_THINKING ); + } + + if( s ) + *s = '/'; /* And convert it back to a full JID. */ + } + + return XT_HANDLED; +} diff --git a/protocols/jabber/nametab.h b/protocols/jabber/nametab.h deleted file mode 100644 index b05e62c7..00000000 --- a/protocols/jabber/nametab.h +++ /dev/null @@ -1,150 +0,0 @@ -static const unsigned namingBitmap[] = { -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, -0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, -0x00000000, 0x04000000, 0x87FFFFFE, 0x07FFFFFE, -0x00000000, 0x00000000, 0xFF7FFFFF, 0xFF7FFFFF, -0xFFFFFFFF, 0x7FF3FFFF, 0xFFFFFDFE, 0x7FFFFFFF, -0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFE00F, 0xFC31FFFF, -0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF, -0xFFFFFFFF, 0xF80001FF, 0x00000003, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0xFFFFD740, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD, -0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF, -0xFFFF0003, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF, -0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE, -0x0000007F, 0x00000000, 0xFFFF0000, 0x000707FF, -0x00000000, 0x07FFFFFE, 0x000007FE, 0xFFFE0000, -0xFFFFFFFF, 0x7CFFFFFF, 0x002F7FFF, 0x00000060, -0xFFFFFFE0, 0x23FFFFFF, 0xFF000000, 0x00000003, -0xFFF99FE0, 0x03C5FDFF, 0xB0000000, 0x00030003, -0xFFF987E0, 0x036DFDFF, 0x5E000000, 0x001C0000, -0xFFFBAFE0, 0x23EDFDFF, 0x00000000, 0x00000001, -0xFFF99FE0, 0x23CDFDFF, 0xB0000000, 0x00000003, -0xD63DC7E0, 0x03BFC718, 0x00000000, 0x00000000, -0xFFFDDFE0, 0x03EFFDFF, 0x00000000, 0x00000003, -0xFFFDDFE0, 0x03EFFDFF, 0x40000000, 0x00000003, -0xFFFDDFE0, 0x03FFFDFF, 0x00000000, 0x00000003, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0xFFFFFFFE, 0x000D7FFF, 0x0000003F, 0x00000000, -0xFEF02596, 0x200D6CAE, 0x0000001F, 0x00000000, -0x00000000, 0x00000000, 0xFFFFFEFF, 0x000003FF, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0xFFFFFFFF, 0xFFFF003F, 0x007FFFFF, -0x0007DAED, 0x50000000, 0x82315001, 0x002C62AB, -0x40000000, 0xF580C900, 0x00000007, 0x02010800, -0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, -0x0FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x03FFFFFF, -0x3F3FFFFF, 0xFFFFFFFF, 0xAAFF3F3F, 0x3FFFFFFF, -0xFFFFFFFF, 0x5FDFFFFF, 0x0FCF1FDC, 0x1FDC1FFF, -0x00000000, 0x00004C40, 0x00000000, 0x00000000, -0x00000007, 0x00000000, 0x00000000, 0x00000000, -0x00000080, 0x000003FE, 0xFFFFFFFE, 0xFFFFFFFF, -0x001FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x07FFFFFF, -0xFFFFFFE0, 0x00001FFF, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, -0xFFFFFFFF, 0x0000003F, 0x00000000, 0x00000000, -0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, -0xFFFFFFFF, 0x0000000F, 0x00000000, 0x00000000, -0x00000000, 0x07FF6000, 0x87FFFFFE, 0x07FFFFFE, -0x00000000, 0x00800000, 0xFF7FFFFF, 0xFF7FFFFF, -0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF, -0xFFFFFFFF, 0xF80001FF, 0x00030003, 0x00000000, -0xFFFFFFFF, 0xFFFFFFFF, 0x0000003F, 0x00000003, -0xFFFFD7C0, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD, -0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF, -0xFFFF007B, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF, -0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE, -0xFFFE007F, 0xBBFFFFFB, 0xFFFF0016, 0x000707FF, -0x00000000, 0x07FFFFFE, 0x0007FFFF, 0xFFFF03FF, -0xFFFFFFFF, 0x7CFFFFFF, 0xFFEF7FFF, 0x03FF3DFF, -0xFFFFFFEE, 0xF3FFFFFF, 0xFF1E3FFF, 0x0000FFCF, -0xFFF99FEE, 0xD3C5FDFF, 0xB080399F, 0x0003FFCF, -0xFFF987E4, 0xD36DFDFF, 0x5E003987, 0x001FFFC0, -0xFFFBAFEE, 0xF3EDFDFF, 0x00003BBF, 0x0000FFC1, -0xFFF99FEE, 0xF3CDFDFF, 0xB0C0398F, 0x0000FFC3, -0xD63DC7EC, 0xC3BFC718, 0x00803DC7, 0x0000FF80, -0xFFFDDFEE, 0xC3EFFDFF, 0x00603DDF, 0x0000FFC3, -0xFFFDDFEC, 0xC3EFFDFF, 0x40603DDF, 0x0000FFC3, -0xFFFDDFEC, 0xC3FFFDFF, 0x00803DCF, 0x0000FFC3, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0xFFFFFFFE, 0x07FF7FFF, 0x03FF7FFF, 0x00000000, -0xFEF02596, 0x3BFF6CAE, 0x03FF3F5F, 0x00000000, -0x03000000, 0xC2A003FF, 0xFFFFFEFF, 0xFFFE03FF, -0xFEBF0FDF, 0x02FE3FFF, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x1FFF0000, 0x00000002, -0x000000A0, 0x003EFFFE, 0xFFFFFFFE, 0xFFFFFFFF, -0x661FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x77FFFFFF, -}; -static const unsigned char nmstrtPages[] = { -0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00, -0x00, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13, -0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x15, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; -static const unsigned char namePages[] = { -0x19, 0x03, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x00, -0x00, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, -0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13, -0x26, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x27, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; diff --git a/protocols/jabber/pool.c b/protocols/jabber/pool.c deleted file mode 100644 index 8b88d747..00000000 --- a/protocols/jabber/pool.c +++ /dev/null @@ -1,247 +0,0 @@ -/* -------------------------------------------------------------------------- - * - * License - * - * The contents of this file are subject to the Jabber Open Source License - * Version 1.0 (the "JOSL"). You may not copy or use this file, in either - * source code or executable form, except in compliance with the JOSL. You - * may obtain a copy of the JOSL at http://www.jabber.org/ or at - * http://www.opensource.org/. - * - * Software distributed under the JOSL is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the JOSL - * for the specific language governing rights and limitations under the - * JOSL. - * - * Copyrights - * - * Portions created by or assigned to Jabber.com, Inc. are - * Copyright (c) 1999-2002 Jabber.com, Inc. All Rights Reserved. Contact - * information for Jabber.com, Inc. is available at http://www.jabber.com/. - * - * Portions Copyright (c) 1998-1999 Jeremie Miller. - * - * Acknowledgements - * - * Special thanks to the Jabber Open Source Contributors for their - * suggestions and support of Jabber. - * - * Alternatively, the contents of this file may be used under the terms of the - * GNU General Public License Version 2 or later (the "GPL"), in which case - * the provisions of the GPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * GPL and not to allow others to use your version of this file under the JOSL, - * indicate your decision by deleting the provisions above and replace them - * with the notice and other provisions required by the GPL. If you do not - * delete the provisions above, a recipient may use your version of this file - * under either the JOSL or the GPL. - * - * - * --------------------------------------------------------------------------*/ - -#include "jabber.h" -#include "bitlbee.h" -#include <glib.h> - - -#ifdef POOL_DEBUG -int pool__total = 0; -int pool__ltotal = 0; -HASHTABLE pool__disturbed = NULL; -void *_pool__malloc(size_t size) -{ - pool__total++; - return g_malloc(size); -} -void _pool__free(void *block) -{ - pool__total--; - g_free(block); -} -#else -#define _pool__malloc g_malloc -#define _pool__free g_free -#endif - - -/* make an empty pool */ -pool _pool_new(char *zone) -{ - pool p; - while((p = _pool__malloc(sizeof(_pool))) == NULL) sleep(1); - p->cleanup = NULL; - p->heap = NULL; - p->size = 0; - -#ifdef POOL_DEBUG - p->lsize = -1; - p->zone[0] = '\0'; - strcat(p->zone,zone); - sprintf(p->name,"%X",p); - - if(pool__disturbed == NULL) - { - pool__disturbed = 1; /* reentrancy flag! */ - pool__disturbed = ghash_create(POOL_DEBUG,(KEYHASHFUNC)str_hash_code,(KEYCOMPAREFUNC)j_strcmp); - } - if(pool__disturbed != 1) - ghash_put(pool__disturbed,p->name,p); -#endif - - return p; -} - -/* free a heap */ -static void _pool_heap_free(void *arg) -{ - struct pheap *h = (struct pheap *)arg; - - _pool__free(h->block); - _pool__free(h); -} - -/* mem should always be freed last */ -static void _pool_cleanup_append(pool p, struct pfree *pf) -{ - struct pfree *cur; - - if(p->cleanup == NULL) - { - p->cleanup = pf; - return; - } - - /* fast forward to end of list */ - for(cur = p->cleanup; cur->next != NULL; cur = cur->next); - - cur->next = pf; -} - -/* create a cleanup tracker */ -static struct pfree *_pool_free(pool p, pool_cleaner f, void *arg) -{ - struct pfree *ret; - - /* make the storage for the tracker */ - while((ret = _pool__malloc(sizeof(struct pfree))) == NULL) sleep(1); - ret->f = f; - ret->arg = arg; - ret->next = NULL; - - return ret; -} - -/* create a heap and make sure it get's cleaned up */ -static struct pheap *_pool_heap(pool p, int size) -{ - struct pheap *ret; - struct pfree *clean; - - /* make the return heap */ - while((ret = _pool__malloc(sizeof(struct pheap))) == NULL) sleep(1); - while((ret->block = _pool__malloc(size)) == NULL) sleep(1); - ret->size = size; - p->size += size; - ret->used = 0; - - /* append to the cleanup list */ - clean = _pool_free(p, _pool_heap_free, (void *)ret); - clean->heap = ret; /* for future use in finding used mem for pstrdup */ - _pool_cleanup_append(p, clean); - - return ret; -} - -pool _pool_new_heap(int size, char *zone) -{ - pool p; - p = _pool_new(zone); - p->heap = _pool_heap(p,size); - return p; -} - -void *pmalloc(pool p, int size) -{ - void *block; - - if(p == NULL) - { - fprintf(stderr,"Memory Leak! [pmalloc received NULL pool, unable to track allocation, exiting]\n"); - abort(); - } - - /* if there is no heap for this pool or it's a big request, just raw, I like how we clean this :) */ - if(p->heap == NULL || size > (p->heap->size / 2)) - { - while((block = _pool__malloc(size)) == NULL) sleep(1); - p->size += size; - _pool_cleanup_append(p, _pool_free(p, _pool__free, block)); - return block; - } - - /* we have to preserve boundaries, long story :) */ - if(size >= 4) - while(p->heap->used&7) p->heap->used++; - - /* if we don't fit in the old heap, replace it */ - if(size > (p->heap->size - p->heap->used)) - p->heap = _pool_heap(p, p->heap->size); - - /* the current heap has room */ - block = (char *)p->heap->block + p->heap->used; - p->heap->used += size; - return block; -} - -void *pmalloc_x(pool p, int size, char c) -{ - void* result = pmalloc(p, size); - if (result != NULL) - memset(result, c, size); - return result; -} - -/* easy safety utility (for creating blank mem for structs, etc) */ -void *pmalloco(pool p, int size) -{ - void *block = pmalloc(p, size); - memset(block, 0, size); - return block; -} - -/* XXX efficient: move this to const char * and then loop throug the existing heaps to see if src is within a block in this pool */ -char *pstrdup(pool p, const char *src) -{ - char *ret; - - if(src == NULL) - return NULL; - - ret = pmalloc(p,strlen(src) + 1); - strcpy(ret,src); - - return ret; -} - -void pool_free(pool p) -{ - struct pfree *cur, *stub; - - if(p == NULL) return; - - cur = p->cleanup; - while(cur != NULL) - { - (*cur->f)(cur->arg); - stub = cur->next; - _pool__free(cur); - cur = stub; - } - -#ifdef POOL_DEBUG - ghash_remove(pool__disturbed,p->name); -#endif - - _pool__free(p); - -} diff --git a/protocols/jabber/presence.c b/protocols/jabber/presence.c new file mode 100644 index 00000000..ef92740a --- /dev/null +++ b/protocols/jabber/presence.c @@ -0,0 +1,176 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Jabber module - Handling of presence (tags), etc * +* * +* Copyright 2006 Wilmer van der Gaast <wilmer@gaast.net> * +* * +* 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 along * +* with this program; if not, write to the Free Software Foundation, Inc., * +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * +* * +\***************************************************************************/ + +#include "jabber.h" + +xt_status jabber_pkt_presence( struct xt_node *node, gpointer data ) +{ + struct im_connection *ic = data; + char *from = xt_find_attr( node, "from" ); + char *type = xt_find_attr( node, "type" ); /* NULL should mean the person is online. */ + struct xt_node *c; + struct jabber_buddy *bud; + char *s; + + if( !from ) + return XT_HANDLED; + + if( type == NULL ) + { + int is_away = 0; + + if( !( bud = jabber_buddy_by_jid( ic, from, GET_BUDDY_EXACT | GET_BUDDY_CREAT ) ) ) + { + if( set_getbool( &ic->irc->set, "debug" ) ) + imcb_log( ic, "WARNING: Could not handle presence information from JID: %s", from ); + return XT_HANDLED; + } + + g_free( bud->away_message ); + if( ( c = xt_find_node( node->children, "status" ) ) && c->text_len > 0 ) + bud->away_message = g_strdup( c->text ); + else + bud->away_message = NULL; + + if( ( c = xt_find_node( node->children, "show" ) ) && c->text_len > 0 ) + { + bud->away_state = (void*) jabber_away_state_by_code( c->text ); + if( strcmp( c->text, "chat" ) != 0 ) + is_away = OPT_AWAY; + } + else + { + bud->away_state = NULL; + /* Let's only set last_act if there's *no* away state, + since it could be some auto-away thingy. */ + bud->last_act = time( NULL ); + } + + if( ( c = xt_find_node( node->children, "priority" ) ) && c->text_len > 0 ) + bud->priority = atoi( c->text ); + else + bud->priority = 0; + + if( bud == jabber_buddy_by_jid( ic, bud->bare_jid, 0 ) ) + imcb_buddy_status( ic, bud->bare_jid, OPT_LOGGED_IN | is_away, + ( is_away && bud->away_state ) ? bud->away_state->full_name : NULL, + bud->away_message ); + } + else if( strcmp( type, "unavailable" ) == 0 ) + { + if( jabber_buddy_by_jid( ic, from, GET_BUDDY_EXACT ) == NULL ) + { + if( set_getbool( &ic->irc->set, "debug" ) ) + imcb_log( ic, "WARNING: Received presence information from unknown JID: %s", from ); + return XT_HANDLED; + } + + jabber_buddy_remove( ic, from ); + + if( ( s = strchr( from, '/' ) ) ) + { + *s = 0; + + /* Only count this as offline if there's no other resource + available anymore. */ + if( jabber_buddy_by_jid( ic, from, 0 ) == NULL ) + imcb_buddy_status( ic, from, 0, NULL, NULL ); + + *s = '/'; + } + else + { + imcb_buddy_status( ic, from, 0, NULL, NULL ); + } + } + else if( strcmp( type, "subscribe" ) == 0 ) + { + jabber_buddy_ask( ic, from ); + } + else if( strcmp( type, "subscribed" ) == 0 ) + { + /* Not sure about this one, actually... */ + imcb_log( ic, "%s just accepted your authorization request", from ); + } + else if( strcmp( type, "unsubscribe" ) == 0 || strcmp( type, "unsubscribed" ) == 0 ) + { + /* Do nothing here. Plenty of control freaks or over-curious + souls get excited when they can see who still has them in + their buddy list and who finally removed them. Somehow I + got the impression that those are the people who get + removed from many buddy lists for "some" reason... + + If you're one of those people, this is your chance to write + your first line of code in C... */ + } + else if( strcmp( type, "error" ) == 0 ) + { + /* What to do with it? */ + } + else + { + printf( "Received PRES from %s:\n", from ); + xt_print( node ); + } + + return XT_HANDLED; +} + +/* Whenever presence information is updated, call this function to inform the + server. */ +int presence_send_update( struct im_connection *ic ) +{ + struct jabber_data *jd = ic->proto_data; + struct xt_node *node; + char *show = jd->away_state->code; + char *status = jd->away_message; + int st; + + node = jabber_make_packet( "presence", NULL, NULL, NULL ); + xt_add_child( node, xt_new_node( "priority", set_getstr( &ic->acc->set, "priority" ), NULL ) ); + if( show && *show ) + xt_add_child( node, xt_new_node( "show", show, NULL ) ); + if( status ) + xt_add_child( node, xt_new_node( "status", status, NULL ) ); + + st = jabber_write_packet( ic, node ); + + xt_free_node( node ); + return st; +} + +/* Send a subscribe/unsubscribe request to a buddy. */ +int presence_send_request( struct im_connection *ic, char *handle, char *request ) +{ + struct xt_node *node; + int st; + + node = jabber_make_packet( "presence", NULL, NULL, NULL ); + xt_add_attr( node, "to", handle ); + xt_add_attr( node, "type", request ); + + st = jabber_write_packet( ic, node ); + + xt_free_node( node ); + return st; +} diff --git a/protocols/jabber/sasl.c b/protocols/jabber/sasl.c new file mode 100644 index 00000000..69199a8b --- /dev/null +++ b/protocols/jabber/sasl.c @@ -0,0 +1,334 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Jabber module - SASL authentication * +* * +* Copyright 2006 Wilmer van der Gaast <wilmer@gaast.net> * +* * +* 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 along * +* with this program; if not, write to the Free Software Foundation, Inc., * +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * +* * +\***************************************************************************/ + +#include "jabber.h" +#include "base64.h" + +xt_status sasl_pkt_mechanisms( struct xt_node *node, gpointer data ) +{ + struct im_connection *ic = data; + struct jabber_data *jd = ic->proto_data; + struct xt_node *c, *reply; + char *s; + int sup_plain = 0, sup_digest = 0; + + if( !sasl_supported( ic ) ) + { + /* Should abort this now, since we should already be doing + IQ authentication. Strange things happen when you try + to do both... */ + imcb_log( ic, "XMPP 1.0 non-compliant server seems to support SASL, please report this as a BitlBee bug!" ); + return XT_HANDLED; + } + + s = xt_find_attr( node, "xmlns" ); + if( !s || strcmp( s, XMLNS_SASL ) != 0 ) + { + imcb_log( ic, "Stream error while authenticating" ); + imc_logout( ic, FALSE ); + return XT_ABORT; + } + + c = node->children; + while( ( c = xt_find_node( c, "mechanism" ) ) ) + { + if( c->text && g_strcasecmp( c->text, "PLAIN" ) == 0 ) + sup_plain = 1; + if( c->text && g_strcasecmp( c->text, "DIGEST-MD5" ) == 0 ) + sup_digest = 1; + + c = c->next; + } + + if( !sup_plain && !sup_digest ) + { + imcb_error( ic, "No known SASL authentication schemes supported" ); + imc_logout( ic, FALSE ); + return XT_ABORT; + } + + reply = xt_new_node( "auth", NULL, NULL ); + xt_add_attr( reply, "xmlns", XMLNS_SASL ); + + if( sup_digest ) + { + xt_add_attr( reply, "mechanism", "DIGEST-MD5" ); + + /* The rest will be done later, when we receive a <challenge/>. */ + } + else if( sup_plain ) + { + int len; + + xt_add_attr( reply, "mechanism", "PLAIN" ); + + /* With SASL PLAIN in XMPP, the text should be b64(\0user\0pass) */ + len = strlen( jd->username ) + strlen( ic->acc->pass ) + 2; + s = g_malloc( len + 1 ); + s[0] = 0; + strcpy( s + 1, jd->username ); + strcpy( s + 2 + strlen( jd->username ), ic->acc->pass ); + reply->text = base64_encode( s, len ); + reply->text_len = strlen( reply->text ); + g_free( s ); + } + + if( !jabber_write_packet( ic, reply ) ) + { + xt_free_node( reply ); + return XT_ABORT; + } + xt_free_node( reply ); + + /* To prevent classic authentication from happening. */ + jd->flags |= JFLAG_STREAM_STARTED; + + return XT_HANDLED; +} + +static char *sasl_get_part( char *data, char *field ) +{ + int i, len; + + len = strlen( field ); + + if( g_strncasecmp( data, field, len ) == 0 && data[len] == '=' ) + { + i = strlen( field ) + 1; + } + else + { + for( i = 0; data[i]; i ++ ) + { + /* If we have a ", skip until it's closed again. */ + if( data[i] == '"' ) + { + i ++; + while( data[i] != '"' || data[i-1] == '\\' ) + i ++; + } + + /* If we got a comma, we got a new field. Check it. */ + if( data[i] == ',' && + g_strncasecmp( data + i + 1, field, len ) == 0 && + data[i+len+1] == '=' ) + { + i += len + 2; + break; + } + } + } + + if( data[i] == '"' ) + { + int j; + char *ret; + + i ++; + len = 0; + while( data[i+len] != '"' || data[i+len-1] == '\\' ) + len ++; + + ret = g_strndup( data + i, len ); + for( i = j = 0; ret[i]; i ++ ) + { + if( ret[i] == '\\' ) + { + ret[j++] = ret[++i]; + } + else + { + ret[j++] = ret[i]; + } + } + ret[j] = 0; + + return ret; + } + else if( data[i] ) + { + len = 0; + while( data[i+len] && data[i+len] != ',' ) + len ++; + + return g_strndup( data + i, len ); + } + else + { + return NULL; + } +} + +xt_status sasl_pkt_challenge( struct xt_node *node, gpointer data ) +{ + struct im_connection *ic = data; + struct jabber_data *jd = ic->proto_data; + struct xt_node *reply = NULL; + char *nonce = NULL, *realm = NULL, *cnonce = NULL, cnonce_bin[30]; + char *digest_uri = NULL; + char *dec = NULL; + char *s = NULL; + xt_status ret = XT_ABORT; + + if( node->text_len == 0 ) + goto error; + + dec = frombase64( node->text ); + + if( !( s = sasl_get_part( dec, "rspauth" ) ) ) + { + /* See RFC 2831 for for information. */ + md5_state_t A1, A2, H; + md5_byte_t A1r[16], A2r[16], Hr[16]; + char A1h[33], A2h[33], Hh[33]; + int i; + + nonce = sasl_get_part( dec, "nonce" ); + realm = sasl_get_part( dec, "realm" ); + + if( !nonce ) + goto error; + + /* Jabber.Org considers the realm part optional and doesn't + specify one. Oh well, actually they're right, but still, + don't know if this is right... */ + if( !realm ) + realm = g_strdup( jd->server ); + + random_bytes( (unsigned char *) cnonce_bin, sizeof( cnonce_bin ) ); + cnonce = base64_encode( cnonce_bin, sizeof( cnonce_bin ) ); + digest_uri = g_strdup_printf( "%s/%s", "xmpp", jd->server ); + + /* Generate the MD5 hash of username:realm:password, + I decided to call it H. */ + md5_init( &H ); + s = g_strdup_printf( "%s:%s:%s", jd->username, realm, ic->acc->pass ); + md5_append( &H, (unsigned char *) s, strlen( s ) ); + g_free( s ); + md5_finish( &H, Hr ); + + /* Now generate the hex. MD5 hash of H:nonce:cnonce, called A1. */ + md5_init( &A1 ); + s = g_strdup_printf( ":%s:%s", nonce, cnonce ); + md5_append( &A1, Hr, 16 ); + md5_append( &A1, (unsigned char *) s, strlen( s ) ); + g_free( s ); + md5_finish( &A1, A1r ); + for( i = 0; i < 16; i ++ ) + sprintf( A1h + i * 2, "%02x", A1r[i] ); + + /* A2... */ + md5_init( &A2 ); + s = g_strdup_printf( "%s:%s", "AUTHENTICATE", digest_uri ); + md5_append( &A2, (unsigned char *) s, strlen( s ) ); + g_free( s ); + md5_finish( &A2, A2r ); + for( i = 0; i < 16; i ++ ) + sprintf( A2h + i * 2, "%02x", A2r[i] ); + + /* Final result: A1:nonce:00000001:cnonce:auth:A2. Let's reuse H for it. */ + md5_init( &H ); + s = g_strdup_printf( "%s:%s:%s:%s:%s:%s", A1h, nonce, "00000001", cnonce, "auth", A2h ); + md5_append( &H, (unsigned char *) s, strlen( s ) ); + g_free( s ); + md5_finish( &H, Hr ); + for( i = 0; i < 16; i ++ ) + sprintf( Hh + i * 2, "%02x", Hr[i] ); + + /* Now build the SASL response string: */ + g_free( dec ); + dec = g_strdup_printf( "username=\"%s\",realm=\"%s\",nonce=\"%s\",cnonce=\"%s\"," + "nc=%08x,qop=auth,digest-uri=\"%s\",response=%s,charset=%s", + jd->username, realm, nonce, cnonce, 1, digest_uri, Hh, "utf-8" ); + s = tobase64( dec ); + } + else + { + /* We found rspauth, but don't really care... */ + g_free( s ); + s = NULL; + } + + reply = xt_new_node( "response", s, NULL ); + xt_add_attr( reply, "xmlns", XMLNS_SASL ); + + if( !jabber_write_packet( ic, reply ) ) + goto silent_error; + + ret = XT_HANDLED; + goto silent_error; + +error: + imcb_error( ic, "Incorrect SASL challenge received" ); + imc_logout( ic, FALSE ); + +silent_error: + g_free( digest_uri ); + g_free( cnonce ); + g_free( nonce ); + g_free( realm ); + g_free( dec ); + g_free( s ); + xt_free_node( reply ); + + return ret; +} + +xt_status sasl_pkt_result( struct xt_node *node, gpointer data ) +{ + struct im_connection *ic = data; + struct jabber_data *jd = ic->proto_data; + char *s; + + s = xt_find_attr( node, "xmlns" ); + if( !s || strcmp( s, XMLNS_SASL ) != 0 ) + { + imcb_log( ic, "Stream error while authenticating" ); + imc_logout( ic, FALSE ); + return XT_ABORT; + } + + if( strcmp( node->name, "success" ) == 0 ) + { + imcb_log( ic, "Authentication finished" ); + jd->flags |= JFLAG_AUTHENTICATED | JFLAG_STREAM_RESTART; + } + else if( strcmp( node->name, "failure" ) == 0 ) + { + imcb_error( ic, "Authentication failure" ); + imc_logout( ic, FALSE ); + return XT_ABORT; + } + + return XT_HANDLED; +} + +/* This one is needed to judge if we'll do authentication using IQ or SASL. + It's done by checking if the <stream:stream> from the server has a + version attribute. I don't know if this is the right way though... */ +gboolean sasl_supported( struct im_connection *ic ) +{ + struct jabber_data *jd = ic->proto_data; + + return ( (void*) ( jd->xt && jd->xt->root && xt_find_attr( jd->xt->root, "version" ) ) ) != NULL; +} diff --git a/protocols/jabber/str.c b/protocols/jabber/str.c deleted file mode 100644 index a8454b44..00000000 --- a/protocols/jabber/str.c +++ /dev/null @@ -1,215 +0,0 @@ -/* -------------------------------------------------------------------------- - * - * License - * - * The contents of this file are subject to the Jabber Open Source License - * Version 1.0 (the "JOSL"). You may not copy or use this file, in either - * source code or executable form, except in compliance with the JOSL. You - * may obtain a copy of the JOSL at http://www.jabber.org/ or at - * http://www.opensource.org/. - * - * Software distributed under the JOSL is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the JOSL - * for the specific language governing rights and limitations under the - * JOSL. - * - * Copyrights - * - * Portions created by or assigned to Jabber.com, Inc. are - * Copyright (c) 1999-2002 Jabber.com, Inc. All Rights Reserved. Contact - * information for Jabber.com, Inc. is available at http://www.jabber.com/. - * - * Portions Copyright (c) 1998-1999 Jeremie Miller. - * - * Acknowledgements - * - * Special thanks to the Jabber Open Source Contributors for their - * suggestions and support of Jabber. - * - * Alternatively, the contents of this file may be used under the terms of the - * GNU General Public License Version 2 or later (the "GPL"), in which case - * the provisions of the GPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * GPL and not to allow others to use your version of this file under the JOSL, - * indicate your decision by deleting the provisions above and replace them - * with the notice and other provisions required by the GPL. If you do not - * delete the provisions above, a recipient may use your version of this file - * under either the JOSL or the GPL. - * - * - * --------------------------------------------------------------------------*/ - -#include "jabber.h" -#include <glib.h> - -static char *j_strcat(char *dest, char *txt) -{ - if(!txt) return(dest); - - while(*txt) - *dest++ = *txt++; - *dest = '\0'; - - return(dest); -} - -int j_strcmp(const char *a, const char *b) -{ - if(a == NULL || b == NULL) - return -1; - - while(*a == *b && *a != '\0' && *b != '\0'){ a++; b++; } - - if(*a == *b) return 0; - - return -1; -} - -spool spool_new(pool p) -{ - spool s; - - s = pmalloc(p, sizeof(struct spool_struct)); - s->p = p; - s->len = 0; - s->last = NULL; - s->first = NULL; - return s; -} - -void spool_add(spool s, char *str) -{ - struct spool_node *sn; - int len; - - if(str == NULL) - return; - - len = strlen(str); - if(len == 0) - return; - - sn = pmalloc(s->p, sizeof(struct spool_node)); - sn->c = pstrdup(s->p, str); - sn->next = NULL; - - s->len += len; - if(s->last != NULL) - s->last->next = sn; - s->last = sn; - if(s->first == NULL) - s->first = sn; -} - -void spooler(spool s, ...) -{ - va_list ap; - char *arg = NULL; - - if(s == NULL) - return; - - VA_START(s); - - /* loop till we hfit our end flag, the first arg */ - while(1) - { - arg = va_arg(ap,char *); - if((spool)arg == s) - break; - else - spool_add(s, arg); - } - - va_end(ap); -} - -char *spool_print(spool s) -{ - char *ret,*tmp; - struct spool_node *next; - - if(s == NULL || s->len == 0 || s->first == NULL) - return NULL; - - ret = pmalloc(s->p, s->len + 1); - *ret = '\0'; - - next = s->first; - tmp = ret; - while(next != NULL) - { - tmp = j_strcat(tmp,next->c); - next = next->next; - } - - return ret; -} - -char *strescape(pool p, char *buf) -{ - int i,j,oldlen,newlen; - char *temp; - - if (p == NULL || buf == NULL) return(NULL); - - oldlen = newlen = strlen(buf); - for(i=0;i<oldlen;i++) - { - switch(buf[i]) - { - case '&': - newlen+=5; - break; - case '\'': - newlen+=6; - break; - case '\"': - newlen+=6; - break; - case '<': - newlen+=4; - break; - case '>': - newlen+=4; - break; - } - } - - if(oldlen == newlen) return buf; - - temp = pmalloc(p,newlen+1); - - if (temp==NULL) return(NULL); - - for(i=j=0;i<oldlen;i++) - { - switch(buf[i]) - { - case '&': - memcpy(&temp[j],"&",5); - j += 5; - break; - case '\'': - memcpy(&temp[j],"'",6); - j += 6; - break; - case '\"': - memcpy(&temp[j],""",6); - j += 6; - break; - case '<': - memcpy(&temp[j],"<",4); - j += 4; - break; - case '>': - memcpy(&temp[j],">",4); - j += 4; - break; - default: - temp[j++] = buf[i]; - } - } - temp[j] = '\0'; - return temp; -} diff --git a/protocols/jabber/utf8tab.h b/protocols/jabber/utf8tab.h deleted file mode 100644 index a38fe624..00000000 --- a/protocols/jabber/utf8tab.h +++ /dev/null @@ -1,63 +0,0 @@ -/* -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in -compliance with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" -basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -License for the specific language governing rights and limitations -under the License. - -The Original Code is expat. - -The Initial Developer of the Original Code is James Clark. -Portions created by James Clark are Copyright (C) 1998, 1999 -James Clark. All Rights Reserved. - -Contributor(s): - -Alternatively, the contents of this file may be used under the terms -of the GNU General Public License (the "GPL"), in which case the -provisions of the GPL are applicable instead of those above. If you -wish to allow use of your version of this file only under the terms of -the GPL and not to allow others to use your version of this file under -the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the -GPL. If you do not delete the provisions above, a recipient may use -your version of this file under either the MPL or the GPL. -*/ - - -/* 0x80 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, -/* 0x84 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, -/* 0x88 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, -/* 0x8C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, -/* 0x90 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, -/* 0x94 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, -/* 0x98 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, -/* 0x9C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, -/* 0xA0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, -/* 0xA4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, -/* 0xA8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, -/* 0xAC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, -/* 0xB0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, -/* 0xB4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, -/* 0xB8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, -/* 0xBC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, -/* 0xC0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, -/* 0xC4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, -/* 0xC8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, -/* 0xCC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, -/* 0xD0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, -/* 0xD4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, -/* 0xD8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, -/* 0xDC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, -/* 0xE0 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, -/* 0xE4 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, -/* 0xE8 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, -/* 0xEC */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, -/* 0xF0 */ BT_LEAD4, BT_LEAD4, BT_LEAD4, BT_LEAD4, -/* 0xF4 */ BT_LEAD4, BT_NONXML, BT_NONXML, BT_NONXML, -/* 0xF8 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, -/* 0xFC */ BT_NONXML, BT_NONXML, BT_MALFORM, BT_MALFORM, diff --git a/protocols/jabber/xmldef.h b/protocols/jabber/xmldef.h deleted file mode 100644 index 8b2b2308..00000000 --- a/protocols/jabber/xmldef.h +++ /dev/null @@ -1,34 +0,0 @@ -/* -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in -compliance with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" -basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -License for the specific language governing rights and limitations -under the License. - -The Original Code is expat. - -The Initial Developer of the Original Code is James Clark. -Portions created by James Clark are Copyright (C) 1998, 1999 -James Clark. All Rights Reserved. - -Contributor(s): - -Alternatively, the contents of this file may be used under the terms -of the GNU General Public License (the "GPL"), in which case the -provisions of the GPL are applicable instead of those above. If you -wish to allow use of your version of this file only under the terms of -the GPL and not to allow others to use your version of this file under -the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the -GPL. If you do not delete the provisions above, a recipient may use -your version of this file under either the MPL or the GPL. -*/ - -#include <glib.h> -#include <string.h> -#include <stdlib.h> - diff --git a/protocols/jabber/xmlnode.c b/protocols/jabber/xmlnode.c deleted file mode 100644 index 88dd4eef..00000000 --- a/protocols/jabber/xmlnode.c +++ /dev/null @@ -1,705 +0,0 @@ -/* -------------------------------------------------------------------------- - * - * License - * - * The contents of this file are subject to the Jabber Open Source License - * Version 1.0 (the "JOSL"). You may not copy or use this file, in either - * source code or executable form, except in compliance with the JOSL. You - * may obtain a copy of the JOSL at http://www.jabber.org/ or at - * http://www.opensource.org/. - * - * Software distributed under the JOSL is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the JOSL - * for the specific language governing rights and limitations under the - * JOSL. - * - * Copyrights - * - * Portions created by or assigned to Jabber.com, Inc. are - * Copyright (c) 1999-2002 Jabber.com, Inc. All Rights Reserved. Contact - * information for Jabber.com, Inc. is available at http://www.jabber.com/. - * - * Portions Copyright (c) 1998-1999 Jeremie Miller. - * - * Acknowledgements - * - * Special thanks to the Jabber Open Source Contributors for their - * suggestions and support of Jabber. - * - * Alternatively, the contents of this file may be used under the terms of the - * GNU General Public License Version 2 or later (the "GPL"), in which case - * the provisions of the GPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * GPL and not to allow others to use your version of this file under the JOSL, - * indicate your decision by deleting the provisions above and replace them - * with the notice and other provisions required by the GPL. If you do not - * delete the provisions above, a recipient may use your version of this file - * under either the JOSL or the GPL. - * - * - * --------------------------------------------------------------------------*/ - -#include "jabber.h" -#include <glib.h> - -static xmlnode xmlnode_get_firstattrib(xmlnode parent); -static int xmlnode_get_type(xmlnode node); -static void xmlnode_insert_node(xmlnode parent, xmlnode node); - -/* Internal routines */ -static xmlnode _xmlnode_new(pool p, const char* name, unsigned int type) -{ - xmlnode result = NULL; - if (type > NTYPE_LAST) - return NULL; - - if (type != NTYPE_CDATA && name == NULL) - return NULL; - - if (p == NULL) - { - p = pool_heap(1*1024); - } - - /* Allocate & zero memory */ - result = (xmlnode)pmalloco(p, sizeof(_xmlnode)); - - /* Initialize fields */ - if (type != NTYPE_CDATA) - result->name = pstrdup(p,name); - result->type = type; - result->p = p; - return result; -} - -static xmlnode _xmlnode_append_sibling(xmlnode lastsibling, const char* name, unsigned int type) -{ - xmlnode result; - - result = _xmlnode_new(xmlnode_pool(lastsibling), name, type); - if (result != NULL) - { - /* Setup sibling pointers */ - result->prev = lastsibling; - lastsibling->next = result; - } - return result; -} - -static xmlnode _xmlnode_insert(xmlnode parent, const char* name, unsigned int type) -{ - xmlnode result; - - if(parent == NULL || (type != NTYPE_CDATA && name == NULL)) return NULL; - - /* If parent->firstchild is NULL, simply create a new node for the first child */ - if (parent->firstchild == NULL) - { - result = _xmlnode_new(parent->p, name, type); - parent->firstchild = result; - } - /* Otherwise, append this to the lastchild */ - else - { - result= _xmlnode_append_sibling(parent->lastchild, name, type); - } - result->parent = parent; - parent->lastchild = result; - return result; - -} - -static xmlnode _xmlnode_search(xmlnode firstsibling, const char* name, unsigned int type) -{ - xmlnode current; - - /* Walk the sibling list, looking for a NTYPE_TAG xmlnode with - the specified name */ - current = firstsibling; - while (current != NULL) - { - if ((current->type == type) && (j_strcmp(current->name, name) == 0)) - return current; - else - current = current->next; - } - return NULL; -} - -static void _xmlnode_merge(xmlnode data) -{ - xmlnode cur; - char *merge, *scur; - int imerge; - - /* get total size of all merged cdata */ - imerge = 0; - for(cur = data; cur != NULL && cur->type == NTYPE_CDATA; cur = cur->next) - imerge += cur->data_sz; - - /* copy in current data and then spin through all of them and merge */ - scur = merge = pmalloc(data->p,imerge + 1); - for(cur = data; cur != NULL && cur->type == NTYPE_CDATA; cur = cur->next) - { - memcpy(scur,cur->data,cur->data_sz); - scur += cur->data_sz; - } - *scur = '\0'; - - /* this effectively hides all of the merged-in chunks */ - data->next = cur; - if(cur == NULL) - data->parent->lastchild = data; - else - cur->prev = data; - - /* reset data */ - data->data = merge; - data->data_sz = imerge; - -} - -static void _xmlnode_hide_sibling(xmlnode child) -{ - if(child == NULL) - return; - - if(child->prev != NULL) - child->prev->next = child->next; - if(child->next != NULL) - child->next->prev = child->prev; -} - -static void _xmlnode_tag2str(spool s, xmlnode node, int flag) -{ - xmlnode tmp; - - if(flag==0 || flag==1) - { - spooler(s,"<",xmlnode_get_name(node),s); - tmp = xmlnode_get_firstattrib(node); - while(tmp) { - spooler(s," ",xmlnode_get_name(tmp),"='",strescape(xmlnode_pool(node),xmlnode_get_data(tmp)),"'",s); - tmp = xmlnode_get_nextsibling(tmp); - } - if(flag==0) - spool_add(s,"/>"); - else - spool_add(s,">"); - } - else - { - spooler(s,"</",xmlnode_get_name(node),">",s); - } -} - -static spool _xmlnode2spool(xmlnode node) -{ - spool s; - int level=0,dir=0; - xmlnode tmp; - - if(!node || xmlnode_get_type(node)!=NTYPE_TAG) - return NULL; - - s = spool_new(xmlnode_pool(node)); - if(!s) return(NULL); - - while(1) - { - if(dir==0) - { - if(xmlnode_get_type(node) == NTYPE_TAG) - { - if(xmlnode_has_children(node)) - { - _xmlnode_tag2str(s,node,1); - node = xmlnode_get_firstchild(node); - level++; - continue; - }else{ - _xmlnode_tag2str(s,node,0); - } - }else{ - spool_add(s,strescape(xmlnode_pool(node),xmlnode_get_data(node))); - } - } - - tmp = xmlnode_get_nextsibling(node); - if(!tmp) - { - node = xmlnode_get_parent(node); - level--; - if(level>=0) _xmlnode_tag2str(s,node,2); - if(level<1) break; - dir = 1; - }else{ - node = tmp; - dir = 0; - } - } - - return s; -} - - -/* External routines */ - - -/* - * xmlnode_new_tag -- create a tag node - * Automatically creates a memory pool for the node. - * - * parameters - * name -- name of the tag - * - * returns - * a pointer to the tag node - * or NULL if it was unsuccessfull - */ -xmlnode xmlnode_new_tag(const char* name) -{ - return _xmlnode_new(NULL, name, NTYPE_TAG); -} - - -/* - * xmlnode_insert_tag -- append a child tag to a tag - * - * parameters - * parent -- pointer to the parent tag - * name -- name of the child tag - * - * returns - * a pointer to the child tag node - * or NULL if it was unsuccessfull - */ -xmlnode xmlnode_insert_tag(xmlnode parent, const char* name) -{ - return _xmlnode_insert(parent, name, NTYPE_TAG); -} - - -/* - * xmlnode_insert_cdata -- append character data to a tag - * - * parameters - * parent -- parent tag - * CDATA -- character data - * size -- size of CDATA - * or -1 for null-terminated CDATA strings - * - * returns - * a pointer to the child CDATA node - * or NULL if it was unsuccessfull - */ -xmlnode xmlnode_insert_cdata(xmlnode parent, const char* CDATA, unsigned int size) -{ - xmlnode result; - - if(CDATA == NULL || parent == NULL) - return NULL; - - if(size == -1) - size = strlen(CDATA); - - result = _xmlnode_insert(parent, NULL, NTYPE_CDATA); - if (result != NULL) - { - result->data = (char*)pmalloc(result->p, size + 1); - memcpy(result->data, CDATA, size); - result->data[size] = '\0'; - result->data_sz = size; - } - - return result; -} - - -/* - * xmlnode_get_tag -- find given tag in an xmlnode tree - * - * parameters - * parent -- pointer to the parent tag - * name -- "name" for the child tag of that name - * "name/name" for a sub child (recurses) - * "?attrib" to match the first tag with that attrib defined - * "?attrib=value" to match the first tag with that attrib and value - * "=cdata" to match the cdata contents of the child - * or any combination: "name/name/?attrib", "name=cdata", etc - * - * results - * a pointer to the tag matching search criteria - * or NULL if search was unsuccessfull - */ -xmlnode xmlnode_get_tag(xmlnode parent, const char* name) -{ - char *str, *slash, *qmark, *equals; - xmlnode step, ret; - - - if(parent == NULL || parent->firstchild == NULL || name == NULL || name == '\0') return NULL; - - if(strstr(name, "/") == NULL && strstr(name,"?") == NULL && strstr(name, "=") == NULL) - return _xmlnode_search(parent->firstchild, name, NTYPE_TAG); - - str = g_strdup(name); - slash = strstr(str, "/"); - qmark = strstr(str, "?"); - equals = strstr(str, "="); - - if(equals != NULL && (slash == NULL || equals < slash) && (qmark == NULL || equals < qmark)) - { /* of type =cdata */ - - *equals = '\0'; - equals++; - - for(step = parent->firstchild; step != NULL; step = xmlnode_get_nextsibling(step)) - { - if(xmlnode_get_type(step) != NTYPE_TAG) - continue; - - if(*str != '\0') - if(j_strcmp(xmlnode_get_name(step),str) != 0) - continue; - - if(j_strcmp(xmlnode_get_data(step),equals) != 0) - continue; - - break; - } - - g_free(str); - return step; - } - - - if(qmark != NULL && (slash == NULL || qmark < slash)) - { /* of type ?attrib */ - - *qmark = '\0'; - qmark++; - if(equals != NULL) - { - *equals = '\0'; - equals++; - } - - for(step = parent->firstchild; step != NULL; step = xmlnode_get_nextsibling(step)) - { - if(xmlnode_get_type(step) != NTYPE_TAG) - continue; - - if(*str != '\0') - if(j_strcmp(xmlnode_get_name(step),str) != 0) - continue; - - if(xmlnode_get_attrib(step,qmark) == NULL) - continue; - - if(equals != NULL && j_strcmp(xmlnode_get_attrib(step,qmark),equals) != 0) - continue; - - break; - } - - g_free(str); - return step; - } - - - *slash = '\0'; - ++slash; - - for(step = parent->firstchild; step != NULL; step = xmlnode_get_nextsibling(step)) - { - if(xmlnode_get_type(step) != NTYPE_TAG) continue; - - if(j_strcmp(xmlnode_get_name(step),str) != 0) - continue; - - ret = xmlnode_get_tag(step, slash); - if(ret != NULL) - { - g_free(str); - return ret; - } - } - - g_free(str); - return NULL; -} - - -/* return the cdata from any tag */ -char *xmlnode_get_tag_data(xmlnode parent, const char *name) -{ - xmlnode tag; - - tag = xmlnode_get_tag(parent, name); - if(tag == NULL) return NULL; - - return xmlnode_get_data(tag); -} - - -void xmlnode_put_attrib(xmlnode owner, const char* name, const char* value) -{ - xmlnode attrib; - - if(owner == NULL || name == NULL || value == NULL) return; - - /* If there are no existing attributs, allocate a new one to start - the list */ - if (owner->firstattrib == NULL) - { - attrib = _xmlnode_new(owner->p, name, NTYPE_ATTRIB); - owner->firstattrib = attrib; - owner->lastattrib = attrib; - } - else - { - attrib = _xmlnode_search(owner->firstattrib, name, NTYPE_ATTRIB); - if(attrib == NULL) - { - attrib = _xmlnode_append_sibling(owner->lastattrib, name, NTYPE_ATTRIB); - owner->lastattrib = attrib; - } - } - /* Update the value of the attribute */ - attrib->data_sz = strlen(value); - attrib->data = pstrdup(owner->p, value); - -} - -char* xmlnode_get_attrib(xmlnode owner, const char* name) -{ - xmlnode attrib; - - if (owner != NULL && owner->firstattrib != NULL) - { - attrib = _xmlnode_search(owner->firstattrib, name, NTYPE_ATTRIB); - if (attrib != NULL) - return (char*)attrib->data; - } - return NULL; -} - -static xmlnode xmlnode_get_firstattrib(xmlnode parent) -{ - if (parent != NULL) - return parent->firstattrib; - return NULL; -} - -xmlnode xmlnode_get_firstchild(xmlnode parent) -{ - if (parent != NULL) - return parent->firstchild; - return NULL; -} - -xmlnode xmlnode_get_nextsibling(xmlnode sibling) -{ - if (sibling != NULL) - return sibling->next; - return NULL; -} - -xmlnode xmlnode_get_parent(xmlnode node) -{ - if (node != NULL) - return node->parent; - return NULL; -} - -char* xmlnode_get_name(xmlnode node) -{ - if (node != NULL) - return node->name; - return NULL; -} - -char* xmlnode_get_data(xmlnode node) -{ - if(xmlnode_get_type(node) == NTYPE_TAG) /* loop till we find a CDATA in the children */ - for(node = xmlnode_get_firstchild(node); node != NULL; node = xmlnode_get_nextsibling(node)) - if(xmlnode_get_type(node) == NTYPE_CDATA) break; - - if(node == NULL) return NULL; - - /* check for a dirty node w/ unassembled cdata chunks */ - if(xmlnode_get_type(node->next) == NTYPE_CDATA) - _xmlnode_merge(node); - - return node->data; -} - -static int xmlnode_get_datasz(xmlnode node) -{ - if(xmlnode_get_type(node) != NTYPE_CDATA) return 0; - - /* check for a dirty node w/ unassembled cdata chunks */ - if(xmlnode_get_type(node->next) == NTYPE_CDATA) - _xmlnode_merge(node); - return node->data_sz; -} - -static int xmlnode_get_type(xmlnode node) -{ - if (node != NULL) - return node->type; - return NTYPE_UNDEF; -} - -int xmlnode_has_children(xmlnode node) -{ - if ((node != NULL) && (node->firstchild != NULL)) - return 1; - return 0; -} - -static int xmlnode_has_attribs(xmlnode node) -{ - if ((node != NULL) && (node->firstattrib != NULL)) - return 1; - return 0; -} - -pool xmlnode_pool(xmlnode node) -{ - if (node != NULL) - return node->p; - return (pool)NULL; -} - -void xmlnode_hide_attrib(xmlnode parent, const char *name) -{ - xmlnode attrib; - - if(parent == NULL || parent->firstattrib == NULL || name == NULL) - return; - - attrib = _xmlnode_search(parent->firstattrib, name, NTYPE_ATTRIB); - if(attrib == NULL) - return; - - /* first fix up at the child level */ - _xmlnode_hide_sibling(attrib); - - /* next fix up at the parent level */ - if(parent->firstattrib == attrib) - parent->firstattrib = attrib->next; - if(parent->lastattrib == attrib) - parent->lastattrib = attrib->prev; -} - - - -/* - * xmlnode2str -- convert given xmlnode tree into a string - * - * parameters - * node -- pointer to the xmlnode structure - * - * results - * a pointer to the created string - * or NULL if it was unsuccessfull - */ -char *xmlnode2str(xmlnode node) -{ - return spool_print(_xmlnode2spool(node)); -} - -/* loop through both a and b comparing everything, attribs, cdata, children, etc */ -static int xmlnode_cmp(xmlnode a, xmlnode b) -{ - int ret = 0; - - while(1) - { - if(a == NULL && b == NULL) - return 0; - - if(a == NULL || b == NULL) - return -1; - - if(xmlnode_get_type(a) != xmlnode_get_type(b)) - return -1; - - switch(xmlnode_get_type(a)) - { - case NTYPE_ATTRIB: - ret = j_strcmp(xmlnode_get_name(a), xmlnode_get_name(b)); - if(ret != 0) - return -1; - ret = j_strcmp(xmlnode_get_data(a), xmlnode_get_data(b)); - if(ret != 0) - return -1; - break; - case NTYPE_TAG: - ret = j_strcmp(xmlnode_get_name(a), xmlnode_get_name(b)); - if(ret != 0) - return -1; - ret = xmlnode_cmp(xmlnode_get_firstattrib(a), xmlnode_get_firstattrib(b)); - if(ret != 0) - return -1; - ret = xmlnode_cmp(xmlnode_get_firstchild(a), xmlnode_get_firstchild(b)); - if(ret != 0) - return -1; - break; - case NTYPE_CDATA: - ret = j_strcmp(xmlnode_get_data(a), xmlnode_get_data(b)); - if(ret != 0) - return -1; - } - a = xmlnode_get_nextsibling(a); - b = xmlnode_get_nextsibling(b); - } -} - - -xmlnode xmlnode_insert_tag_node(xmlnode parent, xmlnode node) -{ - xmlnode child; - - child = xmlnode_insert_tag(parent, xmlnode_get_name(node)); - if (xmlnode_has_attribs(node)) - xmlnode_insert_node(child, xmlnode_get_firstattrib(node)); - if (xmlnode_has_children(node)) - xmlnode_insert_node(child, xmlnode_get_firstchild(node)); - - return child; -} - -/* places copy of node and node's siblings in parent */ -static void xmlnode_insert_node(xmlnode parent, xmlnode node) -{ - if(node == NULL || parent == NULL) - return; - - while(node != NULL) - { - switch(xmlnode_get_type(node)) - { - case NTYPE_ATTRIB: - xmlnode_put_attrib(parent, xmlnode_get_name(node), xmlnode_get_data(node)); - break; - case NTYPE_TAG: - xmlnode_insert_tag_node(parent, node); - break; - case NTYPE_CDATA: - xmlnode_insert_cdata(parent, xmlnode_get_data(node), xmlnode_get_datasz(node)); - } - node = xmlnode_get_nextsibling(node); - } -} - - -void xmlnode_free(xmlnode node) -{ - if(node == NULL) - return; - - pool_free(node->p); -} diff --git a/protocols/jabber/xmlparse.c b/protocols/jabber/xmlparse.c deleted file mode 100644 index bbef7d59..00000000 --- a/protocols/jabber/xmlparse.c +++ /dev/null @@ -1,2640 +0,0 @@ -/* -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in -compliance with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" -basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -License for the specific language governing rights and limitations -under the License. - -The Original Code is expat. - -The Initial Developer of the Original Code is James Clark. -Portions created by James Clark are Copyright (C) 1998, 1999 -James Clark. All Rights Reserved. - -Contributor(s): - -*/ - -#include "xmldef.h" -#include "xmlparse.h" - -#ifdef XML_UNICODE -#define XML_ENCODE_MAX XML_UTF16_ENCODE_MAX -#define XmlConvert XmlUtf16Convert -#define XmlGetInternalEncoding XmlGetUtf16InternalEncoding -#define XmlGetInternalEncodingNS XmlGetUtf16InternalEncodingNS -#define XmlEncode XmlUtf16Encode -#define MUST_CONVERT(enc, s) (!(enc)->isUtf16 || (((unsigned long)s) & 1)) -typedef unsigned short ICHAR; -#else -#define XML_ENCODE_MAX XML_UTF8_ENCODE_MAX -#define XmlConvert XmlUtf8Convert -#define XmlGetInternalEncoding XmlGetUtf8InternalEncoding -#define XmlGetInternalEncodingNS XmlGetUtf8InternalEncodingNS -#define XmlEncode XmlUtf8Encode -#define MUST_CONVERT(enc, s) (!(enc)->isUtf8) -typedef char ICHAR; -#endif - - -#ifndef XML_NS - -#define XmlInitEncodingNS XmlInitEncoding -#define XmlInitUnknownEncodingNS XmlInitUnknownEncoding -#undef XmlGetInternalEncodingNS -#define XmlGetInternalEncodingNS XmlGetInternalEncoding -#define XmlParseXmlDeclNS XmlParseXmlDecl - -#endif - - -#ifdef XML_UNICODE_WCHAR_T -#define XML_T(x) L ## x -#else -#define XML_T(x) x -#endif - -/* Round up n to be a multiple of sz, where sz is a power of 2. */ -#define ROUND_UP(n, sz) (((n) + ((sz) - 1)) & ~((sz) - 1)) - -#include "xmltok.h" -#include "xmlrole.h" -#include "hashtable.h" - -#define INIT_TAG_BUF_SIZE 32 /* must be a multiple of sizeof(XML_Char) */ -#define INIT_DATA_BUF_SIZE 1024 -#define INIT_ATTS_SIZE 16 -#define INIT_BLOCK_SIZE 1024 -#define INIT_BUFFER_SIZE 1024 - -#define EXPAND_SPARE 24 - -typedef struct binding { - struct prefix *prefix; - struct binding *nextTagBinding; - struct binding *prevPrefixBinding; - const struct attribute_id *attId; - XML_Char *uri; - int uriLen; - int uriAlloc; -} BINDING; - -typedef struct prefix { - const XML_Char *name; - BINDING *binding; -} PREFIX; - -typedef struct { - const XML_Char *str; - const XML_Char *localPart; - int uriLen; -} TAG_NAME; - -typedef struct tag { - struct tag *parent; - const char *rawName; - int rawNameLength; - TAG_NAME name; - char *buf; - char *bufEnd; - BINDING *bindings; -} TAG; - -typedef struct { - const XML_Char *name; - const XML_Char *textPtr; - int textLen; - const XML_Char *systemId; - const XML_Char *base; - const XML_Char *publicId; - const XML_Char *notation; - char open; -} ENTITY; - -typedef struct block { - struct block *next; - int size; - XML_Char s[1]; -} BLOCK; - -typedef struct { - BLOCK *blocks; - BLOCK *freeBlocks; - const XML_Char *end; - XML_Char *ptr; - XML_Char *start; -} STRING_POOL; - -/* The XML_Char before the name is used to determine whether -an attribute has been specified. */ -typedef struct attribute_id { - XML_Char *name; - PREFIX *prefix; - char maybeTokenized; - char xmlns; -} ATTRIBUTE_ID; - -typedef struct { - const ATTRIBUTE_ID *id; - char isCdata; - const XML_Char *value; -} DEFAULT_ATTRIBUTE; - -typedef struct { - const XML_Char *name; - PREFIX *prefix; - int nDefaultAtts; - int allocDefaultAtts; - DEFAULT_ATTRIBUTE *defaultAtts; -} ELEMENT_TYPE; - -typedef struct { - HASH_TABLE generalEntities; - HASH_TABLE elementTypes; - HASH_TABLE attributeIds; - HASH_TABLE prefixes; - STRING_POOL pool; - int complete; - int standalone; - const XML_Char *base; - PREFIX defaultPrefix; -} DTD; - -typedef struct open_internal_entity { - const char *internalEventPtr; - const char *internalEventEndPtr; - struct open_internal_entity *next; - ENTITY *entity; -} OPEN_INTERNAL_ENTITY; - -typedef enum XML_Error Processor(XML_Parser parser, - const char *start, - const char *end, - const char **endPtr); - -static Processor prologProcessor; -static Processor prologInitProcessor; -static Processor contentProcessor; -static Processor cdataSectionProcessor; -static Processor epilogProcessor; - -static enum XML_Error -handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName); -static enum XML_Error -processXmlDecl(XML_Parser parser, int isGeneralTextEntity, const char *, const char *); -static enum XML_Error -initializeEncoding(XML_Parser parser); -static enum XML_Error -doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, - const char *start, const char *end, const char **endPtr); -static enum XML_Error -doCdataSection(XML_Parser parser, const ENCODING *, const char **startPtr, const char *end, const char **nextPtr); -static enum XML_Error storeAtts(XML_Parser parser, const ENCODING *, const char *s, - TAG_NAME *tagNamePtr, BINDING **bindingsPtr); -static -int addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, const XML_Char *uri, BINDING **bindingsPtr); -static int -defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *, int isCdata, const XML_Char *dfltValue); -static enum XML_Error -storeAttributeValue(XML_Parser parser, const ENCODING *, int isCdata, const char *, const char *, - STRING_POOL *); -static enum XML_Error -appendAttributeValue(XML_Parser parser, const ENCODING *, int isCdata, const char *, const char *, - STRING_POOL *); -static ATTRIBUTE_ID * -getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start, const char *end); -static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *); -static enum XML_Error -storeEntityValue(XML_Parser parser, const char *start, const char *end); -static int -reportProcessingInstruction(XML_Parser parser, const ENCODING *enc, const char *start, const char *end); -static int -reportComment(XML_Parser parser, const ENCODING *enc, const char *start, const char *end); -static void -reportDefault(XML_Parser parser, const ENCODING *enc, const char *start, const char *end); - -static const XML_Char *getContext(XML_Parser parser); -static void normalizePublicId(XML_Char *s); -static int dtdInit(DTD *); -static void dtdDestroy(DTD *); -static void poolInit(STRING_POOL *); -static void poolClear(STRING_POOL *); -static void poolDestroy(STRING_POOL *); -static XML_Char *poolAppend(STRING_POOL *pool, const ENCODING *enc, - const char *ptr, const char *end); -static XML_Char *poolStoreString(STRING_POOL *pool, const ENCODING *enc, - const char *ptr, const char *end); -static int poolGrow(STRING_POOL *pool); -static const XML_Char *poolCopyString(STRING_POOL *pool, const XML_Char *s); -static void *XML_GetBuffer(XML_Parser parser, int len); -static int XML_ParseBuffer(XML_Parser parser, int len, int isFinal); - -#define poolStart(pool) ((pool)->start) -#define poolEnd(pool) ((pool)->ptr) -#define poolLength(pool) ((pool)->ptr - (pool)->start) -#define poolChop(pool) ((void)--(pool->ptr)) -#define poolLastChar(pool) (((pool)->ptr)[-1]) -#define poolDiscard(pool) ((pool)->ptr = (pool)->start) -#define poolFinish(pool) ((pool)->start = (pool)->ptr) -#define poolAppendChar(pool, c) \ - (((pool)->ptr == (pool)->end && !poolGrow(pool)) \ - ? 0 \ - : ((*((pool)->ptr)++ = c), 1)) - -typedef struct { - /* The first member must be userData so that the XML_GetUserData macro works. */ - void *m_userData; - void *m_handlerArg; - char *m_buffer; - /* first character to be parsed */ - const char *m_bufferPtr; - /* past last character to be parsed */ - char *m_bufferEnd; - /* allocated end of buffer */ - const char *m_bufferLim; - long m_parseEndByteIndex; - const char *m_parseEndPtr; - XML_Char *m_dataBuf; - XML_Char *m_dataBufEnd; - XML_StartElementHandler m_startElementHandler; - XML_EndElementHandler m_endElementHandler; - XML_CharacterDataHandler m_characterDataHandler; - XML_ProcessingInstructionHandler m_processingInstructionHandler; - XML_CommentHandler m_commentHandler; - XML_StartCdataSectionHandler m_startCdataSectionHandler; - XML_EndCdataSectionHandler m_endCdataSectionHandler; - XML_DefaultHandler m_defaultHandler; - XML_UnparsedEntityDeclHandler m_unparsedEntityDeclHandler; - XML_NotationDeclHandler m_notationDeclHandler; - XML_StartNamespaceDeclHandler m_startNamespaceDeclHandler; - XML_EndNamespaceDeclHandler m_endNamespaceDeclHandler; - XML_NotStandaloneHandler m_notStandaloneHandler; - XML_ExternalEntityRefHandler m_externalEntityRefHandler; - void *m_externalEntityRefHandlerArg; - XML_UnknownEncodingHandler m_unknownEncodingHandler; - const ENCODING *m_encoding; - INIT_ENCODING m_initEncoding; - const XML_Char *m_protocolEncodingName; - int m_ns; - void *m_unknownEncodingMem; - void *m_unknownEncodingData; - void *m_unknownEncodingHandlerData; - void (*m_unknownEncodingRelease)(void *); - PROLOG_STATE m_prologState; - Processor *m_processor; - enum XML_Error m_errorCode; - const char *m_eventPtr; - const char *m_eventEndPtr; - const char *m_positionPtr; - OPEN_INTERNAL_ENTITY *m_openInternalEntities; - int m_defaultExpandInternalEntities; - int m_tagLevel; - ENTITY *m_declEntity; - const XML_Char *m_declNotationName; - const XML_Char *m_declNotationPublicId; - ELEMENT_TYPE *m_declElementType; - ATTRIBUTE_ID *m_declAttributeId; - char m_declAttributeIsCdata; - DTD m_dtd; - TAG *m_tagStack; - TAG *m_freeTagList; - BINDING *m_inheritedBindings; - BINDING *m_freeBindingList; - int m_attsSize; - int m_nSpecifiedAtts; - ATTRIBUTE *m_atts; - POSITION m_position; - STRING_POOL m_tempPool; - STRING_POOL m_temp2Pool; - char *m_groupConnector; - unsigned m_groupSize; - int m_hadExternalDoctype; - XML_Char m_namespaceSeparator; -} Parser; - -#define userData (((Parser *)parser)->m_userData) -#define handlerArg (((Parser *)parser)->m_handlerArg) -#define startElementHandler (((Parser *)parser)->m_startElementHandler) -#define endElementHandler (((Parser *)parser)->m_endElementHandler) -#define characterDataHandler (((Parser *)parser)->m_characterDataHandler) -#define processingInstructionHandler (((Parser *)parser)->m_processingInstructionHandler) -#define commentHandler (((Parser *)parser)->m_commentHandler) -#define startCdataSectionHandler (((Parser *)parser)->m_startCdataSectionHandler) -#define endCdataSectionHandler (((Parser *)parser)->m_endCdataSectionHandler) -#define defaultHandler (((Parser *)parser)->m_defaultHandler) -#define unparsedEntityDeclHandler (((Parser *)parser)->m_unparsedEntityDeclHandler) -#define notationDeclHandler (((Parser *)parser)->m_notationDeclHandler) -#define startNamespaceDeclHandler (((Parser *)parser)->m_startNamespaceDeclHandler) -#define endNamespaceDeclHandler (((Parser *)parser)->m_endNamespaceDeclHandler) -#define notStandaloneHandler (((Parser *)parser)->m_notStandaloneHandler) -#define externalEntityRefHandler (((Parser *)parser)->m_externalEntityRefHandler) -#define externalEntityRefHandlerArg (((Parser *)parser)->m_externalEntityRefHandlerArg) -#define unknownEncodingHandler (((Parser *)parser)->m_unknownEncodingHandler) -#define encoding (((Parser *)parser)->m_encoding) -#define initEncoding (((Parser *)parser)->m_initEncoding) -#define unknownEncodingMem (((Parser *)parser)->m_unknownEncodingMem) -#define unknownEncodingData (((Parser *)parser)->m_unknownEncodingData) -#define unknownEncodingHandlerData \ - (((Parser *)parser)->m_unknownEncodingHandlerData) -#define unknownEncodingRelease (((Parser *)parser)->m_unknownEncodingRelease) -#define protocolEncodingName (((Parser *)parser)->m_protocolEncodingName) -#define ns (((Parser *)parser)->m_ns) -#define prologState (((Parser *)parser)->m_prologState) -#define processor (((Parser *)parser)->m_processor) -#define errorCode (((Parser *)parser)->m_errorCode) -#define eventPtr (((Parser *)parser)->m_eventPtr) -#define eventEndPtr (((Parser *)parser)->m_eventEndPtr) -#define positionPtr (((Parser *)parser)->m_positionPtr) -#define position (((Parser *)parser)->m_position) -#define openInternalEntities (((Parser *)parser)->m_openInternalEntities) -#define defaultExpandInternalEntities (((Parser *)parser)->m_defaultExpandInternalEntities) -#define tagLevel (((Parser *)parser)->m_tagLevel) -#define buffer (((Parser *)parser)->m_buffer) -#define bufferPtr (((Parser *)parser)->m_bufferPtr) -#define bufferEnd (((Parser *)parser)->m_bufferEnd) -#define parseEndByteIndex (((Parser *)parser)->m_parseEndByteIndex) -#define parseEndPtr (((Parser *)parser)->m_parseEndPtr) -#define bufferLim (((Parser *)parser)->m_bufferLim) -#define dataBuf (((Parser *)parser)->m_dataBuf) -#define dataBufEnd (((Parser *)parser)->m_dataBufEnd) -#define dtd (((Parser *)parser)->m_dtd) -#define declEntity (((Parser *)parser)->m_declEntity) -#define declNotationName (((Parser *)parser)->m_declNotationName) -#define declNotationPublicId (((Parser *)parser)->m_declNotationPublicId) -#define declElementType (((Parser *)parser)->m_declElementType) -#define declAttributeId (((Parser *)parser)->m_declAttributeId) -#define declAttributeIsCdata (((Parser *)parser)->m_declAttributeIsCdata) -#define freeTagList (((Parser *)parser)->m_freeTagList) -#define freeBindingList (((Parser *)parser)->m_freeBindingList) -#define inheritedBindings (((Parser *)parser)->m_inheritedBindings) -#define tagStack (((Parser *)parser)->m_tagStack) -#define atts (((Parser *)parser)->m_atts) -#define attsSize (((Parser *)parser)->m_attsSize) -#define nSpecifiedAtts (((Parser *)parser)->m_nSpecifiedAtts) -#define tempPool (((Parser *)parser)->m_tempPool) -#define temp2Pool (((Parser *)parser)->m_temp2Pool) -#define groupConnector (((Parser *)parser)->m_groupConnector) -#define groupSize (((Parser *)parser)->m_groupSize) -#define hadExternalDoctype (((Parser *)parser)->m_hadExternalDoctype) -#define namespaceSeparator (((Parser *)parser)->m_namespaceSeparator) - -#ifdef _MSC_VER -#ifdef _DEBUG -Parser *asParser(XML_Parser parser) -{ - return parser; -} -#endif -#endif - -XML_Parser XML_ParserCreate(const XML_Char *encodingName) -{ - XML_Parser parser = malloc(sizeof(Parser)); - if (!parser) - return parser; - processor = prologInitProcessor; - XmlPrologStateInit(&prologState); - userData = 0; - handlerArg = 0; - startElementHandler = 0; - endElementHandler = 0; - characterDataHandler = 0; - processingInstructionHandler = 0; - commentHandler = 0; - startCdataSectionHandler = 0; - endCdataSectionHandler = 0; - defaultHandler = 0; - unparsedEntityDeclHandler = 0; - notationDeclHandler = 0; - startNamespaceDeclHandler = 0; - endNamespaceDeclHandler = 0; - notStandaloneHandler = 0; - externalEntityRefHandler = 0; - externalEntityRefHandlerArg = parser; - unknownEncodingHandler = 0; - buffer = 0; - bufferPtr = 0; - bufferEnd = 0; - parseEndByteIndex = 0; - parseEndPtr = 0; - bufferLim = 0; - declElementType = 0; - declAttributeId = 0; - declEntity = 0; - declNotationName = 0; - declNotationPublicId = 0; - memset(&position, 0, sizeof(POSITION)); - errorCode = XML_ERROR_NONE; - eventPtr = 0; - eventEndPtr = 0; - positionPtr = 0; - openInternalEntities = 0; - tagLevel = 0; - tagStack = 0; - freeTagList = 0; - freeBindingList = 0; - inheritedBindings = 0; - attsSize = INIT_ATTS_SIZE; - atts = malloc(attsSize * sizeof(ATTRIBUTE)); - nSpecifiedAtts = 0; - dataBuf = malloc(INIT_DATA_BUF_SIZE * sizeof(XML_Char)); - groupSize = 0; - groupConnector = 0; - hadExternalDoctype = 0; - unknownEncodingMem = 0; - unknownEncodingRelease = 0; - unknownEncodingData = 0; - unknownEncodingHandlerData = 0; - namespaceSeparator = '!'; - ns = 0; - poolInit(&tempPool); - poolInit(&temp2Pool); - protocolEncodingName = encodingName ? poolCopyString(&tempPool, encodingName) : 0; - if (!dtdInit(&dtd) || !atts || !dataBuf - || (encodingName && !protocolEncodingName)) { - XML_ParserFree(parser); - return 0; - } - dataBufEnd = dataBuf + INIT_DATA_BUF_SIZE; - XmlInitEncoding(&initEncoding, &encoding, 0); - return parser; -} - -static -void destroyBindings(BINDING *bindings) -{ - for (;;) { - BINDING *b = bindings; - if (!b) - break; - bindings = b->nextTagBinding; - g_free(b->uri); - g_free(b); - } -} - -void XML_ParserFree(XML_Parser parser) -{ - for (;;) { - TAG *p; - if (tagStack == 0) { - if (freeTagList == 0) - break; - tagStack = freeTagList; - freeTagList = 0; - } - p = tagStack; - tagStack = tagStack->parent; - g_free(p->buf); - destroyBindings(p->bindings); - g_free(p); - } - destroyBindings(freeBindingList); - destroyBindings(inheritedBindings); - poolDestroy(&tempPool); - poolDestroy(&temp2Pool); - dtdDestroy(&dtd); - g_free((void *)atts); - g_free(groupConnector); - g_free(buffer); - g_free(dataBuf); - g_free(unknownEncodingMem); - if (unknownEncodingRelease) - unknownEncodingRelease(unknownEncodingData); - g_free(parser); -} - -void XML_SetUserData(XML_Parser parser, void *p) -{ - if (handlerArg == userData) - handlerArg = userData = p; - else - userData = p; -} - -void XML_SetElementHandler(XML_Parser parser, - XML_StartElementHandler start, - XML_EndElementHandler end) -{ - startElementHandler = start; - endElementHandler = end; -} - -void XML_SetCharacterDataHandler(XML_Parser parser, - XML_CharacterDataHandler handler) -{ - characterDataHandler = handler; -} - -int XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) -{ - if (len == 0) { - if (!isFinal) - return 1; - positionPtr = bufferPtr; - errorCode = processor(parser, bufferPtr, parseEndPtr = bufferEnd, 0); - if (errorCode == XML_ERROR_NONE) - return 1; - eventEndPtr = eventPtr; - return 0; - } - else if (bufferPtr == bufferEnd) { - const char *end; - int nLeftOver; - parseEndByteIndex += len; - positionPtr = s; - if (isFinal) { - errorCode = processor(parser, s, parseEndPtr = s + len, 0); - if (errorCode == XML_ERROR_NONE) - return 1; - eventEndPtr = eventPtr; - return 0; - } - errorCode = processor(parser, s, parseEndPtr = s + len, &end); - if (errorCode != XML_ERROR_NONE) { - eventEndPtr = eventPtr; - return 0; - } - XmlUpdatePosition(encoding, positionPtr, end, &position); - nLeftOver = s + len - end; - if (nLeftOver) { - if (buffer == 0 || nLeftOver > bufferLim - buffer) { - /* FIXME avoid integer overflow */ - buffer = buffer == 0 ? malloc(len * 2) : realloc(buffer, len * 2); - if (!buffer) { - errorCode = XML_ERROR_NO_MEMORY; - eventPtr = eventEndPtr = 0; - return 0; - } - bufferLim = buffer + len * 2; - } - memcpy(buffer, end, nLeftOver); - bufferPtr = buffer; - bufferEnd = buffer + nLeftOver; - } - return 1; - } - else { - memcpy(XML_GetBuffer(parser, len), s, len); - return XML_ParseBuffer(parser, len, isFinal); - } -} - -static int XML_ParseBuffer(XML_Parser parser, int len, int isFinal) -{ - const char *start = bufferPtr; - positionPtr = start; - bufferEnd += len; - parseEndByteIndex += len; - errorCode = processor(parser, start, parseEndPtr = bufferEnd, - isFinal ? (const char **)0 : &bufferPtr); - if (errorCode == XML_ERROR_NONE) { - if (!isFinal) - XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position); - return 1; - } - else { - eventEndPtr = eventPtr; - return 0; - } -} - -static void *XML_GetBuffer(XML_Parser parser, int len) -{ - if (len > bufferLim - bufferEnd) { - /* FIXME avoid integer overflow */ - int neededSize = len + (bufferEnd - bufferPtr); - if (neededSize <= bufferLim - buffer) { - memmove(buffer, bufferPtr, bufferEnd - bufferPtr); - bufferEnd = buffer + (bufferEnd - bufferPtr); - bufferPtr = buffer; - } - else { - char *newBuf; - int bufferSize = bufferLim - bufferPtr; - if (bufferSize == 0) - bufferSize = INIT_BUFFER_SIZE; - do { - bufferSize *= 2; - } while (bufferSize < neededSize); - newBuf = malloc(bufferSize); - if (newBuf == 0) { - errorCode = XML_ERROR_NO_MEMORY; - return 0; - } - bufferLim = newBuf + bufferSize; - if (bufferPtr) { - memcpy(newBuf, bufferPtr, bufferEnd - bufferPtr); - g_free(buffer); - } - bufferEnd = newBuf + (bufferEnd - bufferPtr); - bufferPtr = buffer = newBuf; - } - } - return bufferEnd; -} - -static -enum XML_Error contentProcessor(XML_Parser parser, - const char *start, - const char *end, - const char **endPtr) -{ - return doContent(parser, 0, encoding, start, end, endPtr); -} - -static enum XML_Error -doContent(XML_Parser parser, - int startTagLevel, - const ENCODING *enc, - const char *s, - const char *end, - const char **nextPtr) -{ - const ENCODING *internalEnc = ns ? XmlGetInternalEncodingNS() : XmlGetInternalEncoding(); - const char **eventPP; - const char **eventEndPP; - if (enc == encoding) { - eventPP = &eventPtr; - eventEndPP = &eventEndPtr; - } - else { - eventPP = &(openInternalEntities->internalEventPtr); - eventEndPP = &(openInternalEntities->internalEventEndPtr); - } - *eventPP = s; - for (;;) { - const char *next = s; /* XmlContentTok doesn't always set the last arg */ - int tok = XmlContentTok(enc, s, end, &next); - *eventEndPP = next; - switch (tok) { - case XML_TOK_TRAILING_CR: - if (nextPtr) { - *nextPtr = s; - return XML_ERROR_NONE; - } - *eventEndPP = end; - if (characterDataHandler) { - XML_Char c = 0xA; - characterDataHandler(handlerArg, &c, 1); - } - else if (defaultHandler) - reportDefault(parser, enc, s, end); - if (startTagLevel == 0) - return XML_ERROR_NO_ELEMENTS; - if (tagLevel != startTagLevel) - return XML_ERROR_ASYNC_ENTITY; - return XML_ERROR_NONE; - case XML_TOK_NONE: - if (nextPtr) { - *nextPtr = s; - return XML_ERROR_NONE; - } - if (startTagLevel > 0) { - if (tagLevel != startTagLevel) - return XML_ERROR_ASYNC_ENTITY; - return XML_ERROR_NONE; - } - return XML_ERROR_NO_ELEMENTS; - case XML_TOK_INVALID: - *eventPP = next; - return XML_ERROR_INVALID_TOKEN; - case XML_TOK_PARTIAL: - if (nextPtr) { - *nextPtr = s; - return XML_ERROR_NONE; - } - return XML_ERROR_UNCLOSED_TOKEN; - case XML_TOK_PARTIAL_CHAR: - if (nextPtr) { - *nextPtr = s; - return XML_ERROR_NONE; - } - return XML_ERROR_PARTIAL_CHAR; - case XML_TOK_ENTITY_REF: - { - const XML_Char *name; - ENTITY *entity; - XML_Char ch = XmlPredefinedEntityName(enc, - s + enc->minBytesPerChar, - next - enc->minBytesPerChar); - if (ch) { - if (characterDataHandler) - characterDataHandler(handlerArg, &ch, 1); - else if (defaultHandler) - reportDefault(parser, enc, s, next); - break; - } - name = poolStoreString(&dtd.pool, enc, - s + enc->minBytesPerChar, - next - enc->minBytesPerChar); - if (!name) - return XML_ERROR_NO_MEMORY; - entity = (ENTITY *)lookup(&dtd.generalEntities, name, 0); - poolDiscard(&dtd.pool); - if (!entity) { - if (dtd.complete || dtd.standalone) - return XML_ERROR_UNDEFINED_ENTITY; - if (defaultHandler) - reportDefault(parser, enc, s, next); - break; - } - if (entity->open) - return XML_ERROR_RECURSIVE_ENTITY_REF; - if (entity->notation) - return XML_ERROR_BINARY_ENTITY_REF; - if (entity) { - if (entity->textPtr) { - enum XML_Error result; - OPEN_INTERNAL_ENTITY openEntity; - if (defaultHandler && !defaultExpandInternalEntities) { - reportDefault(parser, enc, s, next); - break; - } - entity->open = 1; - openEntity.next = openInternalEntities; - openInternalEntities = &openEntity; - openEntity.entity = entity; - openEntity.internalEventPtr = 0; - openEntity.internalEventEndPtr = 0; - result = doContent(parser, - tagLevel, - internalEnc, - (char *)entity->textPtr, - (char *)(entity->textPtr + entity->textLen), - 0); - entity->open = 0; - openInternalEntities = openEntity.next; - if (result) - return result; - } - else if (externalEntityRefHandler) { - const XML_Char *context; - entity->open = 1; - context = getContext(parser); - entity->open = 0; - if (!context) - return XML_ERROR_NO_MEMORY; - if (!externalEntityRefHandler(externalEntityRefHandlerArg, - context, - dtd.base, - entity->systemId, - entity->publicId)) - return XML_ERROR_EXTERNAL_ENTITY_HANDLING; - poolDiscard(&tempPool); - } - else if (defaultHandler) - reportDefault(parser, enc, s, next); - } - break; - } - case XML_TOK_START_TAG_WITH_ATTS: - if (!startElementHandler) { - enum XML_Error result = storeAtts(parser, enc, s, 0, 0); - if (result) - return result; - } - /* fall through */ - case XML_TOK_START_TAG_NO_ATTS: - { - TAG *tag; - if (freeTagList) { - tag = freeTagList; - freeTagList = freeTagList->parent; - } - else { - tag = malloc(sizeof(TAG)); - if (!tag) - return XML_ERROR_NO_MEMORY; - tag->buf = malloc(INIT_TAG_BUF_SIZE); - if (!tag->buf) - return XML_ERROR_NO_MEMORY; - tag->bufEnd = tag->buf + INIT_TAG_BUF_SIZE; - } - tag->bindings = 0; - tag->parent = tagStack; - tagStack = tag; - tag->name.localPart = 0; - tag->rawName = s + enc->minBytesPerChar; - tag->rawNameLength = XmlNameLength(enc, tag->rawName); - if (nextPtr) { - /* Need to guarantee that: - tag->buf + ROUND_UP(tag->rawNameLength, sizeof(XML_Char)) <= tag->bufEnd - sizeof(XML_Char) */ - if (tag->rawNameLength + (int)(sizeof(XML_Char) - 1) + (int)sizeof(XML_Char) > tag->bufEnd - tag->buf) { - int bufSize = tag->rawNameLength * 4; - bufSize = ROUND_UP(bufSize, sizeof(XML_Char)); - tag->buf = realloc(tag->buf, bufSize); - if (!tag->buf) - return XML_ERROR_NO_MEMORY; - tag->bufEnd = tag->buf + bufSize; - } - memcpy(tag->buf, tag->rawName, tag->rawNameLength); - tag->rawName = tag->buf; - } - ++tagLevel; - if (startElementHandler) { - enum XML_Error result; - XML_Char *toPtr; - for (;;) { - const char *rawNameEnd = tag->rawName + tag->rawNameLength; - const char *fromPtr = tag->rawName; - int bufSize; - if (nextPtr) - toPtr = (XML_Char *)(tag->buf + ROUND_UP(tag->rawNameLength, sizeof(XML_Char))); - else - toPtr = (XML_Char *)tag->buf; - tag->name.str = toPtr; - XmlConvert(enc, - &fromPtr, rawNameEnd, - (ICHAR **)&toPtr, (ICHAR *)tag->bufEnd - 1); - if (fromPtr == rawNameEnd) - break; - bufSize = (tag->bufEnd - tag->buf) << 1; - tag->buf = realloc(tag->buf, bufSize); - if (!tag->buf) - return XML_ERROR_NO_MEMORY; - tag->bufEnd = tag->buf + bufSize; - if (nextPtr) - tag->rawName = tag->buf; - } - *toPtr = XML_T('\0'); - result = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings)); - if (result) - return result; - startElementHandler(handlerArg, tag->name.str, (const XML_Char **)atts); - poolClear(&tempPool); - } - else { - tag->name.str = 0; - if (defaultHandler) - reportDefault(parser, enc, s, next); - } - break; - } - case XML_TOK_EMPTY_ELEMENT_WITH_ATTS: - if (!startElementHandler) { - enum XML_Error result = storeAtts(parser, enc, s, 0, 0); - if (result) - return result; - } - /* fall through */ - case XML_TOK_EMPTY_ELEMENT_NO_ATTS: - if (startElementHandler || endElementHandler) { - const char *rawName = s + enc->minBytesPerChar; - enum XML_Error result; - BINDING *bindings = 0; - TAG_NAME name; - name.str = poolStoreString(&tempPool, enc, rawName, - rawName + XmlNameLength(enc, rawName)); - if (!name.str) - return XML_ERROR_NO_MEMORY; - poolFinish(&tempPool); - result = storeAtts(parser, enc, s, &name, &bindings); - if (result) - return result; - poolFinish(&tempPool); - if (startElementHandler) - startElementHandler(handlerArg, name.str, (const XML_Char **)atts); - if (endElementHandler) { - if (startElementHandler) - *eventPP = *eventEndPP; - endElementHandler(handlerArg, name.str); - } - poolClear(&tempPool); - while (bindings) { - BINDING *b = bindings; - if (endNamespaceDeclHandler) - endNamespaceDeclHandler(handlerArg, b->prefix->name); - bindings = bindings->nextTagBinding; - b->nextTagBinding = freeBindingList; - freeBindingList = b; - b->prefix->binding = b->prevPrefixBinding; - } - } - else if (defaultHandler) - reportDefault(parser, enc, s, next); - if (tagLevel == 0) - return epilogProcessor(parser, next, end, nextPtr); - break; - case XML_TOK_END_TAG: - if (tagLevel == startTagLevel) - return XML_ERROR_ASYNC_ENTITY; - else { - int len; - const char *rawName; - TAG *tag = tagStack; - tagStack = tag->parent; - tag->parent = freeTagList; - freeTagList = tag; - rawName = s + enc->minBytesPerChar*2; - len = XmlNameLength(enc, rawName); - if (len != tag->rawNameLength - || memcmp(tag->rawName, rawName, len) != 0) { - *eventPP = rawName; - return XML_ERROR_TAG_MISMATCH; - } - --tagLevel; - if (endElementHandler && tag->name.str) { - if (tag->name.localPart) { - XML_Char *to = (XML_Char *)tag->name.str + tag->name.uriLen; - const XML_Char *from = tag->name.localPart; - while ((*to++ = *from++) != 0) - ; - } - endElementHandler(handlerArg, tag->name.str); - } - else if (defaultHandler) - reportDefault(parser, enc, s, next); - while (tag->bindings) { - BINDING *b = tag->bindings; - if (endNamespaceDeclHandler) - endNamespaceDeclHandler(handlerArg, b->prefix->name); - tag->bindings = tag->bindings->nextTagBinding; - b->nextTagBinding = freeBindingList; - freeBindingList = b; - b->prefix->binding = b->prevPrefixBinding; - } - if (tagLevel == 0) - return epilogProcessor(parser, next, end, nextPtr); - } - break; - case XML_TOK_CHAR_REF: - { - int n = XmlCharRefNumber(enc, s); - if (n < 0) - return XML_ERROR_BAD_CHAR_REF; - if (characterDataHandler) { - XML_Char buf[XML_ENCODE_MAX]; - characterDataHandler(handlerArg, buf, XmlEncode(n, (ICHAR *)buf)); - } - else if (defaultHandler) - reportDefault(parser, enc, s, next); - } - break; - case XML_TOK_XML_DECL: - return XML_ERROR_MISPLACED_XML_PI; - case XML_TOK_DATA_NEWLINE: - if (characterDataHandler) { - XML_Char c = 0xA; - characterDataHandler(handlerArg, &c, 1); - } - else if (defaultHandler) - reportDefault(parser, enc, s, next); - break; - case XML_TOK_CDATA_SECT_OPEN: - { - enum XML_Error result; - if (startCdataSectionHandler) - startCdataSectionHandler(handlerArg); -#if 0 - /* Suppose you doing a transformation on a document that involves - changing only the character data. You set up a defaultHandler - and a characterDataHandler. The defaultHandler simply copies - characters through. The characterDataHandler does the transformation - and writes the characters out escaping them as necessary. This case - will fail to work if we leave out the following two lines (because & - and < inside CDATA sections will be incorrectly escaped). - - However, now we have a start/endCdataSectionHandler, so it seems - easier to let the user deal with this. */ - - else if (characterDataHandler) - characterDataHandler(handlerArg, dataBuf, 0); -#endif - else if (defaultHandler) - reportDefault(parser, enc, s, next); - result = doCdataSection(parser, enc, &next, end, nextPtr); - if (!next) { - processor = cdataSectionProcessor; - return result; - } - } - break; - case XML_TOK_TRAILING_RSQB: - if (nextPtr) { - *nextPtr = s; - return XML_ERROR_NONE; - } - if (characterDataHandler) { - if (MUST_CONVERT(enc, s)) { - ICHAR *dataPtr = (ICHAR *)dataBuf; - XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd); - characterDataHandler(handlerArg, dataBuf, dataPtr - (ICHAR *)dataBuf); - } - else - characterDataHandler(handlerArg, - (XML_Char *)s, - (XML_Char *)end - (XML_Char *)s); - } - else if (defaultHandler) - reportDefault(parser, enc, s, end); - if (startTagLevel == 0) { - *eventPP = end; - return XML_ERROR_NO_ELEMENTS; - } - if (tagLevel != startTagLevel) { - *eventPP = end; - return XML_ERROR_ASYNC_ENTITY; - } - return XML_ERROR_NONE; - case XML_TOK_DATA_CHARS: - if (characterDataHandler) { - if (MUST_CONVERT(enc, s)) { - for (;;) { - ICHAR *dataPtr = (ICHAR *)dataBuf; - XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd); - *eventEndPP = s; - characterDataHandler(handlerArg, dataBuf, dataPtr - (ICHAR *)dataBuf); - if (s == next) - break; - *eventPP = s; - } - } - else - characterDataHandler(handlerArg, - (XML_Char *)s, - (XML_Char *)next - (XML_Char *)s); - } - else if (defaultHandler) - reportDefault(parser, enc, s, next); - break; - case XML_TOK_PI: - if (!reportProcessingInstruction(parser, enc, s, next)) - return XML_ERROR_NO_MEMORY; - break; - case XML_TOK_COMMENT: - if (!reportComment(parser, enc, s, next)) - return XML_ERROR_NO_MEMORY; - break; - default: - if (defaultHandler) - reportDefault(parser, enc, s, next); - break; - } - *eventPP = s = next; - } - /* not reached */ -} - -/* If tagNamePtr is non-null, build a real list of attributes, -otherwise just check the attributes for well-formedness. */ - -static enum XML_Error storeAtts(XML_Parser parser, const ENCODING *enc, - const char *s, TAG_NAME *tagNamePtr, - BINDING **bindingsPtr) -{ - ELEMENT_TYPE *elementType = 0; - int nDefaultAtts = 0; - const XML_Char **appAtts; - int attIndex = 0; - int i; - int n; - int nPrefixes = 0; - BINDING *binding; - const XML_Char *localPart; - - if (tagNamePtr) { - elementType = (ELEMENT_TYPE *)lookup(&dtd.elementTypes, tagNamePtr->str, 0); - if (!elementType) { - tagNamePtr->str = poolCopyString(&dtd.pool, tagNamePtr->str); - if (!tagNamePtr->str) - return XML_ERROR_NO_MEMORY; - elementType = (ELEMENT_TYPE *)lookup(&dtd.elementTypes, tagNamePtr->str, sizeof(ELEMENT_TYPE)); - if (!elementType) - return XML_ERROR_NO_MEMORY; - if (ns && !setElementTypePrefix(parser, elementType)) - return XML_ERROR_NO_MEMORY; - } - nDefaultAtts = elementType->nDefaultAtts; - } - n = XmlGetAttributes(enc, s, attsSize, atts); - if (n + nDefaultAtts > attsSize) { - int oldAttsSize = attsSize; - attsSize = n + nDefaultAtts + INIT_ATTS_SIZE; - atts = realloc((void *)atts, attsSize * sizeof(ATTRIBUTE)); - if (!atts) - return XML_ERROR_NO_MEMORY; - if (n > oldAttsSize) - XmlGetAttributes(enc, s, n, atts); - } - appAtts = (const XML_Char **)atts; - for (i = 0; i < n; i++) { - ATTRIBUTE_ID *attId = getAttributeId(parser, enc, atts[i].name, - atts[i].name - + XmlNameLength(enc, atts[i].name)); - if (!attId) - return XML_ERROR_NO_MEMORY; - if ((attId->name)[-1]) { - if (enc == encoding) - eventPtr = atts[i].name; - return XML_ERROR_DUPLICATE_ATTRIBUTE; - } - (attId->name)[-1] = 1; - appAtts[attIndex++] = attId->name; - if (!atts[i].normalized) { - enum XML_Error result; - int isCdata = 1; - - if (attId->maybeTokenized) { - int j; - for (j = 0; j < nDefaultAtts; j++) { - if (attId == elementType->defaultAtts[j].id) { - isCdata = elementType->defaultAtts[j].isCdata; - break; - } - } - } - - result = storeAttributeValue(parser, enc, isCdata, - atts[i].valuePtr, atts[i].valueEnd, - &tempPool); - if (result) - return result; - if (tagNamePtr) { - appAtts[attIndex] = poolStart(&tempPool); - poolFinish(&tempPool); - } - else - poolDiscard(&tempPool); - } - else if (tagNamePtr) { - appAtts[attIndex] = poolStoreString(&tempPool, enc, atts[i].valuePtr, atts[i].valueEnd); - if (appAtts[attIndex] == 0) - return XML_ERROR_NO_MEMORY; - poolFinish(&tempPool); - } - if (attId->prefix && tagNamePtr) { - if (attId->xmlns) { - if (!addBinding(parser, attId->prefix, attId, appAtts[attIndex], bindingsPtr)) - return XML_ERROR_NO_MEMORY; - --attIndex; - } - else { - attIndex++; - nPrefixes++; - (attId->name)[-1] = 2; - } - } - else - attIndex++; - } - nSpecifiedAtts = attIndex; - if (tagNamePtr) { - int j; - for (j = 0; j < nDefaultAtts; j++) { - const DEFAULT_ATTRIBUTE *da = elementType->defaultAtts + j; - if (!(da->id->name)[-1] && da->value) { - if (da->id->prefix) { - if (da->id->xmlns) { - if (!addBinding(parser, da->id->prefix, da->id, da->value, bindingsPtr)) - return XML_ERROR_NO_MEMORY; - } - else { - (da->id->name)[-1] = 2; - nPrefixes++; - appAtts[attIndex++] = da->id->name; - appAtts[attIndex++] = da->value; - } - } - else { - (da->id->name)[-1] = 1; - appAtts[attIndex++] = da->id->name; - appAtts[attIndex++] = da->value; - } - } - } - appAtts[attIndex] = 0; - } - i = 0; - if (nPrefixes) { - for (; i < attIndex; i += 2) { - if (appAtts[i][-1] == 2) { - ATTRIBUTE_ID *id; - ((XML_Char *)(appAtts[i]))[-1] = 0; - id = (ATTRIBUTE_ID *)lookup(&dtd.attributeIds, appAtts[i], 0); - if (id->prefix->binding) { - int j; - const BINDING *b = id->prefix->binding; - const XML_Char *s = appAtts[i]; - for (j = 0; j < b->uriLen; j++) { - if (!poolAppendChar(&tempPool, b->uri[j])) - return XML_ERROR_NO_MEMORY; - } - while (*s++ != ':') - ; - do { - if (!poolAppendChar(&tempPool, *s)) - return XML_ERROR_NO_MEMORY; - } while (*s++); - appAtts[i] = poolStart(&tempPool); - poolFinish(&tempPool); - } - if (!--nPrefixes) - break; - } - else - ((XML_Char *)(appAtts[i]))[-1] = 0; - } - } - for (; i < attIndex; i += 2) - ((XML_Char *)(appAtts[i]))[-1] = 0; - if (!tagNamePtr) - return XML_ERROR_NONE; - for (binding = *bindingsPtr; binding; binding = binding->nextTagBinding) - binding->attId->name[-1] = 0; - if (elementType->prefix) { - binding = elementType->prefix->binding; - if (!binding) - return XML_ERROR_NONE; - localPart = tagNamePtr->str; - while (*localPart++ != XML_T(':')) - ; - } - else if (dtd.defaultPrefix.binding) { - binding = dtd.defaultPrefix.binding; - localPart = tagNamePtr->str; - } - else - return XML_ERROR_NONE; - tagNamePtr->localPart = localPart; - tagNamePtr->uriLen = binding->uriLen; - i = binding->uriLen; - do { - if (i == binding->uriAlloc) { - binding->uri = realloc(binding->uri, binding->uriAlloc *= 2); - if (!binding->uri) - return XML_ERROR_NO_MEMORY; - } - binding->uri[i++] = *localPart; - } while (*localPart++); - tagNamePtr->str = binding->uri; - return XML_ERROR_NONE; -} - -static -int addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, const XML_Char *uri, BINDING **bindingsPtr) -{ - BINDING *b; - int len; - for (len = 0; uri[len]; len++) - ; - if (namespaceSeparator) - len++; - if (freeBindingList) { - b = freeBindingList; - if (len > b->uriAlloc) { - b->uri = realloc(b->uri, len + EXPAND_SPARE); - if (!b->uri) - return 0; - b->uriAlloc = len + EXPAND_SPARE; - } - freeBindingList = b->nextTagBinding; - } - else { - b = malloc(sizeof(BINDING)); - if (!b) - return 0; - b->uri = malloc(sizeof(XML_Char) * len + EXPAND_SPARE); - if (!b->uri) { - g_free(b); - return 0; - } - b->uriAlloc = len; - } - b->uriLen = len; - memcpy(b->uri, uri, len * sizeof(XML_Char)); - if (namespaceSeparator) - b->uri[len - 1] = namespaceSeparator; - b->prefix = prefix; - b->attId = attId; - b->prevPrefixBinding = prefix->binding; - if (*uri == XML_T('\0') && prefix == &dtd.defaultPrefix) - prefix->binding = 0; - else - prefix->binding = b; - b->nextTagBinding = *bindingsPtr; - *bindingsPtr = b; - if (startNamespaceDeclHandler) - startNamespaceDeclHandler(handlerArg, prefix->name, - prefix->binding ? uri : 0); - return 1; -} - -/* The idea here is to avoid using stack for each CDATA section when -the whole file is parsed with one call. */ - -static -enum XML_Error cdataSectionProcessor(XML_Parser parser, - const char *start, - const char *end, - const char **endPtr) -{ - enum XML_Error result = doCdataSection(parser, encoding, &start, end, endPtr); - if (start) { - processor = contentProcessor; - return contentProcessor(parser, start, end, endPtr); - } - return result; -} - -/* startPtr gets set to non-null is the section is closed, and to null if -the section is not yet closed. */ - -static -enum XML_Error doCdataSection(XML_Parser parser, - const ENCODING *enc, - const char **startPtr, - const char *end, - const char **nextPtr) -{ - const char *s = *startPtr; - const char **eventPP; - const char **eventEndPP; - if (enc == encoding) { - eventPP = &eventPtr; - *eventPP = s; - eventEndPP = &eventEndPtr; - } - else { - eventPP = &(openInternalEntities->internalEventPtr); - eventEndPP = &(openInternalEntities->internalEventEndPtr); - } - *eventPP = s; - *startPtr = 0; - for (;;) { - const char *next; - int tok = XmlCdataSectionTok(enc, s, end, &next); - *eventEndPP = next; - switch (tok) { - case XML_TOK_CDATA_SECT_CLOSE: - if (endCdataSectionHandler) - endCdataSectionHandler(handlerArg); -#if 0 - /* see comment under XML_TOK_CDATA_SECT_OPEN */ - else if (characterDataHandler) - characterDataHandler(handlerArg, dataBuf, 0); -#endif - else if (defaultHandler) - reportDefault(parser, enc, s, next); - *startPtr = next; - return XML_ERROR_NONE; - case XML_TOK_DATA_NEWLINE: - if (characterDataHandler) { - XML_Char c = 0xA; - characterDataHandler(handlerArg, &c, 1); - } - else if (defaultHandler) - reportDefault(parser, enc, s, next); - break; - case XML_TOK_DATA_CHARS: - if (characterDataHandler) { - if (MUST_CONVERT(enc, s)) { - for (;;) { - ICHAR *dataPtr = (ICHAR *)dataBuf; - XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd); - *eventEndPP = next; - characterDataHandler(handlerArg, dataBuf, dataPtr - (ICHAR *)dataBuf); - if (s == next) - break; - *eventPP = s; - } - } - else - characterDataHandler(handlerArg, - (XML_Char *)s, - (XML_Char *)next - (XML_Char *)s); - } - else if (defaultHandler) - reportDefault(parser, enc, s, next); - break; - case XML_TOK_INVALID: - *eventPP = next; - return XML_ERROR_INVALID_TOKEN; - case XML_TOK_PARTIAL_CHAR: - if (nextPtr) { - *nextPtr = s; - return XML_ERROR_NONE; - } - return XML_ERROR_PARTIAL_CHAR; - case XML_TOK_PARTIAL: - case XML_TOK_NONE: - if (nextPtr) { - *nextPtr = s; - return XML_ERROR_NONE; - } - return XML_ERROR_UNCLOSED_CDATA_SECTION; - default: - abort(); - } - *eventPP = s = next; - } - /* not reached */ -} - -static enum XML_Error -initializeEncoding(XML_Parser parser) -{ - const char *s; -#ifdef XML_UNICODE - char encodingBuf[128]; - if (!protocolEncodingName) - s = 0; - else { - int i; - for (i = 0; protocolEncodingName[i]; i++) { - if (i == sizeof(encodingBuf) - 1 - || protocolEncodingName[i] >= 0x80 - || protocolEncodingName[i] < 0) { - encodingBuf[0] = '\0'; - break; - } - encodingBuf[i] = (char)protocolEncodingName[i]; - } - encodingBuf[i] = '\0'; - s = encodingBuf; - } -#else -s = protocolEncodingName; -#endif - if (ns ? XmlInitEncodingNS(&initEncoding, &encoding, s) : XmlInitEncoding(&initEncoding, &encoding, s)) - return XML_ERROR_NONE; - return handleUnknownEncoding(parser, protocolEncodingName); -} - -static enum XML_Error -processXmlDecl(XML_Parser parser, int isGeneralTextEntity, - const char *s, const char *next) -{ - const char *encodingName = 0; - const ENCODING *newEncoding = 0; - const char *version; - int standalone = -1; - if (!(ns - ? XmlParseXmlDeclNS(isGeneralTextEntity, - encoding, - s, - next, - &eventPtr, - &version, - &encodingName, - &newEncoding, - &standalone) - : XmlParseXmlDecl(isGeneralTextEntity, - encoding, - s, - next, - &eventPtr, - &version, - &encodingName, - &newEncoding, - &standalone))) - return XML_ERROR_SYNTAX; - if (!isGeneralTextEntity && standalone == 1) - dtd.standalone = 1; - if (defaultHandler) - reportDefault(parser, encoding, s, next); - if (!protocolEncodingName) { - if (newEncoding) { - if (newEncoding->minBytesPerChar != encoding->minBytesPerChar) { - eventPtr = encodingName; - return XML_ERROR_INCORRECT_ENCODING; - } - encoding = newEncoding; - } - else if (encodingName) { - enum XML_Error result; - const XML_Char *s = poolStoreString(&tempPool, - encoding, - encodingName, - encodingName - + XmlNameLength(encoding, encodingName)); - if (!s) - return XML_ERROR_NO_MEMORY; - result = handleUnknownEncoding(parser, s); - poolDiscard(&tempPool); - if (result == XML_ERROR_UNKNOWN_ENCODING) - eventPtr = encodingName; - return result; - } - } - return XML_ERROR_NONE; -} - -static enum XML_Error -handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName) -{ - if (unknownEncodingHandler) { - XML_Encoding info; - int i; - for (i = 0; i < 256; i++) - info.map[i] = -1; - info.convert = 0; - info.data = 0; - info.release = 0; - if (unknownEncodingHandler(unknownEncodingHandlerData, encodingName, &info)) { - ENCODING *enc; - unknownEncodingMem = malloc(XmlSizeOfUnknownEncoding()); - if (!unknownEncodingMem) { - if (info.release) - info.release(info.data); - return XML_ERROR_NO_MEMORY; - } - enc = (ns - ? XmlInitUnknownEncodingNS(unknownEncodingMem, - info.map, - info.convert, - info.data) - : XmlInitUnknownEncoding(unknownEncodingMem, - info.map, - info.convert, - info.data)); - if (enc) { - unknownEncodingData = info.data; - unknownEncodingRelease = info.release; - encoding = enc; - return XML_ERROR_NONE; - } - } - if (info.release) - info.release(info.data); - } - return XML_ERROR_UNKNOWN_ENCODING; -} - -static enum XML_Error -prologInitProcessor(XML_Parser parser, - const char *s, - const char *end, - const char **nextPtr) -{ - enum XML_Error result = initializeEncoding(parser); - if (result != XML_ERROR_NONE) - return result; - processor = prologProcessor; - return prologProcessor(parser, s, end, nextPtr); -} - -static enum XML_Error -prologProcessor(XML_Parser parser, - const char *s, - const char *end, - const char **nextPtr) -{ - for (;;) { - const char *next; - int tok = XmlPrologTok(encoding, s, end, &next); - if (tok <= 0) { - if (nextPtr != 0 && tok != XML_TOK_INVALID) { - *nextPtr = s; - return XML_ERROR_NONE; - } - switch (tok) { - case XML_TOK_INVALID: - eventPtr = next; - return XML_ERROR_INVALID_TOKEN; - case XML_TOK_NONE: - return XML_ERROR_NO_ELEMENTS; - case XML_TOK_PARTIAL: - return XML_ERROR_UNCLOSED_TOKEN; - case XML_TOK_PARTIAL_CHAR: - return XML_ERROR_PARTIAL_CHAR; - case XML_TOK_TRAILING_CR: - eventPtr = s + encoding->minBytesPerChar; - return XML_ERROR_NO_ELEMENTS; - default: - abort(); - } - } - switch (XmlTokenRole(&prologState, tok, s, next, encoding)) { - case XML_ROLE_XML_DECL: - { - enum XML_Error result = processXmlDecl(parser, 0, s, next); - if (result != XML_ERROR_NONE) - return result; - } - break; - case XML_ROLE_DOCTYPE_SYSTEM_ID: - if (!dtd.standalone - && notStandaloneHandler - && !notStandaloneHandler(handlerArg)) - return XML_ERROR_NOT_STANDALONE; - hadExternalDoctype = 1; - break; - case XML_ROLE_DOCTYPE_PUBLIC_ID: - case XML_ROLE_ENTITY_PUBLIC_ID: - if (!XmlIsPublicId(encoding, s, next, &eventPtr)) - return XML_ERROR_SYNTAX; - if (declEntity) { - XML_Char *tem = poolStoreString(&dtd.pool, - encoding, - s + encoding->minBytesPerChar, - next - encoding->minBytesPerChar); - if (!tem) - return XML_ERROR_NO_MEMORY; - normalizePublicId(tem); - declEntity->publicId = tem; - poolFinish(&dtd.pool); - } - break; - case XML_ROLE_INSTANCE_START: - processor = contentProcessor; - if (hadExternalDoctype) - dtd.complete = 0; - return contentProcessor(parser, s, end, nextPtr); - case XML_ROLE_ATTLIST_ELEMENT_NAME: - { - const XML_Char *name = poolStoreString(&dtd.pool, encoding, s, next); - if (!name) - return XML_ERROR_NO_MEMORY; - declElementType = (ELEMENT_TYPE *)lookup(&dtd.elementTypes, name, sizeof(ELEMENT_TYPE)); - if (!declElementType) - return XML_ERROR_NO_MEMORY; - if (declElementType->name != name) - poolDiscard(&dtd.pool); - else { - poolFinish(&dtd.pool); - if (!setElementTypePrefix(parser, declElementType)) - return XML_ERROR_NO_MEMORY; - } - break; - } - case XML_ROLE_ATTRIBUTE_NAME: - declAttributeId = getAttributeId(parser, encoding, s, next); - if (!declAttributeId) - return XML_ERROR_NO_MEMORY; - declAttributeIsCdata = 0; - break; - case XML_ROLE_ATTRIBUTE_TYPE_CDATA: - declAttributeIsCdata = 1; - break; - case XML_ROLE_IMPLIED_ATTRIBUTE_VALUE: - case XML_ROLE_REQUIRED_ATTRIBUTE_VALUE: - if (dtd.complete - && !defineAttribute(declElementType, declAttributeId, declAttributeIsCdata, 0)) - return XML_ERROR_NO_MEMORY; - break; - case XML_ROLE_DEFAULT_ATTRIBUTE_VALUE: - case XML_ROLE_FIXED_ATTRIBUTE_VALUE: - { - const XML_Char *attVal; - enum XML_Error result - = storeAttributeValue(parser, encoding, declAttributeIsCdata, - s + encoding->minBytesPerChar, - next - encoding->minBytesPerChar, - &dtd.pool); - if (result) - return result; - attVal = poolStart(&dtd.pool); - poolFinish(&dtd.pool); - if (dtd.complete - && !defineAttribute(declElementType, declAttributeId, declAttributeIsCdata, attVal)) - return XML_ERROR_NO_MEMORY; - break; - } - case XML_ROLE_ENTITY_VALUE: - { - enum XML_Error result = storeEntityValue(parser, s, next); - if (result != XML_ERROR_NONE) - return result; - } - break; - case XML_ROLE_ENTITY_SYSTEM_ID: - if (declEntity) { - declEntity->systemId = poolStoreString(&dtd.pool, encoding, - s + encoding->minBytesPerChar, - next - encoding->minBytesPerChar); - if (!declEntity->systemId) - return XML_ERROR_NO_MEMORY; - declEntity->base = dtd.base; - poolFinish(&dtd.pool); - } - break; - case XML_ROLE_ENTITY_NOTATION_NAME: - if (declEntity) { - declEntity->notation = poolStoreString(&dtd.pool, encoding, s, next); - if (!declEntity->notation) - return XML_ERROR_NO_MEMORY; - poolFinish(&dtd.pool); - if (unparsedEntityDeclHandler) { - eventPtr = eventEndPtr = s; - unparsedEntityDeclHandler(handlerArg, - declEntity->name, - declEntity->base, - declEntity->systemId, - declEntity->publicId, - declEntity->notation); - } - - } - break; - case XML_ROLE_GENERAL_ENTITY_NAME: - { - const XML_Char *name; - if (XmlPredefinedEntityName(encoding, s, next)) { - declEntity = 0; - break; - } - name = poolStoreString(&dtd.pool, encoding, s, next); - if (!name) - return XML_ERROR_NO_MEMORY; - if (dtd.complete) { - declEntity = (ENTITY *)lookup(&dtd.generalEntities, name, sizeof(ENTITY)); - if (!declEntity) - return XML_ERROR_NO_MEMORY; - if (declEntity->name != name) { - poolDiscard(&dtd.pool); - declEntity = 0; - } - else - poolFinish(&dtd.pool); - } - else { - poolDiscard(&dtd.pool); - declEntity = 0; - } - } - break; - case XML_ROLE_PARAM_ENTITY_NAME: - declEntity = 0; - break; - case XML_ROLE_NOTATION_NAME: - declNotationPublicId = 0; - declNotationName = 0; - if (notationDeclHandler) { - declNotationName = poolStoreString(&tempPool, encoding, s, next); - if (!declNotationName) - return XML_ERROR_NO_MEMORY; - poolFinish(&tempPool); - } - break; - case XML_ROLE_NOTATION_PUBLIC_ID: - if (!XmlIsPublicId(encoding, s, next, &eventPtr)) - return XML_ERROR_SYNTAX; - if (declNotationName) { - XML_Char *tem = poolStoreString(&tempPool, - encoding, - s + encoding->minBytesPerChar, - next - encoding->minBytesPerChar); - if (!tem) - return XML_ERROR_NO_MEMORY; - normalizePublicId(tem); - declNotationPublicId = tem; - poolFinish(&tempPool); - } - break; - case XML_ROLE_NOTATION_SYSTEM_ID: - if (declNotationName && notationDeclHandler) { - const XML_Char *systemId - = poolStoreString(&tempPool, encoding, - s + encoding->minBytesPerChar, - next - encoding->minBytesPerChar); - if (!systemId) - return XML_ERROR_NO_MEMORY; - eventPtr = eventEndPtr = s; - notationDeclHandler(handlerArg, - declNotationName, - dtd.base, - systemId, - declNotationPublicId); - } - poolClear(&tempPool); - break; - case XML_ROLE_NOTATION_NO_SYSTEM_ID: - if (declNotationPublicId && notationDeclHandler) { - eventPtr = eventEndPtr = s; - notationDeclHandler(handlerArg, - declNotationName, - dtd.base, - 0, - declNotationPublicId); - } - poolClear(&tempPool); - break; - case XML_ROLE_ERROR: - eventPtr = s; - switch (tok) { - case XML_TOK_PARAM_ENTITY_REF: - return XML_ERROR_PARAM_ENTITY_REF; - case XML_TOK_XML_DECL: - return XML_ERROR_MISPLACED_XML_PI; - default: - return XML_ERROR_SYNTAX; - } - case XML_ROLE_GROUP_OPEN: - if (prologState.level >= groupSize) { - if (groupSize) - groupConnector = realloc(groupConnector, groupSize *= 2); - else - groupConnector = malloc(groupSize = 32); - if (!groupConnector) - return XML_ERROR_NO_MEMORY; - } - groupConnector[prologState.level] = 0; - break; - case XML_ROLE_GROUP_SEQUENCE: - if (groupConnector[prologState.level] == '|') { - eventPtr = s; - return XML_ERROR_SYNTAX; - } - groupConnector[prologState.level] = ','; - break; - case XML_ROLE_GROUP_CHOICE: - if (groupConnector[prologState.level] == ',') { - eventPtr = s; - return XML_ERROR_SYNTAX; - } - groupConnector[prologState.level] = '|'; - break; - case XML_ROLE_PARAM_ENTITY_REF: - if (!dtd.standalone - && notStandaloneHandler - && !notStandaloneHandler(handlerArg)) - return XML_ERROR_NOT_STANDALONE; - dtd.complete = 0; - break; - case XML_ROLE_NONE: - switch (tok) { - case XML_TOK_PI: - eventPtr = s; - eventEndPtr = next; - if (!reportProcessingInstruction(parser, encoding, s, next)) - return XML_ERROR_NO_MEMORY; - break; - case XML_TOK_COMMENT: - eventPtr = s; - eventEndPtr = next; - if (!reportComment(parser, encoding, s, next)) - return XML_ERROR_NO_MEMORY; - break; - } - break; - } - if (defaultHandler) { - switch (tok) { - case XML_TOK_PI: - case XML_TOK_COMMENT: - case XML_TOK_BOM: - case XML_TOK_XML_DECL: - break; - default: - eventPtr = s; - eventEndPtr = next; - reportDefault(parser, encoding, s, next); - } - } - s = next; - } - /* not reached */ -} - -static -enum XML_Error epilogProcessor(XML_Parser parser, - const char *s, - const char *end, - const char **nextPtr) -{ - processor = epilogProcessor; - eventPtr = s; - for (;;) { - const char *next; - int tok = XmlPrologTok(encoding, s, end, &next); - eventEndPtr = next; - switch (tok) { - case XML_TOK_TRAILING_CR: - if (defaultHandler) { - eventEndPtr = end; - reportDefault(parser, encoding, s, end); - } - /* fall through */ - case XML_TOK_NONE: - if (nextPtr) - *nextPtr = end; - return XML_ERROR_NONE; - case XML_TOK_PROLOG_S: - if (defaultHandler) - reportDefault(parser, encoding, s, next); - break; - case XML_TOK_PI: - if (!reportProcessingInstruction(parser, encoding, s, next)) - return XML_ERROR_NO_MEMORY; - break; - case XML_TOK_COMMENT: - if (!reportComment(parser, encoding, s, next)) - return XML_ERROR_NO_MEMORY; - break; - case XML_TOK_INVALID: - eventPtr = next; - return XML_ERROR_INVALID_TOKEN; - case XML_TOK_PARTIAL: - if (nextPtr) { - *nextPtr = s; - return XML_ERROR_NONE; - } - return XML_ERROR_UNCLOSED_TOKEN; - case XML_TOK_PARTIAL_CHAR: - if (nextPtr) { - *nextPtr = s; - return XML_ERROR_NONE; - } - return XML_ERROR_PARTIAL_CHAR; - default: - return XML_ERROR_JUNK_AFTER_DOC_ELEMENT; - } - eventPtr = s = next; - } -} - -static enum XML_Error -storeAttributeValue(XML_Parser parser, const ENCODING *enc, int isCdata, - const char *ptr, const char *end, - STRING_POOL *pool) -{ - enum XML_Error result = appendAttributeValue(parser, enc, isCdata, ptr, end, pool); - if (result) - return result; - if (!isCdata && poolLength(pool) && poolLastChar(pool) == 0x20) - poolChop(pool); - if (!poolAppendChar(pool, XML_T('\0'))) - return XML_ERROR_NO_MEMORY; - return XML_ERROR_NONE; -} - -static enum XML_Error -appendAttributeValue(XML_Parser parser, const ENCODING *enc, int isCdata, - const char *ptr, const char *end, - STRING_POOL *pool) -{ - const ENCODING *internalEnc = ns ? XmlGetInternalEncodingNS() : XmlGetInternalEncoding(); - for (;;) { - const char *next; - int tok = XmlAttributeValueTok(enc, ptr, end, &next); - switch (tok) { - case XML_TOK_NONE: - return XML_ERROR_NONE; - case XML_TOK_INVALID: - if (enc == encoding) - eventPtr = next; - return XML_ERROR_INVALID_TOKEN; - case XML_TOK_PARTIAL: - if (enc == encoding) - eventPtr = ptr; - return XML_ERROR_INVALID_TOKEN; - case XML_TOK_CHAR_REF: - { - XML_Char buf[XML_ENCODE_MAX]; - int i; - int n = XmlCharRefNumber(enc, ptr); - if (n < 0) { - if (enc == encoding) - eventPtr = ptr; - return XML_ERROR_BAD_CHAR_REF; - } - if (!isCdata - && n == 0x20 /* space */ - && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20)) - break; - n = XmlEncode(n, (ICHAR *)buf); - if (!n) { - if (enc == encoding) - eventPtr = ptr; - return XML_ERROR_BAD_CHAR_REF; - } - for (i = 0; i < n; i++) { - if (!poolAppendChar(pool, buf[i])) - return XML_ERROR_NO_MEMORY; - } - } - break; - case XML_TOK_DATA_CHARS: - if (!poolAppend(pool, enc, ptr, next)) - return XML_ERROR_NO_MEMORY; - break; - break; - case XML_TOK_TRAILING_CR: - next = ptr + enc->minBytesPerChar; - /* fall through */ - case XML_TOK_ATTRIBUTE_VALUE_S: - case XML_TOK_DATA_NEWLINE: - if (!isCdata && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20)) - break; - if (!poolAppendChar(pool, 0x20)) - return XML_ERROR_NO_MEMORY; - break; - case XML_TOK_ENTITY_REF: - { - const XML_Char *name; - ENTITY *entity; - XML_Char ch = XmlPredefinedEntityName(enc, - ptr + enc->minBytesPerChar, - next - enc->minBytesPerChar); - if (ch) { - if (!poolAppendChar(pool, ch)) - return XML_ERROR_NO_MEMORY; - break; - } - name = poolStoreString(&temp2Pool, enc, - ptr + enc->minBytesPerChar, - next - enc->minBytesPerChar); - if (!name) - return XML_ERROR_NO_MEMORY; - entity = (ENTITY *)lookup(&dtd.generalEntities, name, 0); - poolDiscard(&temp2Pool); - if (!entity) { - if (dtd.complete) { - if (enc == encoding) - eventPtr = ptr; - return XML_ERROR_UNDEFINED_ENTITY; - } - } - else if (entity->open) { - if (enc == encoding) - eventPtr = ptr; - return XML_ERROR_RECURSIVE_ENTITY_REF; - } - else if (entity->notation) { - if (enc == encoding) - eventPtr = ptr; - return XML_ERROR_BINARY_ENTITY_REF; - } - else if (!entity->textPtr) { - if (enc == encoding) - eventPtr = ptr; - return XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF; - } - else { - enum XML_Error result; - const XML_Char *textEnd = entity->textPtr + entity->textLen; - entity->open = 1; - result = appendAttributeValue(parser, internalEnc, isCdata, (char *)entity->textPtr, (char *)textEnd, pool); - entity->open = 0; - if (result) - return result; - } - } - break; - default: - abort(); - } - ptr = next; - } - /* not reached */ -} - -static -enum XML_Error storeEntityValue(XML_Parser parser, - const char *entityTextPtr, - const char *entityTextEnd) -{ - const ENCODING *internalEnc; - STRING_POOL *pool = &(dtd.pool); - entityTextPtr += encoding->minBytesPerChar; - entityTextEnd -= encoding->minBytesPerChar; - internalEnc = ns ? XmlGetInternalEncodingNS() : XmlGetInternalEncoding(); - for (;;) { - const char *next; - int tok = XmlEntityValueTok(encoding, entityTextPtr, entityTextEnd, &next); - switch (tok) { - case XML_TOK_PARAM_ENTITY_REF: - eventPtr = entityTextPtr; - return XML_ERROR_SYNTAX; - case XML_TOK_NONE: - if (declEntity) { - declEntity->textPtr = pool->start; - declEntity->textLen = pool->ptr - pool->start; - poolFinish(pool); - } - else - poolDiscard(pool); - return XML_ERROR_NONE; - case XML_TOK_ENTITY_REF: - case XML_TOK_DATA_CHARS: - if (!poolAppend(pool, encoding, entityTextPtr, next)) - return XML_ERROR_NO_MEMORY; - break; - case XML_TOK_TRAILING_CR: - next = entityTextPtr + encoding->minBytesPerChar; - /* fall through */ - case XML_TOK_DATA_NEWLINE: - if (pool->end == pool->ptr && !poolGrow(pool)) - return XML_ERROR_NO_MEMORY; - *(pool->ptr)++ = 0xA; - break; - case XML_TOK_CHAR_REF: - { - XML_Char buf[XML_ENCODE_MAX]; - int i; - int n = XmlCharRefNumber(encoding, entityTextPtr); - if (n < 0) { - eventPtr = entityTextPtr; - return XML_ERROR_BAD_CHAR_REF; - } - n = XmlEncode(n, (ICHAR *)buf); - if (!n) { - eventPtr = entityTextPtr; - return XML_ERROR_BAD_CHAR_REF; - } - for (i = 0; i < n; i++) { - if (pool->end == pool->ptr && !poolGrow(pool)) - return XML_ERROR_NO_MEMORY; - *(pool->ptr)++ = buf[i]; - } - } - break; - case XML_TOK_PARTIAL: - eventPtr = entityTextPtr; - return XML_ERROR_INVALID_TOKEN; - case XML_TOK_INVALID: - eventPtr = next; - return XML_ERROR_INVALID_TOKEN; - default: - abort(); - } - entityTextPtr = next; - } - /* not reached */ -} - -static void -normalizeLines(XML_Char *s) -{ - XML_Char *p; - for (;; s++) { - if (*s == XML_T('\0')) - return; - if (*s == 0xD) - break; - } - p = s; - do { - if (*s == 0xD) { - *p++ = 0xA; - if (*++s == 0xA) - s++; - } - else - *p++ = *s++; - } while (*s); - *p = XML_T('\0'); -} - -static int -reportProcessingInstruction(XML_Parser parser, const ENCODING *enc, const char *start, const char *end) -{ - const XML_Char *target; - XML_Char *data; - const char *tem; - if (!processingInstructionHandler) { - if (defaultHandler) - reportDefault(parser, enc, start, end); - return 1; - } - start += enc->minBytesPerChar * 2; - tem = start + XmlNameLength(enc, start); - target = poolStoreString(&tempPool, enc, start, tem); - if (!target) - return 0; - poolFinish(&tempPool); - data = poolStoreString(&tempPool, enc, - XmlSkipS(enc, tem), - end - enc->minBytesPerChar*2); - if (!data) - return 0; - normalizeLines(data); - processingInstructionHandler(handlerArg, target, data); - poolClear(&tempPool); - return 1; -} - -static int -reportComment(XML_Parser parser, const ENCODING *enc, const char *start, const char *end) -{ - XML_Char *data; - if (!commentHandler) { - if (defaultHandler) - reportDefault(parser, enc, start, end); - return 1; - } - data = poolStoreString(&tempPool, - enc, - start + enc->minBytesPerChar * 4, - end - enc->minBytesPerChar * 3); - if (!data) - return 0; - normalizeLines(data); - commentHandler(handlerArg, data); - poolClear(&tempPool); - return 1; -} - -static void -reportDefault(XML_Parser parser, const ENCODING *enc, const char *s, const char *end) -{ - if (MUST_CONVERT(enc, s)) { - const char **eventPP; - const char **eventEndPP; - if (enc == encoding) { - eventPP = &eventPtr; - eventEndPP = &eventEndPtr; - } - else { - eventPP = &(openInternalEntities->internalEventPtr); - eventEndPP = &(openInternalEntities->internalEventEndPtr); - } - do { - ICHAR *dataPtr = (ICHAR *)dataBuf; - XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd); - *eventEndPP = s; - defaultHandler(handlerArg, dataBuf, dataPtr - (ICHAR *)dataBuf); - *eventPP = s; - } while (s != end); - } - else - defaultHandler(handlerArg, (XML_Char *)s, (XML_Char *)end - (XML_Char *)s); -} - - -static int -defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, int isCdata, const XML_Char *value) -{ - DEFAULT_ATTRIBUTE *att; - if (type->nDefaultAtts == type->allocDefaultAtts) { - if (type->allocDefaultAtts == 0) { - type->allocDefaultAtts = 8; - type->defaultAtts = malloc(type->allocDefaultAtts*sizeof(DEFAULT_ATTRIBUTE)); - } - else { - type->allocDefaultAtts *= 2; - type->defaultAtts = realloc(type->defaultAtts, - type->allocDefaultAtts*sizeof(DEFAULT_ATTRIBUTE)); - } - if (!type->defaultAtts) - return 0; - } - att = type->defaultAtts + type->nDefaultAtts; - att->id = attId; - att->value = value; - att->isCdata = isCdata; - if (!isCdata) - attId->maybeTokenized = 1; - type->nDefaultAtts += 1; - return 1; -} - -static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *elementType) -{ - const XML_Char *name; - for (name = elementType->name; *name; name++) { - if (*name == XML_T(':')) { - PREFIX *prefix; - const XML_Char *s; - for (s = elementType->name; s != name; s++) { - if (!poolAppendChar(&dtd.pool, *s)) - return 0; - } - if (!poolAppendChar(&dtd.pool, XML_T('\0'))) - return 0; - prefix = (PREFIX *)lookup(&dtd.prefixes, poolStart(&dtd.pool), sizeof(PREFIX)); - if (!prefix) - return 0; - if (prefix->name == poolStart(&dtd.pool)) - poolFinish(&dtd.pool); - else - poolDiscard(&dtd.pool); - elementType->prefix = prefix; - - } - } - return 1; -} - -static ATTRIBUTE_ID * -getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start, const char *end) -{ - ATTRIBUTE_ID *id; - const XML_Char *name; - if (!poolAppendChar(&dtd.pool, XML_T('\0'))) - return 0; - name = poolStoreString(&dtd.pool, enc, start, end); - if (!name) - return 0; - ++name; - id = (ATTRIBUTE_ID *)lookup(&dtd.attributeIds, name, sizeof(ATTRIBUTE_ID)); - if (!id) - return 0; - if (id->name != name) - poolDiscard(&dtd.pool); - else { - poolFinish(&dtd.pool); - if (!ns) - ; - else if (name[0] == 'x' - && name[1] == 'm' - && name[2] == 'l' - && name[3] == 'n' - && name[4] == 's' - && (name[5] == XML_T('\0') || name[5] == XML_T(':'))) { - if (name[5] == '\0') - id->prefix = &dtd.defaultPrefix; - else - id->prefix = (PREFIX *)lookup(&dtd.prefixes, name + 6, sizeof(PREFIX)); - id->xmlns = 1; - } - else { - int i; - for (i = 0; name[i]; i++) { - if (name[i] == XML_T(':')) { - int j; - for (j = 0; j < i; j++) { - if (!poolAppendChar(&dtd.pool, name[j])) - return 0; - } - if (!poolAppendChar(&dtd.pool, XML_T('\0'))) - return 0; - id->prefix = (PREFIX *)lookup(&dtd.prefixes, poolStart(&dtd.pool), sizeof(PREFIX)); - if (id->prefix->name == poolStart(&dtd.pool)) - poolFinish(&dtd.pool); - else - poolDiscard(&dtd.pool); - break; - } - } - } - } - return id; -} - -#define CONTEXT_SEP XML_T('\f') - -static -const XML_Char *getContext(XML_Parser parser) -{ - HASH_TABLE_ITER iter; - int needSep = 0; - - if (dtd.defaultPrefix.binding) { - int i; - int len; - if (!poolAppendChar(&tempPool, XML_T('='))) - return 0; - len = dtd.defaultPrefix.binding->uriLen; - if (namespaceSeparator != XML_T('\0')) - len--; - for (i = 0; i < len; i++) - if (!poolAppendChar(&tempPool, dtd.defaultPrefix.binding->uri[i])) - return 0; - needSep = 1; - } - - hashTableIterInit(&iter, &(dtd.prefixes)); - for (;;) { - int i; - int len; - const XML_Char *s; - PREFIX *prefix = (PREFIX *)hashTableIterNext(&iter); - if (!prefix) - break; - if (!prefix->binding) - continue; - if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP)) - return 0; - for (s = prefix->name; *s; s++) - if (!poolAppendChar(&tempPool, *s)) - return 0; - if (!poolAppendChar(&tempPool, XML_T('='))) - return 0; - len = prefix->binding->uriLen; - if (namespaceSeparator != XML_T('\0')) - len--; - for (i = 0; i < len; i++) - if (!poolAppendChar(&tempPool, prefix->binding->uri[i])) - return 0; - needSep = 1; - } - - - hashTableIterInit(&iter, &(dtd.generalEntities)); - for (;;) { - const XML_Char *s; - ENTITY *e = (ENTITY *)hashTableIterNext(&iter); - if (!e) - break; - if (!e->open) - continue; - if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP)) - return 0; - for (s = e->name; *s; s++) - if (!poolAppendChar(&tempPool, *s)) - return 0; - needSep = 1; - } - - if (!poolAppendChar(&tempPool, XML_T('\0'))) - return 0; - return tempPool.start; -} - -static -void normalizePublicId(XML_Char *publicId) -{ - XML_Char *p = publicId; - XML_Char *s; - for (s = publicId; *s; s++) { - switch (*s) { - case 0x20: - case 0xD: - case 0xA: - if (p != publicId && p[-1] != 0x20) - *p++ = 0x20; - break; - default: - *p++ = *s; - } - } - if (p != publicId && p[-1] == 0x20) - --p; - *p = XML_T('\0'); -} - -static int dtdInit(DTD *p) -{ - poolInit(&(p->pool)); - hashTableInit(&(p->generalEntities)); - hashTableInit(&(p->elementTypes)); - hashTableInit(&(p->attributeIds)); - hashTableInit(&(p->prefixes)); - p->complete = 1; - p->standalone = 0; - p->base = 0; - p->defaultPrefix.name = 0; - p->defaultPrefix.binding = 0; - return 1; -} - -static void dtdDestroy(DTD *p) -{ - HASH_TABLE_ITER iter; - hashTableIterInit(&iter, &(p->elementTypes)); - for (;;) { - ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter); - if (!e) - break; - if (e->allocDefaultAtts != 0) - g_free(e->defaultAtts); - } - hashTableDestroy(&(p->generalEntities)); - hashTableDestroy(&(p->elementTypes)); - hashTableDestroy(&(p->attributeIds)); - hashTableDestroy(&(p->prefixes)); - poolDestroy(&(p->pool)); -} - -static -void poolInit(STRING_POOL *pool) -{ - pool->blocks = 0; - pool->freeBlocks = 0; - pool->start = 0; - pool->ptr = 0; - pool->end = 0; -} - -static -void poolClear(STRING_POOL *pool) -{ - if (!pool->freeBlocks) - pool->freeBlocks = pool->blocks; - else { - BLOCK *p = pool->blocks; - while (p) { - BLOCK *tem = p->next; - p->next = pool->freeBlocks; - pool->freeBlocks = p; - p = tem; - } - } - pool->blocks = 0; - pool->start = 0; - pool->ptr = 0; - pool->end = 0; -} - -static -void poolDestroy(STRING_POOL *pool) -{ - BLOCK *p = pool->blocks; - while (p) { - BLOCK *tem = p->next; - g_free(p); - p = tem; - } - pool->blocks = 0; - p = pool->freeBlocks; - while (p) { - BLOCK *tem = p->next; - g_free(p); - p = tem; - } - pool->freeBlocks = 0; - pool->ptr = 0; - pool->start = 0; - pool->end = 0; -} - -static -XML_Char *poolAppend(STRING_POOL *pool, const ENCODING *enc, - const char *ptr, const char *end) -{ - if (!pool->ptr && !poolGrow(pool)) - return 0; - for (;;) { - XmlConvert(enc, &ptr, end, (ICHAR **)&(pool->ptr), (ICHAR *)pool->end); - if (ptr == end) - break; - if (!poolGrow(pool)) - return 0; - } - return pool->start; -} - -static const XML_Char *poolCopyString(STRING_POOL *pool, const XML_Char *s) -{ - do { - if (!poolAppendChar(pool, *s)) - return 0; - } while (*s++); - s = pool->start; - poolFinish(pool); - return s; -} - -static -XML_Char *poolStoreString(STRING_POOL *pool, const ENCODING *enc, - const char *ptr, const char *end) -{ - if (!poolAppend(pool, enc, ptr, end)) - return 0; - if (pool->ptr == pool->end && !poolGrow(pool)) - return 0; - *(pool->ptr)++ = 0; - return pool->start; -} - -static -int poolGrow(STRING_POOL *pool) -{ - if (pool->freeBlocks) { - if (pool->start == 0) { - pool->blocks = pool->freeBlocks; - pool->freeBlocks = pool->freeBlocks->next; - pool->blocks->next = 0; - pool->start = pool->blocks->s; - pool->end = pool->start + pool->blocks->size; - pool->ptr = pool->start; - return 1; - } - if (pool->end - pool->start < pool->freeBlocks->size) { - BLOCK *tem = pool->freeBlocks->next; - pool->freeBlocks->next = pool->blocks; - pool->blocks = pool->freeBlocks; - pool->freeBlocks = tem; - memcpy(pool->blocks->s, pool->start, (pool->end - pool->start) * sizeof(XML_Char)); - pool->ptr = pool->blocks->s + (pool->ptr - pool->start); - pool->start = pool->blocks->s; - pool->end = pool->start + pool->blocks->size; - return 1; - } - } - if (pool->blocks && pool->start == pool->blocks->s) { - int blockSize = (pool->end - pool->start)*2; - pool->blocks = realloc(pool->blocks, offsetof(BLOCK, s) + blockSize * sizeof(XML_Char)); - if (!pool->blocks) - return 0; - pool->blocks->size = blockSize; - pool->ptr = pool->blocks->s + (pool->ptr - pool->start); - pool->start = pool->blocks->s; - pool->end = pool->start + blockSize; - } - else { - BLOCK *tem; - int blockSize = pool->end - pool->start; - if (blockSize < INIT_BLOCK_SIZE) - blockSize = INIT_BLOCK_SIZE; - else - blockSize *= 2; - tem = malloc(offsetof(BLOCK, s) + blockSize * sizeof(XML_Char)); - if (!tem) - return 0; - tem->size = blockSize; - tem->next = pool->blocks; - pool->blocks = tem; - memcpy(tem->s, pool->start, (pool->ptr - pool->start) * sizeof(XML_Char)); - pool->ptr = tem->s + (pool->ptr - pool->start); - pool->start = tem->s; - pool->end = tem->s + blockSize; - } - return 1; -} diff --git a/protocols/jabber/xmlparse.h b/protocols/jabber/xmlparse.h deleted file mode 100644 index f39edb8c..00000000 --- a/protocols/jabber/xmlparse.h +++ /dev/null @@ -1,476 +0,0 @@ -/* -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in -compliance with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" -basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -License for the specific language governing rights and limitations -under the License. - -The Original Code is expat. - -The Initial Developer of the Original Code is James Clark. -Portions created by James Clark are Copyright (C) 1998, 1999 -James Clark. All Rights Reserved. - -Contributor(s): - -Alternatively, the contents of this file may be used under the terms -of the GNU General Public License (the "GPL"), in which case the -provisions of the GPL are applicable instead of those above. If you -wish to allow use of your version of this file only under the terms of -the GPL and not to allow others to use your version of this file under -the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the -GPL. If you do not delete the provisions above, a recipient may use -your version of this file under either the MPL or the GPL. -*/ - -#ifndef XmlParse_INCLUDED -#define XmlParse_INCLUDED 1 - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef XMLPARSEAPI -#define XMLPARSEAPI /* as nothing */ -#endif - -typedef void *XML_Parser; - -#ifdef XML_UNICODE_WCHAR_T - -/* XML_UNICODE_WCHAR_T will work only if sizeof(wchar_t) == 2 and wchar_t -uses Unicode. */ -/* Information is UTF-16 encoded as wchar_ts */ - -#ifndef XML_UNICODE -#define XML_UNICODE -#endif - -#include <stddef.h> -typedef wchar_t XML_Char; -typedef wchar_t XML_LChar; - -#else /* not XML_UNICODE_WCHAR_T */ - -#ifdef XML_UNICODE - -/* Information is UTF-16 encoded as unsigned shorts */ -typedef unsigned short XML_Char; -typedef char XML_LChar; - -#else /* not XML_UNICODE */ - -/* Information is UTF-8 encoded. */ -typedef char XML_Char; -typedef char XML_LChar; - -#endif /* not XML_UNICODE */ - -#endif /* not XML_UNICODE_WCHAR_T */ - - -/* Constructs a new parser; encoding is the encoding specified by the external -protocol or null if there is none specified. */ - -XML_Parser XMLPARSEAPI -XML_ParserCreate(const XML_Char *encoding); - -/* Constructs a new parser and namespace processor. Element type names -and attribute names that belong to a namespace will be expanded; -unprefixed attribute names are never expanded; unprefixed element type -names are expanded only if there is a default namespace. The expanded -name is the concatenation of the namespace URI, the namespace separator character, -and the local part of the name. If the namespace separator is '\0' then -the namespace URI and the local part will be concatenated without any -separator. When a namespace is not declared, the name and prefix will be -passed through without expansion. */ - -XML_Parser XMLPARSEAPI -XML_ParserCreateNS(const XML_Char *encoding, XML_Char namespaceSeparator); - - -/* atts is array of name/value pairs, terminated by 0; - names and values are 0 terminated. */ - -typedef void (*XML_StartElementHandler)(void *userData, - const XML_Char *name, - const XML_Char **atts); - -typedef void (*XML_EndElementHandler)(void *userData, - const XML_Char *name); - -/* s is not 0 terminated. */ -typedef void (*XML_CharacterDataHandler)(void *userData, - const XML_Char *s, - int len); - -/* target and data are 0 terminated */ -typedef void (*XML_ProcessingInstructionHandler)(void *userData, - const XML_Char *target, - const XML_Char *data); - -/* data is 0 terminated */ -typedef void (*XML_CommentHandler)(void *userData, const XML_Char *data); - -typedef void (*XML_StartCdataSectionHandler)(void *userData); -typedef void (*XML_EndCdataSectionHandler)(void *userData); - -/* This is called for any characters in the XML document for -which there is no applicable handler. This includes both -characters that are part of markup which is of a kind that is -not reported (comments, markup declarations), or characters -that are part of a construct which could be reported but -for which no handler has been supplied. The characters are passed -exactly as they were in the XML document except that -they will be encoded in UTF-8. Line boundaries are not normalized. -Note that a byte order mark character is not passed to the default handler. -There are no guarantees about how characters are divided between calls -to the default handler: for example, a comment might be split between -multiple calls. */ - -typedef void (*XML_DefaultHandler)(void *userData, - const XML_Char *s, - int len); - -/* This is called for a declaration of an unparsed (NDATA) -entity. The base argument is whatever was set by XML_SetBase. -The entityName, systemId and notationName arguments will never be null. -The other arguments may be. */ - -typedef void (*XML_UnparsedEntityDeclHandler)(void *userData, - const XML_Char *entityName, - const XML_Char *base, - const XML_Char *systemId, - const XML_Char *publicId, - const XML_Char *notationName); - -/* This is called for a declaration of notation. -The base argument is whatever was set by XML_SetBase. -The notationName will never be null. The other arguments can be. */ - -typedef void (*XML_NotationDeclHandler)(void *userData, - const XML_Char *notationName, - const XML_Char *base, - const XML_Char *systemId, - const XML_Char *publicId); - -/* When namespace processing is enabled, these are called once for -each namespace declaration. The call to the start and end element -handlers occur between the calls to the start and end namespace -declaration handlers. For an xmlns attribute, prefix will be null. -For an xmlns="" attribute, uri will be null. */ - -typedef void (*XML_StartNamespaceDeclHandler)(void *userData, - const XML_Char *prefix, - const XML_Char *uri); - -typedef void (*XML_EndNamespaceDeclHandler)(void *userData, - const XML_Char *prefix); - -/* This is called if the document is not standalone (it has an -external subset or a reference to a parameter entity, but does not -have standalone="yes"). If this handler returns 0, then processing -will not continue, and the parser will return a -XML_ERROR_NOT_STANDALONE error. */ - -typedef int (*XML_NotStandaloneHandler)(void *userData); - -/* This is called for a reference to an external parsed general entity. -The referenced entity is not automatically parsed. -The application can parse it immediately or later using -XML_ExternalEntityParserCreate. -The parser argument is the parser parsing the entity containing the reference; -it can be passed as the parser argument to XML_ExternalEntityParserCreate. -The systemId argument is the system identifier as specified in the entity declaration; -it will not be null. -The base argument is the system identifier that should be used as the base for -resolving systemId if systemId was relative; this is set by XML_SetBase; -it may be null. -The publicId argument is the public identifier as specified in the entity declaration, -or null if none was specified; the whitespace in the public identifier -will have been normalized as required by the XML spec. -The context argument specifies the parsing context in the format -expected by the context argument to -XML_ExternalEntityParserCreate; context is valid only until the handler -returns, so if the referenced entity is to be parsed later, it must be copied. -The handler should return 0 if processing should not continue because of -a fatal error in the handling of the external entity. -In this case the calling parser will return an XML_ERROR_EXTERNAL_ENTITY_HANDLING -error. -Note that unlike other handlers the first argument is the parser, not userData. */ - -typedef int (*XML_ExternalEntityRefHandler)(XML_Parser parser, - const XML_Char *context, - const XML_Char *base, - const XML_Char *systemId, - const XML_Char *publicId); - -/* This structure is filled in by the XML_UnknownEncodingHandler -to provide information to the parser about encodings that are unknown -to the parser. -The map[b] member gives information about byte sequences -whose first byte is b. -If map[b] is c where c is >= 0, then b by itself encodes the Unicode scalar value c. -If map[b] is -1, then the byte sequence is malformed. -If map[b] is -n, where n >= 2, then b is the first byte of an n-byte -sequence that encodes a single Unicode scalar value. -The data member will be passed as the first argument to the convert function. -The convert function is used to convert multibyte sequences; -s will point to a n-byte sequence where map[(unsigned char)*s] == -n. -The convert function must return the Unicode scalar value -represented by this byte sequence or -1 if the byte sequence is malformed. -The convert function may be null if the encoding is a single-byte encoding, -that is if map[b] >= -1 for all bytes b. -When the parser is finished with the encoding, then if release is not null, -it will call release passing it the data member; -once release has been called, the convert function will not be called again. - -Expat places certain restrictions on the encodings that are supported -using this mechanism. - -1. Every ASCII character that can appear in a well-formed XML document, -other than the characters - - $@\^`{}~ - -must be represented by a single byte, and that byte must be the -same byte that represents that character in ASCII. - -2. No character may require more than 4 bytes to encode. - -3. All characters encoded must have Unicode scalar values <= 0xFFFF, -(ie characters that would be encoded by surrogates in UTF-16 -are not allowed). Note that this restriction doesn't apply to -the built-in support for UTF-8 and UTF-16. - -4. No Unicode character may be encoded by more than one distinct sequence -of bytes. */ - -typedef struct { - int map[256]; - void *data; - int (*convert)(void *data, const char *s); - void (*release)(void *data); -} XML_Encoding; - -/* This is called for an encoding that is unknown to the parser. -The encodingHandlerData argument is that which was passed as the -second argument to XML_SetUnknownEncodingHandler. -The name argument gives the name of the encoding as specified in -the encoding declaration. -If the callback can provide information about the encoding, -it must fill in the XML_Encoding structure, and return 1. -Otherwise it must return 0. -If info does not describe a suitable encoding, -then the parser will return an XML_UNKNOWN_ENCODING error. */ - -typedef int (*XML_UnknownEncodingHandler)(void *encodingHandlerData, - const XML_Char *name, - XML_Encoding *info); - -void XMLPARSEAPI -XML_SetElementHandler(XML_Parser parser, - XML_StartElementHandler start, - XML_EndElementHandler end); - -void XMLPARSEAPI -XML_SetCharacterDataHandler(XML_Parser parser, - XML_CharacterDataHandler handler); - -void XMLPARSEAPI -XML_SetProcessingInstructionHandler(XML_Parser parser, - XML_ProcessingInstructionHandler handler); -void XMLPARSEAPI -XML_SetCommentHandler(XML_Parser parser, - XML_CommentHandler handler); - -void XMLPARSEAPI -XML_SetCdataSectionHandler(XML_Parser parser, - XML_StartCdataSectionHandler start, - XML_EndCdataSectionHandler end); - -/* This sets the default handler and also inhibits expansion of internal entities. -The entity reference will be passed to the default handler. */ - -void XMLPARSEAPI -XML_SetDefaultHandler(XML_Parser parser, - XML_DefaultHandler handler); - -/* This sets the default handler but does not inhibit expansion of internal entities. -The entity reference will not be passed to the default handler. */ - -void XMLPARSEAPI -XML_SetDefaultHandlerExpand(XML_Parser parser, - XML_DefaultHandler handler); - -void XMLPARSEAPI -XML_SetUnparsedEntityDeclHandler(XML_Parser parser, - XML_UnparsedEntityDeclHandler handler); - -void XMLPARSEAPI -XML_SetNotationDeclHandler(XML_Parser parser, - XML_NotationDeclHandler handler); - -void XMLPARSEAPI -XML_SetNamespaceDeclHandler(XML_Parser parser, - XML_StartNamespaceDeclHandler start, - XML_EndNamespaceDeclHandler end); - -void XMLPARSEAPI -XML_SetNotStandaloneHandler(XML_Parser parser, - XML_NotStandaloneHandler handler); - -void XMLPARSEAPI -XML_SetExternalEntityRefHandler(XML_Parser parser, - XML_ExternalEntityRefHandler handler); - -/* If a non-null value for arg is specified here, then it will be passed -as the first argument to the external entity ref handler instead -of the parser object. */ -void XMLPARSEAPI -XML_SetExternalEntityRefHandlerArg(XML_Parser, void *arg); - -void XMLPARSEAPI -XML_SetUnknownEncodingHandler(XML_Parser parser, - XML_UnknownEncodingHandler handler, - void *encodingHandlerData); - -/* This can be called within a handler for a start element, end element, -processing instruction or character data. It causes the corresponding -markup to be passed to the default handler. */ -void XMLPARSEAPI XML_DefaultCurrent(XML_Parser parser); - -/* This value is passed as the userData argument to callbacks. */ -void XMLPARSEAPI -XML_SetUserData(XML_Parser parser, void *userData); - -/* Returns the last value set by XML_SetUserData or null. */ -#define XML_GetUserData(parser) (*(void **)(parser)) - -/* This is equivalent to supplying an encoding argument -to XML_CreateParser. It must not be called after XML_Parse -or XML_ParseBuffer. */ - -int XMLPARSEAPI -XML_SetEncoding(XML_Parser parser, const XML_Char *encoding); - -/* If this function is called, then the parser will be passed -as the first argument to callbacks instead of userData. -The userData will still be accessible using XML_GetUserData. */ - -void XMLPARSEAPI -XML_UseParserAsHandlerArg(XML_Parser parser); - -/* Sets the base to be used for resolving relative URIs in system identifiers in -declarations. Resolving relative identifiers is left to the application: -this value will be passed through as the base argument to the -XML_ExternalEntityRefHandler, XML_NotationDeclHandler -and XML_UnparsedEntityDeclHandler. The base argument will be copied. -Returns zero if out of memory, non-zero otherwise. */ - -int XMLPARSEAPI -XML_SetBase(XML_Parser parser, const XML_Char *base); - -const XML_Char XMLPARSEAPI * -XML_GetBase(XML_Parser parser); - -/* Returns the number of the attributes passed in last call to the -XML_StartElementHandler that were specified in the start-tag rather -than defaulted. */ - -int XMLPARSEAPI XML_GetSpecifiedAttributeCount(XML_Parser parser); - -/* Parses some input. Returns 0 if a fatal error is detected. -The last call to XML_Parse must have isFinal true; -len may be zero for this call (or any other). */ -int XMLPARSEAPI -XML_Parse(XML_Parser parser, const char *s, int len, int isFinal); - -/* Creates an XML_Parser object that can parse an external general entity; -context is a '\0'-terminated string specifying the parse context; -encoding is a '\0'-terminated string giving the name of the externally specified encoding, -or null if there is no externally specified encoding. -The context string consists of a sequence of tokens separated by formfeeds (\f); -a token consisting of a name specifies that the general entity of the name -is open; a token of the form prefix=uri specifies the namespace for a particular -prefix; a token of the form =uri specifies the default namespace. -This can be called at any point after the first call to an ExternalEntityRefHandler -so longer as the parser has not yet been freed. -The new parser is completely independent and may safely be used in a separate thread. -The handlers and userData are initialized from the parser argument. -Returns 0 if out of memory. Otherwise returns a new XML_Parser object. */ -XML_Parser XMLPARSEAPI -XML_ExternalEntityParserCreate(XML_Parser parser, - const XML_Char *context, - const XML_Char *encoding); - -enum XML_Error { - XML_ERROR_NONE, - XML_ERROR_NO_MEMORY, - XML_ERROR_SYNTAX, - XML_ERROR_NO_ELEMENTS, - XML_ERROR_INVALID_TOKEN, - XML_ERROR_UNCLOSED_TOKEN, - XML_ERROR_PARTIAL_CHAR, - XML_ERROR_TAG_MISMATCH, - XML_ERROR_DUPLICATE_ATTRIBUTE, - XML_ERROR_JUNK_AFTER_DOC_ELEMENT, - XML_ERROR_PARAM_ENTITY_REF, - XML_ERROR_UNDEFINED_ENTITY, - XML_ERROR_RECURSIVE_ENTITY_REF, - XML_ERROR_ASYNC_ENTITY, - XML_ERROR_BAD_CHAR_REF, - XML_ERROR_BINARY_ENTITY_REF, - XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF, - XML_ERROR_MISPLACED_XML_PI, - XML_ERROR_UNKNOWN_ENCODING, - XML_ERROR_INCORRECT_ENCODING, - XML_ERROR_UNCLOSED_CDATA_SECTION, - XML_ERROR_EXTERNAL_ENTITY_HANDLING, - XML_ERROR_NOT_STANDALONE -}; - -/* If XML_Parse or XML_ParseBuffer have returned 0, then XML_GetErrorCode -returns information about the error. */ - -enum XML_Error XMLPARSEAPI XML_GetErrorCode(XML_Parser parser); - -/* These functions return information about the current parse location. -They may be called when XML_Parse or XML_ParseBuffer return 0; -in this case the location is the location of the character at which -the error was detected. -They may also be called from any other callback called to report -some parse event; in this the location is the location of the first -of the sequence of characters that generated the event. */ - -int XMLPARSEAPI XML_GetCurrentLineNumber(XML_Parser parser); -int XMLPARSEAPI XML_GetCurrentColumnNumber(XML_Parser parser); -long XMLPARSEAPI XML_GetCurrentByteIndex(XML_Parser parser); - -/* Return the number of bytes in the current event. -Returns 0 if the event is in an internal entity. */ - -int XMLPARSEAPI XML_GetCurrentByteCount(XML_Parser parser); - -/* For backwards compatibility with previous versions. */ -#define XML_GetErrorLineNumber XML_GetCurrentLineNumber -#define XML_GetErrorColumnNumber XML_GetCurrentColumnNumber -#define XML_GetErrorByteIndex XML_GetCurrentByteIndex - -/* Frees memory used by the parser. */ -void XMLPARSEAPI -XML_ParserFree(XML_Parser parser); - -/* Returns a string describing the error. */ -const XML_LChar XMLPARSEAPI *XML_ErrorString(int code); - -#ifdef __cplusplus -} -#endif - -#endif /* not XmlParse_INCLUDED */ diff --git a/protocols/jabber/xmlrole.c b/protocols/jabber/xmlrole.c deleted file mode 100644 index 320749e8..00000000 --- a/protocols/jabber/xmlrole.c +++ /dev/null @@ -1,1104 +0,0 @@ -/* -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in -compliance with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" -basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -License for the specific language governing rights and limitations -under the License. - -The Original Code is expat. - -The Initial Developer of the Original Code is James Clark. -Portions created by James Clark are Copyright (C) 1998, 1999 -James Clark. All Rights Reserved. - -Contributor(s): - -*/ - -#include "xmldef.h" -#include "xmlrole.h" - -/* Doesn't check: - - that ,| are not mixed in a model group - content of literals - -*/ - -#ifndef MIN_BYTES_PER_CHAR -#define MIN_BYTES_PER_CHAR(enc) ((enc)->minBytesPerChar) -#endif - -typedef int PROLOG_HANDLER(struct prolog_state *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc); - -static PROLOG_HANDLER -prolog0, prolog1, prolog2, -doctype0, doctype1, doctype2, doctype3, doctype4, doctype5, -internalSubset, -entity0, entity1, entity2, entity3, entity4, entity5, entity6, -entity7, entity8, entity9, -notation0, notation1, notation2, notation3, notation4, -attlist0, attlist1, attlist2, attlist3, attlist4, attlist5, attlist6, -attlist7, attlist8, attlist9, -element0, element1, element2, element3, element4, element5, element6, -element7, -declClose, -error; - -static -int syntaxError(PROLOG_STATE *); - -static -int prolog0(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - state->handler = prolog1; - return XML_ROLE_NONE; - case XML_TOK_XML_DECL: - state->handler = prolog1; - return XML_ROLE_XML_DECL; - case XML_TOK_PI: - state->handler = prolog1; - return XML_ROLE_NONE; - case XML_TOK_COMMENT: - state->handler = prolog1; - case XML_TOK_BOM: - return XML_ROLE_NONE; - case XML_TOK_DECL_OPEN: - if (!XmlNameMatchesAscii(enc, - ptr + 2 * MIN_BYTES_PER_CHAR(enc), - "DOCTYPE")) - break; - state->handler = doctype0; - return XML_ROLE_NONE; - case XML_TOK_INSTANCE_START: - state->handler = error; - return XML_ROLE_INSTANCE_START; - } - return syntaxError(state); -} - -static -int prolog1(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_PI: - case XML_TOK_COMMENT: - case XML_TOK_BOM: - return XML_ROLE_NONE; - case XML_TOK_DECL_OPEN: - if (!XmlNameMatchesAscii(enc, - ptr + 2 * MIN_BYTES_PER_CHAR(enc), - "DOCTYPE")) - break; - state->handler = doctype0; - return XML_ROLE_NONE; - case XML_TOK_INSTANCE_START: - state->handler = error; - return XML_ROLE_INSTANCE_START; - } - return syntaxError(state); -} - -static -int prolog2(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_PI: - case XML_TOK_COMMENT: - return XML_ROLE_NONE; - case XML_TOK_INSTANCE_START: - state->handler = error; - return XML_ROLE_INSTANCE_START; - } - return syntaxError(state); -} - -static -int doctype0(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_NAME: - case XML_TOK_PREFIXED_NAME: - state->handler = doctype1; - return XML_ROLE_DOCTYPE_NAME; - } - return syntaxError(state); -} - -static -int doctype1(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_OPEN_BRACKET: - state->handler = internalSubset; - return XML_ROLE_NONE; - case XML_TOK_DECL_CLOSE: - state->handler = prolog2; - return XML_ROLE_DOCTYPE_CLOSE; - case XML_TOK_NAME: - if (XmlNameMatchesAscii(enc, ptr, "SYSTEM")) { - state->handler = doctype3; - return XML_ROLE_NONE; - } - if (XmlNameMatchesAscii(enc, ptr, "PUBLIC")) { - state->handler = doctype2; - return XML_ROLE_NONE; - } - break; - } - return syntaxError(state); -} - -static -int doctype2(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_LITERAL: - state->handler = doctype3; - return XML_ROLE_DOCTYPE_PUBLIC_ID; - } - return syntaxError(state); -} - -static -int doctype3(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_LITERAL: - state->handler = doctype4; - return XML_ROLE_DOCTYPE_SYSTEM_ID; - } - return syntaxError(state); -} - -static -int doctype4(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_OPEN_BRACKET: - state->handler = internalSubset; - return XML_ROLE_NONE; - case XML_TOK_DECL_CLOSE: - state->handler = prolog2; - return XML_ROLE_DOCTYPE_CLOSE; - } - return syntaxError(state); -} - -static -int doctype5(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_DECL_CLOSE: - state->handler = prolog2; - return XML_ROLE_DOCTYPE_CLOSE; - } - return syntaxError(state); -} - -static -int internalSubset(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_DECL_OPEN: - if (XmlNameMatchesAscii(enc, - ptr + 2 * MIN_BYTES_PER_CHAR(enc), - "ENTITY")) { - state->handler = entity0; - return XML_ROLE_NONE; - } - if (XmlNameMatchesAscii(enc, - ptr + 2 * MIN_BYTES_PER_CHAR(enc), - "ATTLIST")) { - state->handler = attlist0; - return XML_ROLE_NONE; - } - if (XmlNameMatchesAscii(enc, - ptr + 2 * MIN_BYTES_PER_CHAR(enc), - "ELEMENT")) { - state->handler = element0; - return XML_ROLE_NONE; - } - if (XmlNameMatchesAscii(enc, - ptr + 2 * MIN_BYTES_PER_CHAR(enc), - "NOTATION")) { - state->handler = notation0; - return XML_ROLE_NONE; - } - break; - case XML_TOK_PI: - case XML_TOK_COMMENT: - return XML_ROLE_NONE; - case XML_TOK_PARAM_ENTITY_REF: - return XML_ROLE_PARAM_ENTITY_REF; - case XML_TOK_CLOSE_BRACKET: - state->handler = doctype5; - return XML_ROLE_NONE; - } - return syntaxError(state); -} - -static -int entity0(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_PERCENT: - state->handler = entity1; - return XML_ROLE_NONE; - case XML_TOK_NAME: - state->handler = entity2; - return XML_ROLE_GENERAL_ENTITY_NAME; - } - return syntaxError(state); -} - -static -int entity1(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_NAME: - state->handler = entity7; - return XML_ROLE_PARAM_ENTITY_NAME; - } - return syntaxError(state); -} - -static -int entity2(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_NAME: - if (XmlNameMatchesAscii(enc, ptr, "SYSTEM")) { - state->handler = entity4; - return XML_ROLE_NONE; - } - if (XmlNameMatchesAscii(enc, ptr, "PUBLIC")) { - state->handler = entity3; - return XML_ROLE_NONE; - } - break; - case XML_TOK_LITERAL: - state->handler = declClose; - return XML_ROLE_ENTITY_VALUE; - } - return syntaxError(state); -} - -static -int entity3(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_LITERAL: - state->handler = entity4; - return XML_ROLE_ENTITY_PUBLIC_ID; - } - return syntaxError(state); -} - - -static -int entity4(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_LITERAL: - state->handler = entity5; - return XML_ROLE_ENTITY_SYSTEM_ID; - } - return syntaxError(state); -} - -static -int entity5(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_DECL_CLOSE: - state->handler = internalSubset; - return XML_ROLE_NONE; - case XML_TOK_NAME: - if (XmlNameMatchesAscii(enc, ptr, "NDATA")) { - state->handler = entity6; - return XML_ROLE_NONE; - } - break; - } - return syntaxError(state); -} - -static -int entity6(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_NAME: - state->handler = declClose; - return XML_ROLE_ENTITY_NOTATION_NAME; - } - return syntaxError(state); -} - -static -int entity7(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_NAME: - if (XmlNameMatchesAscii(enc, ptr, "SYSTEM")) { - state->handler = entity9; - return XML_ROLE_NONE; - } - if (XmlNameMatchesAscii(enc, ptr, "PUBLIC")) { - state->handler = entity8; - return XML_ROLE_NONE; - } - break; - case XML_TOK_LITERAL: - state->handler = declClose; - return XML_ROLE_ENTITY_VALUE; - } - return syntaxError(state); -} - -static -int entity8(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_LITERAL: - state->handler = entity9; - return XML_ROLE_ENTITY_PUBLIC_ID; - } - return syntaxError(state); -} - -static -int entity9(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_LITERAL: - state->handler = declClose; - return XML_ROLE_ENTITY_SYSTEM_ID; - } - return syntaxError(state); -} - -static -int notation0(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_NAME: - state->handler = notation1; - return XML_ROLE_NOTATION_NAME; - } - return syntaxError(state); -} - -static -int notation1(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_NAME: - if (XmlNameMatchesAscii(enc, ptr, "SYSTEM")) { - state->handler = notation3; - return XML_ROLE_NONE; - } - if (XmlNameMatchesAscii(enc, ptr, "PUBLIC")) { - state->handler = notation2; - return XML_ROLE_NONE; - } - break; - } - return syntaxError(state); -} - -static -int notation2(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_LITERAL: - state->handler = notation4; - return XML_ROLE_NOTATION_PUBLIC_ID; - } - return syntaxError(state); -} - -static -int notation3(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_LITERAL: - state->handler = declClose; - return XML_ROLE_NOTATION_SYSTEM_ID; - } - return syntaxError(state); -} - -static -int notation4(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_LITERAL: - state->handler = declClose; - return XML_ROLE_NOTATION_SYSTEM_ID; - case XML_TOK_DECL_CLOSE: - state->handler = internalSubset; - return XML_ROLE_NOTATION_NO_SYSTEM_ID; - } - return syntaxError(state); -} - -static -int attlist0(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_NAME: - case XML_TOK_PREFIXED_NAME: - state->handler = attlist1; - return XML_ROLE_ATTLIST_ELEMENT_NAME; - } - return syntaxError(state); -} - -static -int attlist1(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_DECL_CLOSE: - state->handler = internalSubset; - return XML_ROLE_NONE; - case XML_TOK_NAME: - case XML_TOK_PREFIXED_NAME: - state->handler = attlist2; - return XML_ROLE_ATTRIBUTE_NAME; - } - return syntaxError(state); -} - -static -int attlist2(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_NAME: - { - static const char *types[] = { - "CDATA", - "ID", - "IDREF", - "IDREFS", - "ENTITY", - "ENTITIES", - "NMTOKEN", - "NMTOKENS", - }; - int i; - for (i = 0; i < (int)(sizeof(types)/sizeof(types[0])); i++) - if (XmlNameMatchesAscii(enc, ptr, types[i])) { - state->handler = attlist8; - return XML_ROLE_ATTRIBUTE_TYPE_CDATA + i; - } - } - if (XmlNameMatchesAscii(enc, ptr, "NOTATION")) { - state->handler = attlist5; - return XML_ROLE_NONE; - } - break; - case XML_TOK_OPEN_PAREN: - state->handler = attlist3; - return XML_ROLE_NONE; - } - return syntaxError(state); -} - -static -int attlist3(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_NMTOKEN: - case XML_TOK_NAME: - case XML_TOK_PREFIXED_NAME: - state->handler = attlist4; - return XML_ROLE_ATTRIBUTE_ENUM_VALUE; - } - return syntaxError(state); -} - -static -int attlist4(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_CLOSE_PAREN: - state->handler = attlist8; - return XML_ROLE_NONE; - case XML_TOK_OR: - state->handler = attlist3; - return XML_ROLE_NONE; - } - return syntaxError(state); -} - -static -int attlist5(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_OPEN_PAREN: - state->handler = attlist6; - return XML_ROLE_NONE; - } - return syntaxError(state); -} - - -static -int attlist6(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_NAME: - state->handler = attlist7; - return XML_ROLE_ATTRIBUTE_NOTATION_VALUE; - } - return syntaxError(state); -} - -static -int attlist7(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_CLOSE_PAREN: - state->handler = attlist8; - return XML_ROLE_NONE; - case XML_TOK_OR: - state->handler = attlist6; - return XML_ROLE_NONE; - } - return syntaxError(state); -} - -/* default value */ -static -int attlist8(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_POUND_NAME: - if (XmlNameMatchesAscii(enc, - ptr + MIN_BYTES_PER_CHAR(enc), - "IMPLIED")) { - state->handler = attlist1; - return XML_ROLE_IMPLIED_ATTRIBUTE_VALUE; - } - if (XmlNameMatchesAscii(enc, - ptr + MIN_BYTES_PER_CHAR(enc), - "REQUIRED")) { - state->handler = attlist1; - return XML_ROLE_REQUIRED_ATTRIBUTE_VALUE; - } - if (XmlNameMatchesAscii(enc, - ptr + MIN_BYTES_PER_CHAR(enc), - "FIXED")) { - state->handler = attlist9; - return XML_ROLE_NONE; - } - break; - case XML_TOK_LITERAL: - state->handler = attlist1; - return XML_ROLE_DEFAULT_ATTRIBUTE_VALUE; - } - return syntaxError(state); -} - -static -int attlist9(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_LITERAL: - state->handler = attlist1; - return XML_ROLE_FIXED_ATTRIBUTE_VALUE; - } - return syntaxError(state); -} - -static -int element0(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_NAME: - case XML_TOK_PREFIXED_NAME: - state->handler = element1; - return XML_ROLE_ELEMENT_NAME; - } - return syntaxError(state); -} - -static -int element1(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_NAME: - if (XmlNameMatchesAscii(enc, ptr, "EMPTY")) { - state->handler = declClose; - return XML_ROLE_CONTENT_EMPTY; - } - if (XmlNameMatchesAscii(enc, ptr, "ANY")) { - state->handler = declClose; - return XML_ROLE_CONTENT_ANY; - } - break; - case XML_TOK_OPEN_PAREN: - state->handler = element2; - state->level = 1; - return XML_ROLE_GROUP_OPEN; - } - return syntaxError(state); -} - -static -int element2(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_POUND_NAME: - if (XmlNameMatchesAscii(enc, - ptr + MIN_BYTES_PER_CHAR(enc), - "PCDATA")) { - state->handler = element3; - return XML_ROLE_CONTENT_PCDATA; - } - break; - case XML_TOK_OPEN_PAREN: - state->level = 2; - state->handler = element6; - return XML_ROLE_GROUP_OPEN; - case XML_TOK_NAME: - case XML_TOK_PREFIXED_NAME: - state->handler = element7; - return XML_ROLE_CONTENT_ELEMENT; - case XML_TOK_NAME_QUESTION: - state->handler = element7; - return XML_ROLE_CONTENT_ELEMENT_OPT; - case XML_TOK_NAME_ASTERISK: - state->handler = element7; - return XML_ROLE_CONTENT_ELEMENT_REP; - case XML_TOK_NAME_PLUS: - state->handler = element7; - return XML_ROLE_CONTENT_ELEMENT_PLUS; - } - return syntaxError(state); -} - -static -int element3(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_CLOSE_PAREN: - case XML_TOK_CLOSE_PAREN_ASTERISK: - state->handler = declClose; - return XML_ROLE_GROUP_CLOSE_REP; - case XML_TOK_OR: - state->handler = element4; - return XML_ROLE_NONE; - } - return syntaxError(state); -} - -static -int element4(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_NAME: - case XML_TOK_PREFIXED_NAME: - state->handler = element5; - return XML_ROLE_CONTENT_ELEMENT; - } - return syntaxError(state); -} - -static -int element5(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_CLOSE_PAREN_ASTERISK: - state->handler = declClose; - return XML_ROLE_GROUP_CLOSE_REP; - case XML_TOK_OR: - state->handler = element4; - return XML_ROLE_NONE; - } - return syntaxError(state); -} - -static -int element6(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_OPEN_PAREN: - state->level += 1; - return XML_ROLE_GROUP_OPEN; - case XML_TOK_NAME: - case XML_TOK_PREFIXED_NAME: - state->handler = element7; - return XML_ROLE_CONTENT_ELEMENT; - case XML_TOK_NAME_QUESTION: - state->handler = element7; - return XML_ROLE_CONTENT_ELEMENT_OPT; - case XML_TOK_NAME_ASTERISK: - state->handler = element7; - return XML_ROLE_CONTENT_ELEMENT_REP; - case XML_TOK_NAME_PLUS: - state->handler = element7; - return XML_ROLE_CONTENT_ELEMENT_PLUS; - } - return syntaxError(state); -} - -static -int element7(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_CLOSE_PAREN: - state->level -= 1; - if (state->level == 0) - state->handler = declClose; - return XML_ROLE_GROUP_CLOSE; - case XML_TOK_CLOSE_PAREN_ASTERISK: - state->level -= 1; - if (state->level == 0) - state->handler = declClose; - return XML_ROLE_GROUP_CLOSE_REP; - case XML_TOK_CLOSE_PAREN_QUESTION: - state->level -= 1; - if (state->level == 0) - state->handler = declClose; - return XML_ROLE_GROUP_CLOSE_OPT; - case XML_TOK_CLOSE_PAREN_PLUS: - state->level -= 1; - if (state->level == 0) - state->handler = declClose; - return XML_ROLE_GROUP_CLOSE_PLUS; - case XML_TOK_COMMA: - state->handler = element6; - return XML_ROLE_GROUP_SEQUENCE; - case XML_TOK_OR: - state->handler = element6; - return XML_ROLE_GROUP_CHOICE; - } - return syntaxError(state); -} - -static -int declClose(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_DECL_CLOSE: - state->handler = internalSubset; - return XML_ROLE_NONE; - } - return syntaxError(state); -} - -#if 0 - -static -int ignore(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_DECL_CLOSE: - state->handler = internalSubset; - return 0; - default: - return XML_ROLE_NONE; - } - return syntaxError(state); -} -#endif - -static -int error(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - return XML_ROLE_NONE; -} - -static -int syntaxError(PROLOG_STATE *state) -{ - state->handler = error; - return XML_ROLE_ERROR; -} - -void XmlPrologStateInit(PROLOG_STATE *state) -{ - state->handler = prolog0; -} diff --git a/protocols/jabber/xmlrole.h b/protocols/jabber/xmlrole.h deleted file mode 100644 index 877c40ba..00000000 --- a/protocols/jabber/xmlrole.h +++ /dev/null @@ -1,111 +0,0 @@ -/* -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in -compliance with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" -basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -License for the specific language governing rights and limitations -under the License. - -The Original Code is expat. - -The Initial Developer of the Original Code is James Clark. -Portions created by James Clark are Copyright (C) 1998, 1999 -James Clark. All Rights Reserved. - -Contributor(s): - -Alternatively, the contents of this file may be used under the terms -of the GNU General Public License (the "GPL"), in which case the -provisions of the GPL are applicable instead of those above. If you -wish to allow use of your version of this file only under the terms of -the GPL and not to allow others to use your version of this file under -the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the -GPL. If you do not delete the provisions above, a recipient may use -your version of this file under either the MPL or the GPL. -*/ - -#ifndef XmlRole_INCLUDED -#define XmlRole_INCLUDED 1 - -#include "xmltok.h" - -#ifdef __cplusplus -extern "C" { -#endif - -enum { - XML_ROLE_ERROR = -1, - XML_ROLE_NONE = 0, - XML_ROLE_XML_DECL, - XML_ROLE_INSTANCE_START, - XML_ROLE_DOCTYPE_NAME, - XML_ROLE_DOCTYPE_SYSTEM_ID, - XML_ROLE_DOCTYPE_PUBLIC_ID, - XML_ROLE_DOCTYPE_CLOSE, - XML_ROLE_GENERAL_ENTITY_NAME, - XML_ROLE_PARAM_ENTITY_NAME, - XML_ROLE_ENTITY_VALUE, - XML_ROLE_ENTITY_SYSTEM_ID, - XML_ROLE_ENTITY_PUBLIC_ID, - XML_ROLE_ENTITY_NOTATION_NAME, - XML_ROLE_NOTATION_NAME, - XML_ROLE_NOTATION_SYSTEM_ID, - XML_ROLE_NOTATION_NO_SYSTEM_ID, - XML_ROLE_NOTATION_PUBLIC_ID, - XML_ROLE_ATTRIBUTE_NAME, - XML_ROLE_ATTRIBUTE_TYPE_CDATA, - XML_ROLE_ATTRIBUTE_TYPE_ID, - XML_ROLE_ATTRIBUTE_TYPE_IDREF, - XML_ROLE_ATTRIBUTE_TYPE_IDREFS, - XML_ROLE_ATTRIBUTE_TYPE_ENTITY, - XML_ROLE_ATTRIBUTE_TYPE_ENTITIES, - XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN, - XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS, - XML_ROLE_ATTRIBUTE_ENUM_VALUE, - XML_ROLE_ATTRIBUTE_NOTATION_VALUE, - XML_ROLE_ATTLIST_ELEMENT_NAME, - XML_ROLE_IMPLIED_ATTRIBUTE_VALUE, - XML_ROLE_REQUIRED_ATTRIBUTE_VALUE, - XML_ROLE_DEFAULT_ATTRIBUTE_VALUE, - XML_ROLE_FIXED_ATTRIBUTE_VALUE, - XML_ROLE_ELEMENT_NAME, - XML_ROLE_CONTENT_ANY, - XML_ROLE_CONTENT_EMPTY, - XML_ROLE_CONTENT_PCDATA, - XML_ROLE_GROUP_OPEN, - XML_ROLE_GROUP_CLOSE, - XML_ROLE_GROUP_CLOSE_REP, - XML_ROLE_GROUP_CLOSE_OPT, - XML_ROLE_GROUP_CLOSE_PLUS, - XML_ROLE_GROUP_CHOICE, - XML_ROLE_GROUP_SEQUENCE, - XML_ROLE_CONTENT_ELEMENT, - XML_ROLE_CONTENT_ELEMENT_REP, - XML_ROLE_CONTENT_ELEMENT_OPT, - XML_ROLE_CONTENT_ELEMENT_PLUS, - XML_ROLE_PARAM_ENTITY_REF -}; - -typedef struct prolog_state { - int (*handler)(struct prolog_state *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc); - unsigned level; -} PROLOG_STATE; - -void XMLTOKAPI XmlPrologStateInit(PROLOG_STATE *); - -#define XmlTokenRole(state, tok, ptr, end, enc) \ - (((state)->handler)(state, tok, ptr, end, enc)) - -#ifdef __cplusplus -} -#endif - -#endif /* not XmlRole_INCLUDED */ diff --git a/protocols/jabber/xmltok.c b/protocols/jabber/xmltok.c deleted file mode 100644 index 8b7ae15e..00000000 --- a/protocols/jabber/xmltok.c +++ /dev/null @@ -1,1518 +0,0 @@ -/* -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in -compliance with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" -basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -License for the specific language governing rights and limitations -under the License. - -The Original Code is expat. - -The Initial Developer of the Original Code is James Clark. -Portions created by James Clark are Copyright (C) 1998, 1999 -James Clark. All Rights Reserved. - -Contributor(s): - -*/ - -#include "xmldef.h" -#include "xmltok.h" -#include "nametab.h" - -#define VTABLE1 \ - { PREFIX(prologTok), PREFIX(contentTok), PREFIX(cdataSectionTok) }, \ - { PREFIX(attributeValueTok), PREFIX(entityValueTok) }, \ - PREFIX(sameName), \ - PREFIX(nameMatchesAscii), \ - PREFIX(nameLength), \ - PREFIX(skipS), \ - PREFIX(getAtts), \ - PREFIX(charRefNumber), \ - PREFIX(predefinedEntityName), \ - PREFIX(updatePosition), \ - PREFIX(isPublicId) - -#define VTABLE VTABLE1, PREFIX(toUtf8), PREFIX(toUtf16) - -#define UCS2_GET_NAMING(pages, hi, lo) \ - (namingBitmap[(pages[hi] << 3) + ((lo) >> 5)] & (1 << ((lo) & 0x1F))) - -/* A 2 byte UTF-8 representation splits the characters 11 bits -between the bottom 5 and 6 bits of the bytes. -We need 8 bits to index into pages, 3 bits to add to that index and -5 bits to generate the mask. */ -#define UTF8_GET_NAMING2(pages, byte) \ - (namingBitmap[((pages)[(((byte)[0]) >> 2) & 7] << 3) \ - + ((((byte)[0]) & 3) << 1) \ - + ((((byte)[1]) >> 5) & 1)] \ - & (1 << (((byte)[1]) & 0x1F))) - -/* A 3 byte UTF-8 representation splits the characters 16 bits -between the bottom 4, 6 and 6 bits of the bytes. -We need 8 bits to index into pages, 3 bits to add to that index and -5 bits to generate the mask. */ -#define UTF8_GET_NAMING3(pages, byte) \ - (namingBitmap[((pages)[((((byte)[0]) & 0xF) << 4) \ - + ((((byte)[1]) >> 2) & 0xF)] \ - << 3) \ - + ((((byte)[1]) & 3) << 1) \ - + ((((byte)[2]) >> 5) & 1)] \ - & (1 << (((byte)[2]) & 0x1F))) - -#define UTF8_GET_NAMING(pages, p, n) \ - ((n) == 2 \ - ? UTF8_GET_NAMING2(pages, (const unsigned char *)(p)) \ - : ((n) == 3 \ - ? UTF8_GET_NAMING3(pages, (const unsigned char *)(p)) \ - : 0)) - -#define UTF8_INVALID3(p) \ - ((*p) == 0xED \ - ? (((p)[1] & 0x20) != 0) \ - : ((*p) == 0xEF \ - ? ((p)[1] == 0xBF && ((p)[2] == 0xBF || (p)[2] == 0xBE)) \ - : 0)) - -#define UTF8_INVALID4(p) ((*p) == 0xF4 && ((p)[1] & 0x30) != 0) - -static -int isNever(const ENCODING *enc, const char *p) -{ - return 0; -} - -static -int utf8_isName2(const ENCODING *enc, const char *p) -{ - return UTF8_GET_NAMING2(namePages, (const unsigned char *)p); -} - -static -int utf8_isName3(const ENCODING *enc, const char *p) -{ - return UTF8_GET_NAMING3(namePages, (const unsigned char *)p); -} - -#define utf8_isName4 isNever - -static -int utf8_isNmstrt2(const ENCODING *enc, const char *p) -{ - return UTF8_GET_NAMING2(nmstrtPages, (const unsigned char *)p); -} - -static -int utf8_isNmstrt3(const ENCODING *enc, const char *p) -{ - return UTF8_GET_NAMING3(nmstrtPages, (const unsigned char *)p); -} - -#define utf8_isNmstrt4 isNever - -#define utf8_isInvalid2 isNever - -static -int utf8_isInvalid3(const ENCODING *enc, const char *p) -{ - return UTF8_INVALID3((const unsigned char *)p); -} - -static -int utf8_isInvalid4(const ENCODING *enc, const char *p) -{ - return UTF8_INVALID4((const unsigned char *)p); -} - -struct normal_encoding { - ENCODING enc; - unsigned char type[256]; -#ifdef XML_MIN_SIZE - int (*byteType)(const ENCODING *, const char *); - int (*isNameMin)(const ENCODING *, const char *); - int (*isNmstrtMin)(const ENCODING *, const char *); - int (*byteToAscii)(const ENCODING *, const char *); - int (*charMatches)(const ENCODING *, const char *, int); -#endif /* XML_MIN_SIZE */ - int (*isName2)(const ENCODING *, const char *); - int (*isName3)(const ENCODING *, const char *); - int (*isName4)(const ENCODING *, const char *); - int (*isNmstrt2)(const ENCODING *, const char *); - int (*isNmstrt3)(const ENCODING *, const char *); - int (*isNmstrt4)(const ENCODING *, const char *); - int (*isInvalid2)(const ENCODING *, const char *); - int (*isInvalid3)(const ENCODING *, const char *); - int (*isInvalid4)(const ENCODING *, const char *); -}; - -#ifdef XML_MIN_SIZE - -#define STANDARD_VTABLE(E) \ - E ## byteType, \ - E ## isNameMin, \ - E ## isNmstrtMin, \ - E ## byteToAscii, \ - E ## charMatches, - -#else - -#define STANDARD_VTABLE(E) /* as nothing */ - -#endif - -#define NORMAL_VTABLE(E) \ - E ## isName2, \ - E ## isName3, \ - E ## isName4, \ - E ## isNmstrt2, \ - E ## isNmstrt3, \ - E ## isNmstrt4, \ - E ## isInvalid2, \ - E ## isInvalid3, \ - E ## isInvalid4 - -static int checkCharRefNumber(int); - -#include "xmltok_impl.h" - -#ifdef XML_MIN_SIZE -#define sb_isNameMin isNever -#define sb_isNmstrtMin isNever -#endif - -#ifdef XML_MIN_SIZE -#define MINBPC(enc) ((enc)->minBytesPerChar) -#else -/* minimum bytes per character */ -#define MINBPC(enc) 1 -#endif - -#define SB_BYTE_TYPE(enc, p) \ - (((struct normal_encoding *)(enc))->type[(unsigned char)*(p)]) - -#ifdef XML_MIN_SIZE -static -int sb_byteType(const ENCODING *enc, const char *p) -{ - return SB_BYTE_TYPE(enc, p); -} -#define BYTE_TYPE(enc, p) \ - (((const struct normal_encoding *)(enc))->byteType(enc, p)) -#else -#define BYTE_TYPE(enc, p) SB_BYTE_TYPE(enc, p) -#endif - -#ifdef XML_MIN_SIZE -#define BYTE_TO_ASCII(enc, p) \ - (((const struct normal_encoding *)(enc))->byteToAscii(enc, p)) -static -int sb_byteToAscii(const ENCODING *enc, const char *p) -{ - return *p; -} -#else -#define BYTE_TO_ASCII(enc, p) (*p) -#endif - -#define IS_NAME_CHAR(enc, p, n) \ - (((const struct normal_encoding *)(enc))->isName ## n(enc, p)) -#define IS_NMSTRT_CHAR(enc, p, n) \ - (((const struct normal_encoding *)(enc))->isNmstrt ## n(enc, p)) -#define IS_INVALID_CHAR(enc, p, n) \ - (((const struct normal_encoding *)(enc))->isInvalid ## n(enc, p)) - -#ifdef XML_MIN_SIZE -#define IS_NAME_CHAR_MINBPC(enc, p) \ - (((const struct normal_encoding *)(enc))->isNameMin(enc, p)) -#define IS_NMSTRT_CHAR_MINBPC(enc, p) \ - (((const struct normal_encoding *)(enc))->isNmstrtMin(enc, p)) -#else -#define IS_NAME_CHAR_MINBPC(enc, p) (0) -#define IS_NMSTRT_CHAR_MINBPC(enc, p) (0) -#endif - -#ifdef XML_MIN_SIZE -#define CHAR_MATCHES(enc, p, c) \ - (((const struct normal_encoding *)(enc))->charMatches(enc, p, c)) -static -int sb_charMatches(const ENCODING *enc, const char *p, int c) -{ - return *p == c; -} -#else -/* c is an ASCII character */ -#define CHAR_MATCHES(enc, p, c) (*(p) == c) -#endif - -#define PREFIX(ident) normal_ ## ident -#include "xmltok_impl.c" - -#undef MINBPC -#undef BYTE_TYPE -#undef BYTE_TO_ASCII -#undef CHAR_MATCHES -#undef IS_NAME_CHAR -#undef IS_NAME_CHAR_MINBPC -#undef IS_NMSTRT_CHAR -#undef IS_NMSTRT_CHAR_MINBPC -#undef IS_INVALID_CHAR - -enum { /* UTF8_cvalN is value of masked first byte of N byte sequence */ - UTF8_cval1 = 0x00, - UTF8_cval2 = 0xc0, - UTF8_cval3 = 0xe0, - UTF8_cval4 = 0xf0 -}; - -static -void utf8_toUtf8(const ENCODING *enc, - const char **fromP, const char *fromLim, - char **toP, const char *toLim) -{ - char *to; - const char *from; - if (fromLim - *fromP > toLim - *toP) { - /* Avoid copying partial characters. */ - for (fromLim = *fromP + (toLim - *toP); fromLim > *fromP; fromLim--) - if (((unsigned char)fromLim[-1] & 0xc0) != 0x80) - break; - } - for (to = *toP, from = *fromP; from != fromLim; from++, to++) - *to = *from; - *fromP = from; - *toP = to; -} - -static -void utf8_toUtf16(const ENCODING *enc, - const char **fromP, const char *fromLim, - unsigned short **toP, const unsigned short *toLim) -{ - unsigned short *to = *toP; - const char *from = *fromP; - while (from != fromLim && to != toLim) { - switch (((struct normal_encoding *)enc)->type[(unsigned char)*from]) { - case BT_LEAD2: - *to++ = ((from[0] & 0x1f) << 6) | (from[1] & 0x3f); - from += 2; - break; - case BT_LEAD3: - *to++ = ((from[0] & 0xf) << 12) | ((from[1] & 0x3f) << 6) | (from[2] & 0x3f); - from += 3; - break; - case BT_LEAD4: - { - unsigned long n; - if (to + 1 == toLim) - break; - n = ((from[0] & 0x7) << 18) | ((from[1] & 0x3f) << 12) | ((from[2] & 0x3f) << 6) | (from[3] & 0x3f); - n -= 0x10000; - to[0] = (unsigned short)((n >> 10) | 0xD800); - to[1] = (unsigned short)((n & 0x3FF) | 0xDC00); - to += 2; - from += 4; - } - break; - default: - *to++ = *from++; - break; - } - } - *fromP = from; - *toP = to; -} - -#ifdef XML_NS -static const struct normal_encoding utf8_encoding_ns = { - { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 }, - { -#include "asciitab.h" -#include "utf8tab.h" - }, - STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_) - }; -#endif - -static const struct normal_encoding utf8_encoding = { - { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 }, - { -#define BT_COLON BT_NMSTRT -#include "asciitab.h" -#undef BT_COLON -#include "utf8tab.h" - }, - STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_) - }; - -#ifdef XML_NS - -static const struct normal_encoding internal_utf8_encoding_ns = { - { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 }, - { -#include "iasciitab.h" -#include "utf8tab.h" - }, - STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_) - }; - -#endif - -static const struct normal_encoding internal_utf8_encoding = { - { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 }, - { -#define BT_COLON BT_NMSTRT -#include "iasciitab.h" -#undef BT_COLON -#include "utf8tab.h" - }, - STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_) - }; - -static -void latin1_toUtf8(const ENCODING *enc, - const char **fromP, const char *fromLim, - char **toP, const char *toLim) -{ - for (;;) { - unsigned char c; - if (*fromP == fromLim) - break; - c = (unsigned char)**fromP; - if (c & 0x80) { - if (toLim - *toP < 2) - break; - *(*toP)++ = ((c >> 6) | UTF8_cval2); - *(*toP)++ = ((c & 0x3f) | 0x80); - (*fromP)++; - } - else { - if (*toP == toLim) - break; - *(*toP)++ = *(*fromP)++; - } - } -} - -static -void latin1_toUtf16(const ENCODING *enc, - const char **fromP, const char *fromLim, - unsigned short **toP, const unsigned short *toLim) -{ - while (*fromP != fromLim && *toP != toLim) - *(*toP)++ = (unsigned char)*(*fromP)++; -} - -#ifdef XML_NS - -static const struct normal_encoding latin1_encoding_ns = { - { VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0 }, - { -#include "asciitab.h" -#include "latin1tab.h" - }, - STANDARD_VTABLE(sb_) - }; - -#endif - -static const struct normal_encoding latin1_encoding = { - { VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0 }, - { -#define BT_COLON BT_NMSTRT -#include "asciitab.h" -#undef BT_COLON -#include "latin1tab.h" - }, - STANDARD_VTABLE(sb_) - }; - -static -void ascii_toUtf8(const ENCODING *enc, - const char **fromP, const char *fromLim, - char **toP, const char *toLim) -{ - while (*fromP != fromLim && *toP != toLim) - *(*toP)++ = *(*fromP)++; -} - -#ifdef XML_NS - -static const struct normal_encoding ascii_encoding_ns = { - { VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0 }, - { -#include "asciitab.h" - /* BT_NONXML == 0 */ - }, - STANDARD_VTABLE(sb_) - }; - -#endif - -static const struct normal_encoding ascii_encoding = { - { VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0 }, - { -#define BT_COLON BT_NMSTRT -#include "asciitab.h" -#undef BT_COLON - /* BT_NONXML == 0 */ - }, - STANDARD_VTABLE(sb_) - }; - -static int unicode_byte_type(char hi, char lo) -{ - switch ((unsigned char)hi) { -case 0xD8: case 0xD9: case 0xDA: case 0xDB: - return BT_LEAD4; -case 0xDC: case 0xDD: case 0xDE: case 0xDF: - return BT_TRAIL; - case 0xFF: - switch ((unsigned char)lo) { - case 0xFF: - case 0xFE: - return BT_NONXML; - } - break; - } - return BT_NONASCII; -} - -#define DEFINE_UTF16_TO_UTF8(E) \ -static \ -void E ## toUtf8(const ENCODING *enc, \ - const char **fromP, const char *fromLim, \ - char **toP, const char *toLim) \ -{ \ - const char *from; \ - for (from = *fromP; from != fromLim; from += 2) { \ - int plane; \ - unsigned char lo2; \ - unsigned char lo = GET_LO(from); \ - unsigned char hi = GET_HI(from); \ - switch (hi) { \ - case 0: \ - if (lo < 0x80) { \ - if (*toP == toLim) { \ - *fromP = from; \ - return; \ - } \ - *(*toP)++ = lo; \ - break; \ - } \ - /* fall through */ \ - case 0x1: case 0x2: case 0x3: \ - case 0x4: case 0x5: case 0x6: case 0x7: \ - if (toLim - *toP < 2) { \ - *fromP = from; \ - return; \ - } \ - *(*toP)++ = ((lo >> 6) | (hi << 2) | UTF8_cval2); \ - *(*toP)++ = ((lo & 0x3f) | 0x80); \ - break; \ - default: \ - if (toLim - *toP < 3) { \ - *fromP = from; \ - return; \ - } \ - /* 16 bits divided 4, 6, 6 amongst 3 bytes */ \ - *(*toP)++ = ((hi >> 4) | UTF8_cval3); \ - *(*toP)++ = (((hi & 0xf) << 2) | (lo >> 6) | 0x80); \ - *(*toP)++ = ((lo & 0x3f) | 0x80); \ - break; \ - case 0xD8: case 0xD9: case 0xDA: case 0xDB: \ - if (toLim - *toP < 4) { \ - *fromP = from; \ - return; \ - } \ - plane = (((hi & 0x3) << 2) | ((lo >> 6) & 0x3)) + 1; \ - *(*toP)++ = ((plane >> 2) | UTF8_cval4); \ - *(*toP)++ = (((lo >> 2) & 0xF) | ((plane & 0x3) << 4) | 0x80); \ - from += 2; \ - lo2 = GET_LO(from); \ - *(*toP)++ = (((lo & 0x3) << 4) \ - | ((GET_HI(from) & 0x3) << 2) \ - | (lo2 >> 6) \ - | 0x80); \ - *(*toP)++ = ((lo2 & 0x3f) | 0x80); \ - break; \ - } \ - } \ - *fromP = from; \ -} - -#define DEFINE_UTF16_TO_UTF16(E) \ -static \ -void E ## toUtf16(const ENCODING *enc, \ - const char **fromP, const char *fromLim, \ - unsigned short **toP, const unsigned short *toLim) \ -{ \ - /* Avoid copying first half only of surrogate */ \ - if (fromLim - *fromP > ((toLim - *toP) << 1) \ - && (GET_HI(fromLim - 2) & 0xF8) == 0xD8) \ - fromLim -= 2; \ - for (; *fromP != fromLim && *toP != toLim; *fromP += 2) \ - *(*toP)++ = (GET_HI(*fromP) << 8) | GET_LO(*fromP); \ -} - -#define SET2(ptr, ch) \ - (((ptr)[0] = ((ch) & 0xff)), ((ptr)[1] = ((ch) >> 8))) -#define GET_LO(ptr) ((unsigned char)(ptr)[0]) -#define GET_HI(ptr) ((unsigned char)(ptr)[1]) - -DEFINE_UTF16_TO_UTF8(little2_) -DEFINE_UTF16_TO_UTF16(little2_) - -#undef SET2 -#undef GET_LO -#undef GET_HI - -#define SET2(ptr, ch) \ - (((ptr)[0] = ((ch) >> 8)), ((ptr)[1] = ((ch) & 0xFF))) -#define GET_LO(ptr) ((unsigned char)(ptr)[1]) -#define GET_HI(ptr) ((unsigned char)(ptr)[0]) - -DEFINE_UTF16_TO_UTF8(big2_) -DEFINE_UTF16_TO_UTF16(big2_) - -#undef SET2 -#undef GET_LO -#undef GET_HI - -#define LITTLE2_BYTE_TYPE(enc, p) \ - ((p)[1] == 0 \ - ? ((struct normal_encoding *)(enc))->type[(unsigned char)*(p)] \ - : unicode_byte_type((p)[1], (p)[0])) -#define LITTLE2_BYTE_TO_ASCII(enc, p) ((p)[1] == 0 ? (p)[0] : -1) -#define LITTLE2_CHAR_MATCHES(enc, p, c) ((p)[1] == 0 && (p)[0] == c) -#define LITTLE2_IS_NAME_CHAR_MINBPC(enc, p) \ - UCS2_GET_NAMING(namePages, (unsigned char)p[1], (unsigned char)p[0]) -#define LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p) \ - UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[1], (unsigned char)p[0]) - -#ifdef XML_MIN_SIZE - -static -int little2_byteType(const ENCODING *enc, const char *p) -{ - return LITTLE2_BYTE_TYPE(enc, p); -} - -static -int little2_byteToAscii(const ENCODING *enc, const char *p) -{ - return LITTLE2_BYTE_TO_ASCII(enc, p); -} - -static -int little2_charMatches(const ENCODING *enc, const char *p, int c) -{ - return LITTLE2_CHAR_MATCHES(enc, p, c); -} - -static -int little2_isNameMin(const ENCODING *enc, const char *p) -{ - return LITTLE2_IS_NAME_CHAR_MINBPC(enc, p); -} - -static -int little2_isNmstrtMin(const ENCODING *enc, const char *p) -{ - return LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p); -} - -#undef VTABLE -#define VTABLE VTABLE1, little2_toUtf8, little2_toUtf16 - -#else /* not XML_MIN_SIZE */ - -#undef PREFIX -#define PREFIX(ident) little2_ ## ident -#define MINBPC(enc) 2 -/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */ -#define BYTE_TYPE(enc, p) LITTLE2_BYTE_TYPE(enc, p) -#define BYTE_TO_ASCII(enc, p) LITTLE2_BYTE_TO_ASCII(enc, p) -#define CHAR_MATCHES(enc, p, c) LITTLE2_CHAR_MATCHES(enc, p, c) -#define IS_NAME_CHAR(enc, p, n) 0 -#define IS_NAME_CHAR_MINBPC(enc, p) LITTLE2_IS_NAME_CHAR_MINBPC(enc, p) -#define IS_NMSTRT_CHAR(enc, p, n) (0) -#define IS_NMSTRT_CHAR_MINBPC(enc, p) LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p) - -#include "xmltok_impl.c" - -#undef MINBPC -#undef BYTE_TYPE -#undef BYTE_TO_ASCII -#undef CHAR_MATCHES -#undef IS_NAME_CHAR -#undef IS_NAME_CHAR_MINBPC -#undef IS_NMSTRT_CHAR -#undef IS_NMSTRT_CHAR_MINBPC -#undef IS_INVALID_CHAR - -#endif /* not XML_MIN_SIZE */ - -#ifdef XML_NS - -static const struct normal_encoding little2_encoding_ns = { - { VTABLE, 2, 0, -#if XML_BYTE_ORDER == 12 - 1 -#else -0 -#endif - }, - { -#include "asciitab.h" -#include "latin1tab.h" - }, - STANDARD_VTABLE(little2_) - }; - -#endif - -static const struct normal_encoding little2_encoding = { - { VTABLE, 2, 0, -#if XML_BYTE_ORDER == 12 - 1 -#else - 0 -#endif - }, - { -#define BT_COLON BT_NMSTRT -#include "asciitab.h" -#undef BT_COLON -#include "latin1tab.h" - }, - STANDARD_VTABLE(little2_) - }; - -#if XML_BYTE_ORDER != 21 - -#ifdef XML_NS - -static const struct normal_encoding internal_little2_encoding_ns = { - { VTABLE, 2, 0, 1 }, - { -#include "iasciitab.h" -#include "latin1tab.h" - }, - STANDARD_VTABLE(little2_) - }; - -#endif - -static const struct normal_encoding internal_little2_encoding = { - { VTABLE, 2, 0, 1 }, - { -#define BT_COLON BT_NMSTRT -#include "iasciitab.h" -#undef BT_COLON -#include "latin1tab.h" - }, - STANDARD_VTABLE(little2_) - }; - -#endif - - -#define BIG2_BYTE_TYPE(enc, p) \ - ((p)[0] == 0 \ - ? ((struct normal_encoding *)(enc))->type[(unsigned char)(p)[1]] \ - : unicode_byte_type((p)[0], (p)[1])) -#define BIG2_BYTE_TO_ASCII(enc, p) ((p)[0] == 0 ? (p)[1] : -1) -#define BIG2_CHAR_MATCHES(enc, p, c) ((p)[0] == 0 && (p)[1] == c) -#define BIG2_IS_NAME_CHAR_MINBPC(enc, p) \ - UCS2_GET_NAMING(namePages, (unsigned char)p[0], (unsigned char)p[1]) -#define BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p) \ - UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[0], (unsigned char)p[1]) - -#ifdef XML_MIN_SIZE - -static -int big2_byteType(const ENCODING *enc, const char *p) -{ - return BIG2_BYTE_TYPE(enc, p); -} - -static -int big2_byteToAscii(const ENCODING *enc, const char *p) -{ - return BIG2_BYTE_TO_ASCII(enc, p); -} - -static -int big2_charMatches(const ENCODING *enc, const char *p, int c) -{ - return BIG2_CHAR_MATCHES(enc, p, c); -} - -static -int big2_isNameMin(const ENCODING *enc, const char *p) -{ - return BIG2_IS_NAME_CHAR_MINBPC(enc, p); -} - -static -int big2_isNmstrtMin(const ENCODING *enc, const char *p) -{ - return BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p); -} - -#undef VTABLE -#define VTABLE VTABLE1, big2_toUtf8, big2_toUtf16 - -#else /* not XML_MIN_SIZE */ - -#undef PREFIX -#define PREFIX(ident) big2_ ## ident -#define MINBPC(enc) 2 -/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */ -#define BYTE_TYPE(enc, p) BIG2_BYTE_TYPE(enc, p) -#define BYTE_TO_ASCII(enc, p) BIG2_BYTE_TO_ASCII(enc, p) -#define CHAR_MATCHES(enc, p, c) BIG2_CHAR_MATCHES(enc, p, c) -#define IS_NAME_CHAR(enc, p, n) 0 -#define IS_NAME_CHAR_MINBPC(enc, p) BIG2_IS_NAME_CHAR_MINBPC(enc, p) -#define IS_NMSTRT_CHAR(enc, p, n) (0) -#define IS_NMSTRT_CHAR_MINBPC(enc, p) BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p) - -#include "xmltok_impl.c" - -#undef MINBPC -#undef BYTE_TYPE -#undef BYTE_TO_ASCII -#undef CHAR_MATCHES -#undef IS_NAME_CHAR -#undef IS_NAME_CHAR_MINBPC -#undef IS_NMSTRT_CHAR -#undef IS_NMSTRT_CHAR_MINBPC -#undef IS_INVALID_CHAR - -#endif /* not XML_MIN_SIZE */ - -#ifdef XML_NS - -static const struct normal_encoding big2_encoding_ns = { - { VTABLE, 2, 0, -#if XML_BYTE_ORDER == 21 - 1 -#else -0 -#endif - }, - { -#include "asciitab.h" -#include "latin1tab.h" - }, - STANDARD_VTABLE(big2_) - }; - -#endif - -static const struct normal_encoding big2_encoding = { - { VTABLE, 2, 0, -#if XML_BYTE_ORDER == 21 - 1 -#else - 0 -#endif - }, - { -#define BT_COLON BT_NMSTRT -#include "asciitab.h" -#undef BT_COLON -#include "latin1tab.h" - }, - STANDARD_VTABLE(big2_) - }; - -#if XML_BYTE_ORDER != 12 - -#ifdef XML_NS - -static const struct normal_encoding internal_big2_encoding_ns = { - { VTABLE, 2, 0, 1 }, - { -#include "iasciitab.h" -#include "latin1tab.h" - }, - STANDARD_VTABLE(big2_) - }; - -#endif - -static const struct normal_encoding internal_big2_encoding = { - { VTABLE, 2, 0, 1 }, - { -#define BT_COLON BT_NMSTRT -#include "iasciitab.h" -#undef BT_COLON -#include "latin1tab.h" - }, - STANDARD_VTABLE(big2_) - }; - -#endif - -#undef PREFIX - -static -int streqci(const char *s1, const char *s2) -{ - for (;;) { - char c1 = *s1++; - char c2 = *s2++; - if ('a' <= c1 && c1 <= 'z') - c1 += 'A' - 'a'; - if ('a' <= c2 && c2 <= 'z') - c2 += 'A' - 'a'; - if (c1 != c2) - return 0; - if (!c1) - break; - } - return 1; -} - -static -void initUpdatePosition(const ENCODING *enc, const char *ptr, - const char *end, POSITION *pos) -{ - normal_updatePosition(&utf8_encoding.enc, ptr, end, pos); -} - -static -int toAscii(const ENCODING *enc, const char *ptr, const char *end) -{ - char buf[1]; - char *p = buf; - XmlUtf8Convert(enc, &ptr, end, &p, p + 1); - if (p == buf) - return -1; - else - return buf[0]; -} - -static -int isSpace(int c) -{ - switch (c) { - case 0x20: - case 0xD: - case 0xA: - case 0x9: - return 1; - } - return 0; -} - -/* Return 1 if there's just optional white space -or there's an S followed by name=val. */ -static -int parsePseudoAttribute(const ENCODING *enc, - const char *ptr, - const char *end, - const char **namePtr, - const char **valPtr, - const char **nextTokPtr) -{ - int c; - char open; - if (ptr == end) { - *namePtr = 0; - return 1; - } - if (!isSpace(toAscii(enc, ptr, end))) { - *nextTokPtr = ptr; - return 0; - } - do { - ptr += enc->minBytesPerChar; - } while (isSpace(toAscii(enc, ptr, end))); - if (ptr == end) { - *namePtr = 0; - return 1; - } - *namePtr = ptr; - for (;;) { - c = toAscii(enc, ptr, end); - if (c == -1) { - *nextTokPtr = ptr; - return 0; - } - if (c == '=') - break; - if (isSpace(c)) { - do { - ptr += enc->minBytesPerChar; - } while (isSpace(c = toAscii(enc, ptr, end))); - if (c != '=') { - *nextTokPtr = ptr; - return 0; - } - break; - } - ptr += enc->minBytesPerChar; - } - if (ptr == *namePtr) { - *nextTokPtr = ptr; - return 0; - } - ptr += enc->minBytesPerChar; - c = toAscii(enc, ptr, end); - while (isSpace(c)) { - ptr += enc->minBytesPerChar; - c = toAscii(enc, ptr, end); - } - if (c != '"' && c != '\'') { - *nextTokPtr = ptr; - return 0; - } - open = c; - ptr += enc->minBytesPerChar; - *valPtr = ptr; - for (;; ptr += enc->minBytesPerChar) { - c = toAscii(enc, ptr, end); - if (c == open) - break; - if (!('a' <= c && c <= 'z') - && !('A' <= c && c <= 'Z') - && !('0' <= c && c <= '9') - && c != '.' - && c != '-' - && c != '_') { - *nextTokPtr = ptr; - return 0; - } - } - *nextTokPtr = ptr + enc->minBytesPerChar; - return 1; -} - -static -int doParseXmlDecl(const ENCODING *(*encodingFinder)(const ENCODING *, - const char *, - const char *), - int isGeneralTextEntity, - const ENCODING *enc, - const char *ptr, - const char *end, - const char **badPtr, - const char **versionPtr, - const char **encodingName, - const ENCODING **encoding, - int *standalone) -{ - const char *val = 0; - const char *name = 0; - ptr += 5 * enc->minBytesPerChar; - end -= 2 * enc->minBytesPerChar; - if (!parsePseudoAttribute(enc, ptr, end, &name, &val, &ptr) || !name) { - *badPtr = ptr; - return 0; - } - if (!XmlNameMatchesAscii(enc, name, "version")) { - if (!isGeneralTextEntity) { - *badPtr = name; - return 0; - } - } - else { - if (versionPtr) - *versionPtr = val; - if (!parsePseudoAttribute(enc, ptr, end, &name, &val, &ptr)) { - *badPtr = ptr; - return 0; - } - if (!name) { - if (isGeneralTextEntity) { - /* a TextDecl must have an EncodingDecl */ - *badPtr = ptr; - return 0; - } - return 1; - } - } - if (XmlNameMatchesAscii(enc, name, "encoding")) { - int c = toAscii(enc, val, end); - if (!('a' <= c && c <= 'z') && !('A' <= c && c <= 'Z')) { - *badPtr = val; - return 0; - } - if (encodingName) - *encodingName = val; - if (encoding) - *encoding = encodingFinder(enc, val, ptr - enc->minBytesPerChar); - if (!parsePseudoAttribute(enc, ptr, end, &name, &val, &ptr)) { - *badPtr = ptr; - return 0; - } - if (!name) - return 1; - } - if (!XmlNameMatchesAscii(enc, name, "standalone") || isGeneralTextEntity) { - *badPtr = name; - return 0; - } - if (XmlNameMatchesAscii(enc, val, "yes")) { - if (standalone) - *standalone = 1; - } - else if (XmlNameMatchesAscii(enc, val, "no")) { - if (standalone) - *standalone = 0; - } - else { - *badPtr = val; - return 0; - } - while (isSpace(toAscii(enc, ptr, end))) - ptr += enc->minBytesPerChar; - if (ptr != end) { - *badPtr = ptr; - return 0; - } - return 1; -} - -static -int checkCharRefNumber(int result) -{ - switch (result >> 8) { -case 0xD8: case 0xD9: case 0xDA: case 0xDB: -case 0xDC: case 0xDD: case 0xDE: case 0xDF: - return -1; - case 0: - if (latin1_encoding.type[result] == BT_NONXML) - return -1; - break; - case 0xFF: - if (result == 0xFFFE || result == 0xFFFF) - return -1; - break; - } - return result; -} - -int XmlUtf8Encode(int c, char *buf) -{ - enum { - /* minN is minimum legal resulting value for N byte sequence */ - min2 = 0x80, - min3 = 0x800, - min4 = 0x10000 - }; - - if (c < 0) - return 0; - if (c < min2) { - buf[0] = (c | UTF8_cval1); - return 1; - } - if (c < min3) { - buf[0] = ((c >> 6) | UTF8_cval2); - buf[1] = ((c & 0x3f) | 0x80); - return 2; - } - if (c < min4) { - buf[0] = ((c >> 12) | UTF8_cval3); - buf[1] = (((c >> 6) & 0x3f) | 0x80); - buf[2] = ((c & 0x3f) | 0x80); - return 3; - } - if (c < 0x110000) { - buf[0] = ((c >> 18) | UTF8_cval4); - buf[1] = (((c >> 12) & 0x3f) | 0x80); - buf[2] = (((c >> 6) & 0x3f) | 0x80); - buf[3] = ((c & 0x3f) | 0x80); - return 4; - } - return 0; -} - -int XmlUtf16Encode(int charNum, unsigned short *buf) -{ - if (charNum < 0) - return 0; - if (charNum < 0x10000) { - buf[0] = charNum; - return 1; - } - if (charNum < 0x110000) { - charNum -= 0x10000; - buf[0] = (charNum >> 10) + 0xD800; - buf[1] = (charNum & 0x3FF) + 0xDC00; - return 2; - } - return 0; -} - -struct unknown_encoding { - struct normal_encoding normal; - int (*convert)(void *userData, const char *p); - void *userData; - unsigned short utf16[256]; - char utf8[256][4]; -}; - -int XmlSizeOfUnknownEncoding() -{ - return sizeof(struct unknown_encoding); -} - -static -int unknown_isName(const ENCODING *enc, const char *p) -{ - int c = ((const struct unknown_encoding *)enc) - ->convert(((const struct unknown_encoding *)enc)->userData, p); - if (c & ~0xFFFF) - return 0; - return UCS2_GET_NAMING(namePages, c >> 8, c & 0xFF); -} - -static -int unknown_isNmstrt(const ENCODING *enc, const char *p) -{ - int c = ((const struct unknown_encoding *)enc) - ->convert(((const struct unknown_encoding *)enc)->userData, p); - if (c & ~0xFFFF) - return 0; - return UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xFF); -} - -static -int unknown_isInvalid(const ENCODING *enc, const char *p) -{ - int c = ((const struct unknown_encoding *)enc) - ->convert(((const struct unknown_encoding *)enc)->userData, p); - return (c & ~0xFFFF) || checkCharRefNumber(c) < 0; -} - -static -void unknown_toUtf8(const ENCODING *enc, - const char **fromP, const char *fromLim, - char **toP, const char *toLim) -{ - char buf[XML_UTF8_ENCODE_MAX]; - for (;;) { - const char *utf8; - int n; - if (*fromP == fromLim) - break; - utf8 = ((const struct unknown_encoding *)enc)->utf8[(unsigned char)**fromP]; - n = *utf8++; - if (n == 0) { - int c = ((const struct unknown_encoding *)enc) - ->convert(((const struct unknown_encoding *)enc)->userData, *fromP); - n = XmlUtf8Encode(c, buf); - if (n > toLim - *toP) - break; - utf8 = buf; - *fromP += ((const struct normal_encoding *)enc)->type[(unsigned char)**fromP] - - (BT_LEAD2 - 2); - } - else { - if (n > toLim - *toP) - break; - (*fromP)++; - } - do { - *(*toP)++ = *utf8++; - } while (--n != 0); - } -} - -static -void unknown_toUtf16(const ENCODING *enc, - const char **fromP, const char *fromLim, - unsigned short **toP, const unsigned short *toLim) -{ - while (*fromP != fromLim && *toP != toLim) { - unsigned short c - = ((const struct unknown_encoding *)enc)->utf16[(unsigned char)**fromP]; - if (c == 0) { - c = (unsigned short)((const struct unknown_encoding *)enc) - ->convert(((const struct unknown_encoding *)enc)->userData, *fromP); - *fromP += ((const struct normal_encoding *)enc)->type[(unsigned char)**fromP] - - (BT_LEAD2 - 2); - } - else - (*fromP)++; - *(*toP)++ = c; - } -} - -ENCODING * -XmlInitUnknownEncoding(void *mem, - int *table, - int (*convert)(void *userData, const char *p), - void *userData) -{ - int i; - struct unknown_encoding *e = mem; - for (i = 0; i < sizeof(struct normal_encoding); i++) - ((char *)mem)[i] = ((char *)&latin1_encoding)[i]; - for (i = 0; i < 128; i++) - if (latin1_encoding.type[i] != BT_OTHER - && latin1_encoding.type[i] != BT_NONXML - && table[i] != i) - return 0; - for (i = 0; i < 256; i++) { - int c = table[i]; - if (c == -1) { - e->normal.type[i] = BT_MALFORM; - /* This shouldn't really get used. */ - e->utf16[i] = 0xFFFF; - e->utf8[i][0] = 1; - e->utf8[i][1] = 0; - } - else if (c < 0) { - if (c < -4) - return 0; - e->normal.type[i] = BT_LEAD2 - (c + 2); - e->utf8[i][0] = 0; - e->utf16[i] = 0; - } - else if (c < 0x80) { - if (latin1_encoding.type[c] != BT_OTHER - && latin1_encoding.type[c] != BT_NONXML - && c != i) - return 0; - e->normal.type[i] = latin1_encoding.type[c]; - e->utf8[i][0] = 1; - e->utf8[i][1] = (char)c; - e->utf16[i] = c == 0 ? 0xFFFF : c; - } - else if (checkCharRefNumber(c) < 0) { - e->normal.type[i] = BT_NONXML; - /* This shouldn't really get used. */ - e->utf16[i] = 0xFFFF; - e->utf8[i][0] = 1; - e->utf8[i][1] = 0; - } - else { - if (c > 0xFFFF) - return 0; - if (UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xff)) - e->normal.type[i] = BT_NMSTRT; - else if (UCS2_GET_NAMING(namePages, c >> 8, c & 0xff)) - e->normal.type[i] = BT_NAME; - else - e->normal.type[i] = BT_OTHER; - e->utf8[i][0] = (char)XmlUtf8Encode(c, e->utf8[i] + 1); - e->utf16[i] = c; - } - } - e->userData = userData; - e->convert = convert; - if (convert) { - e->normal.isName2 = unknown_isName; - e->normal.isName3 = unknown_isName; - e->normal.isName4 = unknown_isName; - e->normal.isNmstrt2 = unknown_isNmstrt; - e->normal.isNmstrt3 = unknown_isNmstrt; - e->normal.isNmstrt4 = unknown_isNmstrt; - e->normal.isInvalid2 = unknown_isInvalid; - e->normal.isInvalid3 = unknown_isInvalid; - e->normal.isInvalid4 = unknown_isInvalid; - } - e->normal.enc.utf8Convert = unknown_toUtf8; - e->normal.enc.utf16Convert = unknown_toUtf16; - return &(e->normal.enc); -} - -/* If this enumeration is changed, getEncodingIndex and encodings -must also be changed. */ -enum { - UNKNOWN_ENC = -1, - ISO_8859_1_ENC = 0, - US_ASCII_ENC, - UTF_8_ENC, - UTF_16_ENC, - UTF_16BE_ENC, - UTF_16LE_ENC, - /* must match encodingNames up to here */ - NO_ENC -}; - -static -int getEncodingIndex(const char *name) -{ - static const char *encodingNames[] = { - "ISO-8859-1", - "US-ASCII", - "UTF-8", - "UTF-16", - "UTF-16BE" - "UTF-16LE", - }; - int i; - if (name == 0) - return NO_ENC; - for (i = 0; i < sizeof(encodingNames)/sizeof(encodingNames[0]); i++) - if (streqci(name, encodingNames[i])) - return i; - return UNKNOWN_ENC; -} - -/* For binary compatibility, we store the index of the encoding specified -at initialization in the isUtf16 member. */ - -#define INIT_ENC_INDEX(enc) ((enc)->initEnc.isUtf16) - -/* This is what detects the encoding. -encodingTable maps from encoding indices to encodings; -INIT_ENC_INDEX(enc) is the index of the external (protocol) specified encoding; -state is XML_CONTENT_STATE if we're parsing an external text entity, -and XML_PROLOG_STATE otherwise. -*/ - - -static -int initScan(const ENCODING **encodingTable, - const INIT_ENCODING *enc, - int state, - const char *ptr, - const char *end, - const char **nextTokPtr) -{ - const ENCODING **encPtr; - - if (ptr == end) - return XML_TOK_NONE; - encPtr = enc->encPtr; - if (ptr + 1 == end) { - /* only a single byte available for auto-detection */ - /* a well-formed document entity must have more than one byte */ - if (state != XML_CONTENT_STATE) - return XML_TOK_PARTIAL; - /* so we're parsing an external text entity... */ - /* if UTF-16 was externally specified, then we need at least 2 bytes */ - switch (INIT_ENC_INDEX(enc)) { - case UTF_16_ENC: - case UTF_16LE_ENC: - case UTF_16BE_ENC: - return XML_TOK_PARTIAL; - } - switch ((unsigned char)*ptr) { - case 0xFE: - case 0xFF: - case 0xEF: /* possibly first byte of UTF-8 BOM */ - if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC - && state == XML_CONTENT_STATE) - break; - /* fall through */ - case 0x00: - case 0x3C: - return XML_TOK_PARTIAL; - } - } - else { - switch (((unsigned char)ptr[0] << 8) | (unsigned char)ptr[1]) { - case 0xFEFF: - if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC - && state == XML_CONTENT_STATE) - break; - *nextTokPtr = ptr + 2; - *encPtr = encodingTable[UTF_16BE_ENC]; - return XML_TOK_BOM; - /* 00 3C is handled in the default case */ - case 0x3C00: - if ((INIT_ENC_INDEX(enc) == UTF_16BE_ENC - || INIT_ENC_INDEX(enc) == UTF_16_ENC) - && state == XML_CONTENT_STATE) - break; - *encPtr = encodingTable[UTF_16LE_ENC]; - return XmlTok(*encPtr, state, ptr, end, nextTokPtr); - case 0xFFFE: - if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC - && state == XML_CONTENT_STATE) - break; - *nextTokPtr = ptr + 2; - *encPtr = encodingTable[UTF_16LE_ENC]; - return XML_TOK_BOM; - case 0xEFBB: - /* Maybe a UTF-8 BOM (EF BB BF) */ - /* If there's an explicitly specified (external) encoding - of ISO-8859-1 or some flavour of UTF-16 - and this is an external text entity, - don't look for the BOM, - because it might be a legal data. */ - if (state == XML_CONTENT_STATE) { - int e = INIT_ENC_INDEX(enc); - if (e == ISO_8859_1_ENC || e == UTF_16BE_ENC || e == UTF_16LE_ENC || e == UTF_16_ENC) - break; - } - if (ptr + 2 == end) - return XML_TOK_PARTIAL; - if ((unsigned char)ptr[2] == 0xBF) { - *encPtr = encodingTable[UTF_8_ENC]; - return XML_TOK_BOM; - } - break; - default: - if (ptr[0] == '\0') { - /* 0 isn't a legal data character. Furthermore a document entity can only - start with ASCII characters. So the only way this can fail to be big-endian - UTF-16 if it it's an external parsed general entity that's labelled as - UTF-16LE. */ - if (state == XML_CONTENT_STATE && INIT_ENC_INDEX(enc) == UTF_16LE_ENC) - break; - *encPtr = encodingTable[UTF_16BE_ENC]; - return XmlTok(*encPtr, state, ptr, end, nextTokPtr); - } - else if (ptr[1] == '\0') { - /* We could recover here in the case: - - parsing an external entity - - second byte is 0 - - no externally specified encoding - - no encoding declaration - by assuming UTF-16LE. But we don't, because this would mean when - presented just with a single byte, we couldn't reliably determine - whether we needed further bytes. */ - if (state == XML_CONTENT_STATE) - break; - *encPtr = encodingTable[UTF_16LE_ENC]; - return XmlTok(*encPtr, state, ptr, end, nextTokPtr); - } - break; - } - } - *encPtr = encodingTable[(int)INIT_ENC_INDEX(enc)]; - return XmlTok(*encPtr, state, ptr, end, nextTokPtr); -} - - -#define NS(x) x -#define ns(x) x -#include "xmltok_ns.c" -#undef NS -#undef ns - -#ifdef XML_NS - -#define NS(x) x ## NS -#define ns(x) x ## _ns - -#include "xmltok_ns.c" - -#undef NS -#undef ns - -ENCODING * -XmlInitUnknownEncodingNS(void *mem, - int *table, - int (*convert)(void *userData, const char *p), - void *userData) -{ - ENCODING *enc = XmlInitUnknownEncoding(mem, table, convert, userData); - if (enc) - ((struct normal_encoding *)enc)->type[':'] = BT_COLON; - return enc; -} - -#endif /* XML_NS */ diff --git a/protocols/jabber/xmltok.h b/protocols/jabber/xmltok.h deleted file mode 100644 index 06544d15..00000000 --- a/protocols/jabber/xmltok.h +++ /dev/null @@ -1,307 +0,0 @@ -/* -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in -compliance with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" -basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -License for the specific language governing rights and limitations -under the License. - -The Original Code is expat. - -The Initial Developer of the Original Code is James Clark. -Portions created by James Clark are Copyright (C) 1998, 1999 -James Clark. All Rights Reserved. - -Contributor(s): - -Alternatively, the contents of this file may be used under the terms -of the GNU General Public License (the "GPL"), in which case the -provisions of the GPL are applicable instead of those above. If you -wish to allow use of your version of this file only under the terms of -the GPL and not to allow others to use your version of this file under -the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the -GPL. If you do not delete the provisions above, a recipient may use -your version of this file under either the MPL or the GPL. -*/ - -#ifndef XmlTok_INCLUDED -#define XmlTok_INCLUDED 1 - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef XMLTOKAPI -#define XMLTOKAPI /* as nothing */ -#endif - -/* The following token may be returned by XmlContentTok */ -#define XML_TOK_TRAILING_RSQB -5 /* ] or ]] at the end of the scan; might be start of - illegal ]]> sequence */ -/* The following tokens may be returned by both XmlPrologTok and XmlContentTok */ -#define XML_TOK_NONE -4 /* The string to be scanned is empty */ -#define XML_TOK_TRAILING_CR -3 /* A CR at the end of the scan; - might be part of CRLF sequence */ -#define XML_TOK_PARTIAL_CHAR -2 /* only part of a multibyte sequence */ -#define XML_TOK_PARTIAL -1 /* only part of a token */ -#define XML_TOK_INVALID 0 - -/* The following tokens are returned by XmlContentTok; some are also - returned by XmlAttributeValueTok, XmlEntityTok, XmlCdataSectionTok */ - -#define XML_TOK_START_TAG_WITH_ATTS 1 -#define XML_TOK_START_TAG_NO_ATTS 2 -#define XML_TOK_EMPTY_ELEMENT_WITH_ATTS 3 /* empty element tag <e/> */ -#define XML_TOK_EMPTY_ELEMENT_NO_ATTS 4 -#define XML_TOK_END_TAG 5 -#define XML_TOK_DATA_CHARS 6 -#define XML_TOK_DATA_NEWLINE 7 -#define XML_TOK_CDATA_SECT_OPEN 8 -#define XML_TOK_ENTITY_REF 9 -#define XML_TOK_CHAR_REF 10 /* numeric character reference */ - -/* The following tokens may be returned by both XmlPrologTok and XmlContentTok */ -#define XML_TOK_PI 11 /* processing instruction */ -#define XML_TOK_XML_DECL 12 /* XML decl or text decl */ -#define XML_TOK_COMMENT 13 -#define XML_TOK_BOM 14 /* Byte order mark */ - -/* The following tokens are returned only by XmlPrologTok */ -#define XML_TOK_PROLOG_S 15 -#define XML_TOK_DECL_OPEN 16 /* <!foo */ -#define XML_TOK_DECL_CLOSE 17 /* > */ -#define XML_TOK_NAME 18 -#define XML_TOK_NMTOKEN 19 -#define XML_TOK_POUND_NAME 20 /* #name */ -#define XML_TOK_OR 21 /* | */ -#define XML_TOK_PERCENT 22 -#define XML_TOK_OPEN_PAREN 23 -#define XML_TOK_CLOSE_PAREN 24 -#define XML_TOK_OPEN_BRACKET 25 -#define XML_TOK_CLOSE_BRACKET 26 -#define XML_TOK_LITERAL 27 -#define XML_TOK_PARAM_ENTITY_REF 28 -#define XML_TOK_INSTANCE_START 29 - -/* The following occur only in element type declarations */ -#define XML_TOK_NAME_QUESTION 30 /* name? */ -#define XML_TOK_NAME_ASTERISK 31 /* name* */ -#define XML_TOK_NAME_PLUS 32 /* name+ */ -#define XML_TOK_COND_SECT_OPEN 33 /* <![ */ -#define XML_TOK_COND_SECT_CLOSE 34 /* ]]> */ -#define XML_TOK_CLOSE_PAREN_QUESTION 35 /* )? */ -#define XML_TOK_CLOSE_PAREN_ASTERISK 36 /* )* */ -#define XML_TOK_CLOSE_PAREN_PLUS 37 /* )+ */ -#define XML_TOK_COMMA 38 - -/* The following token is returned only by XmlAttributeValueTok */ -#define XML_TOK_ATTRIBUTE_VALUE_S 39 - -/* The following token is returned only by XmlCdataSectionTok */ -#define XML_TOK_CDATA_SECT_CLOSE 40 - -/* With namespace processing this is returned by XmlPrologTok - for a name with a colon. */ -#define XML_TOK_PREFIXED_NAME 41 - -#define XML_N_STATES 3 -#define XML_PROLOG_STATE 0 -#define XML_CONTENT_STATE 1 -#define XML_CDATA_SECTION_STATE 2 - -#define XML_N_LITERAL_TYPES 2 -#define XML_ATTRIBUTE_VALUE_LITERAL 0 -#define XML_ENTITY_VALUE_LITERAL 1 - -/* The size of the buffer passed to XmlUtf8Encode must be at least this. */ -#define XML_UTF8_ENCODE_MAX 4 -/* The size of the buffer passed to XmlUtf16Encode must be at least this. */ -#define XML_UTF16_ENCODE_MAX 2 - -typedef struct position { - /* first line and first column are 0 not 1 */ - unsigned long lineNumber; - unsigned long columnNumber; -} POSITION; - -typedef struct { - const char *name; - const char *valuePtr; - const char *valueEnd; - char normalized; -} ATTRIBUTE; - -struct encoding; -typedef struct encoding ENCODING; - -struct encoding { - int (*scanners[XML_N_STATES])(const ENCODING *, - const char *, - const char *, - const char **); - int (*literalScanners[XML_N_LITERAL_TYPES])(const ENCODING *, - const char *, - const char *, - const char **); - int (*sameName)(const ENCODING *, - const char *, const char *); - int (*nameMatchesAscii)(const ENCODING *, - const char *, const char *); - int (*nameLength)(const ENCODING *, const char *); - const char *(*skipS)(const ENCODING *, const char *); - int (*getAtts)(const ENCODING *enc, const char *ptr, - int attsMax, ATTRIBUTE *atts); - int (*charRefNumber)(const ENCODING *enc, const char *ptr); - int (*predefinedEntityName)(const ENCODING *, const char *, const char *); - void (*updatePosition)(const ENCODING *, - const char *ptr, - const char *end, - POSITION *); - int (*isPublicId)(const ENCODING *enc, const char *ptr, const char *end, - const char **badPtr); - void (*utf8Convert)(const ENCODING *enc, - const char **fromP, - const char *fromLim, - char **toP, - const char *toLim); - void (*utf16Convert)(const ENCODING *enc, - const char **fromP, - const char *fromLim, - unsigned short **toP, - const unsigned short *toLim); - int minBytesPerChar; - char isUtf8; - char isUtf16; -}; - -/* -Scan the string starting at ptr until the end of the next complete token, -but do not scan past eptr. Return an integer giving the type of token. - -Return XML_TOK_NONE when ptr == eptr; nextTokPtr will not be set. - -Return XML_TOK_PARTIAL when the string does not contain a complete token; -nextTokPtr will not be set. - -Return XML_TOK_INVALID when the string does not start a valid token; nextTokPtr -will be set to point to the character which made the token invalid. - -Otherwise the string starts with a valid token; nextTokPtr will be set to point -to the character following the end of that token. - -Each data character counts as a single token, but adjacent data characters -may be returned together. Similarly for characters in the prolog outside -literals, comments and processing instructions. -*/ - - -#define XmlTok(enc, state, ptr, end, nextTokPtr) \ - (((enc)->scanners[state])(enc, ptr, end, nextTokPtr)) - -#define XmlPrologTok(enc, ptr, end, nextTokPtr) \ - XmlTok(enc, XML_PROLOG_STATE, ptr, end, nextTokPtr) - -#define XmlContentTok(enc, ptr, end, nextTokPtr) \ - XmlTok(enc, XML_CONTENT_STATE, ptr, end, nextTokPtr) - -#define XmlCdataSectionTok(enc, ptr, end, nextTokPtr) \ - XmlTok(enc, XML_CDATA_SECTION_STATE, ptr, end, nextTokPtr) - -/* This is used for performing a 2nd-level tokenization on -the content of a literal that has already been returned by XmlTok. */ - -#define XmlLiteralTok(enc, literalType, ptr, end, nextTokPtr) \ - (((enc)->literalScanners[literalType])(enc, ptr, end, nextTokPtr)) - -#define XmlAttributeValueTok(enc, ptr, end, nextTokPtr) \ - XmlLiteralTok(enc, XML_ATTRIBUTE_VALUE_LITERAL, ptr, end, nextTokPtr) - -#define XmlEntityValueTok(enc, ptr, end, nextTokPtr) \ - XmlLiteralTok(enc, XML_ENTITY_VALUE_LITERAL, ptr, end, nextTokPtr) - -#define XmlSameName(enc, ptr1, ptr2) (((enc)->sameName)(enc, ptr1, ptr2)) - -#define XmlNameMatchesAscii(enc, ptr1, ptr2) \ - (((enc)->nameMatchesAscii)(enc, ptr1, ptr2)) - -#define XmlNameLength(enc, ptr) \ - (((enc)->nameLength)(enc, ptr)) - -#define XmlSkipS(enc, ptr) \ - (((enc)->skipS)(enc, ptr)) - -#define XmlGetAttributes(enc, ptr, attsMax, atts) \ - (((enc)->getAtts)(enc, ptr, attsMax, atts)) - -#define XmlCharRefNumber(enc, ptr) \ - (((enc)->charRefNumber)(enc, ptr)) - -#define XmlPredefinedEntityName(enc, ptr, end) \ - (((enc)->predefinedEntityName)(enc, ptr, end)) - -#define XmlUpdatePosition(enc, ptr, end, pos) \ - (((enc)->updatePosition)(enc, ptr, end, pos)) - -#define XmlIsPublicId(enc, ptr, end, badPtr) \ - (((enc)->isPublicId)(enc, ptr, end, badPtr)) - -#define XmlUtf8Convert(enc, fromP, fromLim, toP, toLim) \ - (((enc)->utf8Convert)(enc, fromP, fromLim, toP, toLim)) - -#define XmlUtf16Convert(enc, fromP, fromLim, toP, toLim) \ - (((enc)->utf16Convert)(enc, fromP, fromLim, toP, toLim)) - -typedef struct { - ENCODING initEnc; - const ENCODING **encPtr; -} INIT_ENCODING; - -int XMLTOKAPI XmlParseXmlDecl(int isGeneralTextEntity, - const ENCODING *enc, - const char *ptr, - const char *end, - const char **badPtr, - const char **versionPtr, - const char **encodingNamePtr, - const ENCODING **namedEncodingPtr, - int *standalonePtr); - -int XMLTOKAPI XmlInitEncoding(INIT_ENCODING *, const ENCODING **, const char *name); -const ENCODING XMLTOKAPI *XmlGetUtf8InternalEncoding(); -const ENCODING XMLTOKAPI *XmlGetUtf16InternalEncoding(); -int XMLTOKAPI XmlUtf8Encode(int charNumber, char *buf); -int XMLTOKAPI XmlUtf16Encode(int charNumber, unsigned short *buf); - -int XMLTOKAPI XmlSizeOfUnknownEncoding(); -ENCODING XMLTOKAPI * -XmlInitUnknownEncoding(void *mem, - int *table, - int (*conv)(void *userData, const char *p), - void *userData); - -int XMLTOKAPI XmlParseXmlDeclNS(int isGeneralTextEntity, - const ENCODING *enc, - const char *ptr, - const char *end, - const char **badPtr, - const char **versionPtr, - const char **encodingNamePtr, - const ENCODING **namedEncodingPtr, - int *standalonePtr); -int XMLTOKAPI XmlInitEncodingNS(INIT_ENCODING *, const ENCODING **, const char *name); -const ENCODING XMLTOKAPI *XmlGetUtf8InternalEncodingNS(); -const ENCODING XMLTOKAPI *XmlGetUtf16InternalEncodingNS(); -ENCODING XMLTOKAPI * -XmlInitUnknownEncodingNS(void *mem, - int *table, - int (*conv)(void *userData, const char *p), - void *userData); -#ifdef __cplusplus -} -#endif - -#endif /* not XmlTok_INCLUDED */ diff --git a/protocols/jabber/xmltok_impl.c b/protocols/jabber/xmltok_impl.c deleted file mode 100644 index de11c2a8..00000000 --- a/protocols/jabber/xmltok_impl.c +++ /dev/null @@ -1,1737 +0,0 @@ -/* -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in -compliance with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" -basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -License for the specific language governing rights and limitations -under the License. - -The Original Code is expat. - -The Initial Developer of the Original Code is James Clark. -Portions created by James Clark are Copyright (C) 1998, 1999 -James Clark. All Rights Reserved. - -Contributor(s): - -*/ - -#ifndef IS_INVALID_CHAR -#define IS_INVALID_CHAR(enc, ptr, n) (0) -#endif - -#define INVALID_LEAD_CASE(n, ptr, nextTokPtr) \ - case BT_LEAD ## n: \ - if (end - ptr < n) \ - return XML_TOK_PARTIAL_CHAR; \ - if (IS_INVALID_CHAR(enc, ptr, n)) { \ - *(nextTokPtr) = (ptr); \ - return XML_TOK_INVALID; \ - } \ - ptr += n; \ - break; - -#define INVALID_CASES(ptr, nextTokPtr) \ - INVALID_LEAD_CASE(2, ptr, nextTokPtr) \ - INVALID_LEAD_CASE(3, ptr, nextTokPtr) \ - INVALID_LEAD_CASE(4, ptr, nextTokPtr) \ - case BT_NONXML: \ - case BT_MALFORM: \ - case BT_TRAIL: \ - *(nextTokPtr) = (ptr); \ - return XML_TOK_INVALID; - -#define CHECK_NAME_CASE(n, enc, ptr, end, nextTokPtr) \ - case BT_LEAD ## n: \ - if (end - ptr < n) \ - return XML_TOK_PARTIAL_CHAR; \ - if (!IS_NAME_CHAR(enc, ptr, n)) { \ - *nextTokPtr = ptr; \ - return XML_TOK_INVALID; \ - } \ - ptr += n; \ - break; - -#define CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) \ - case BT_NONASCII: \ - if (!IS_NAME_CHAR_MINBPC(enc, ptr)) { \ - *nextTokPtr = ptr; \ - return XML_TOK_INVALID; \ - } \ - case BT_NMSTRT: \ - case BT_HEX: \ - case BT_DIGIT: \ - case BT_NAME: \ - case BT_MINUS: \ - ptr += MINBPC(enc); \ - break; \ - CHECK_NAME_CASE(2, enc, ptr, end, nextTokPtr) \ - CHECK_NAME_CASE(3, enc, ptr, end, nextTokPtr) \ - CHECK_NAME_CASE(4, enc, ptr, end, nextTokPtr) - -#define CHECK_NMSTRT_CASE(n, enc, ptr, end, nextTokPtr) \ - case BT_LEAD ## n: \ - if (end - ptr < n) \ - return XML_TOK_PARTIAL_CHAR; \ - if (!IS_NMSTRT_CHAR(enc, ptr, n)) { \ - *nextTokPtr = ptr; \ - return XML_TOK_INVALID; \ - } \ - ptr += n; \ - break; - -#define CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) \ - case BT_NONASCII: \ - if (!IS_NMSTRT_CHAR_MINBPC(enc, ptr)) { \ - *nextTokPtr = ptr; \ - return XML_TOK_INVALID; \ - } \ - case BT_NMSTRT: \ - case BT_HEX: \ - ptr += MINBPC(enc); \ - break; \ - CHECK_NMSTRT_CASE(2, enc, ptr, end, nextTokPtr) \ - CHECK_NMSTRT_CASE(3, enc, ptr, end, nextTokPtr) \ - CHECK_NMSTRT_CASE(4, enc, ptr, end, nextTokPtr) - -#ifndef PREFIX -#define PREFIX(ident) ident -#endif - -/* ptr points to character following "<!-" */ - -static -int PREFIX(scanComment)(const ENCODING *enc, const char *ptr, const char *end, - const char **nextTokPtr) -{ - if (ptr != end) { - if (!CHAR_MATCHES(enc, ptr, '-')) { - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - ptr += MINBPC(enc); - while (ptr != end) { - switch (BYTE_TYPE(enc, ptr)) { - INVALID_CASES(ptr, nextTokPtr) - case BT_MINUS: - if ((ptr += MINBPC(enc)) == end) - return XML_TOK_PARTIAL; - if (CHAR_MATCHES(enc, ptr, '-')) { - if ((ptr += MINBPC(enc)) == end) - return XML_TOK_PARTIAL; - if (!CHAR_MATCHES(enc, ptr, '>')) { - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_COMMENT; - } - break; - default: - ptr += MINBPC(enc); - break; - } - } - } - return XML_TOK_PARTIAL; -} - -/* ptr points to character following "<!" */ - -static -int PREFIX(scanDecl)(const ENCODING *enc, const char *ptr, const char *end, - const char **nextTokPtr) -{ - if (ptr == end) - return XML_TOK_PARTIAL; - switch (BYTE_TYPE(enc, ptr)) { - case BT_MINUS: - return PREFIX(scanComment)(enc, ptr + MINBPC(enc), end, nextTokPtr); - case BT_LSQB: - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_COND_SECT_OPEN; - case BT_NMSTRT: - case BT_HEX: - ptr += MINBPC(enc); - break; - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - while (ptr != end) { - switch (BYTE_TYPE(enc, ptr)) { - case BT_PERCNT: - if (ptr + MINBPC(enc) == end) - return XML_TOK_PARTIAL; - /* don't allow <!ENTITY% foo "whatever"> */ - switch (BYTE_TYPE(enc, ptr + MINBPC(enc))) { -case BT_S: case BT_CR: case BT_LF: case BT_PERCNT: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - /* fall through */ -case BT_S: case BT_CR: case BT_LF: - *nextTokPtr = ptr; - return XML_TOK_DECL_OPEN; - case BT_NMSTRT: - case BT_HEX: - ptr += MINBPC(enc); - break; - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - } - return XML_TOK_PARTIAL; -} - -static -int PREFIX(checkPiTarget)(const ENCODING *enc, const char *ptr, const char *end, int *tokPtr) -{ - int upper = 0; - *tokPtr = XML_TOK_PI; - if (end - ptr != MINBPC(enc)*3) - return 1; - switch (BYTE_TO_ASCII(enc, ptr)) { - case 'x': - break; - case 'X': - upper = 1; - break; - default: - return 1; - } - ptr += MINBPC(enc); - switch (BYTE_TO_ASCII(enc, ptr)) { - case 'm': - break; - case 'M': - upper = 1; - break; - default: - return 1; - } - ptr += MINBPC(enc); - switch (BYTE_TO_ASCII(enc, ptr)) { - case 'l': - break; - case 'L': - upper = 1; - break; - default: - return 1; - } - if (upper) - return 0; - *tokPtr = XML_TOK_XML_DECL; - return 1; -} - -/* ptr points to character following "<?" */ - -static -int PREFIX(scanPi)(const ENCODING *enc, const char *ptr, const char *end, - const char **nextTokPtr) -{ - int tok; - const char *target = ptr; - if (ptr == end) - return XML_TOK_PARTIAL; - switch (BYTE_TYPE(enc, ptr)) { - CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - while (ptr != end) { - switch (BYTE_TYPE(enc, ptr)) { - CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) -case BT_S: case BT_CR: case BT_LF: - if (!PREFIX(checkPiTarget)(enc, target, ptr, &tok)) { - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - ptr += MINBPC(enc); - while (ptr != end) { - switch (BYTE_TYPE(enc, ptr)) { - INVALID_CASES(ptr, nextTokPtr) - case BT_QUEST: - ptr += MINBPC(enc); - if (ptr == end) - return XML_TOK_PARTIAL; - if (CHAR_MATCHES(enc, ptr, '>')) { - *nextTokPtr = ptr + MINBPC(enc); - return tok; - } - break; - default: - ptr += MINBPC(enc); - break; - } - } - return XML_TOK_PARTIAL; - case BT_QUEST: - if (!PREFIX(checkPiTarget)(enc, target, ptr, &tok)) { - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - ptr += MINBPC(enc); - if (ptr == end) - return XML_TOK_PARTIAL; - if (CHAR_MATCHES(enc, ptr, '>')) { - *nextTokPtr = ptr + MINBPC(enc); - return tok; - } - /* fall through */ - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - } - return XML_TOK_PARTIAL; -} - - -static -int PREFIX(scanCdataSection)(const ENCODING *enc, const char *ptr, const char *end, - const char **nextTokPtr) -{ - int i; - /* CDATA[ */ - if (end - ptr < 6 * MINBPC(enc)) - return XML_TOK_PARTIAL; - for (i = 0; i < 6; i++, ptr += MINBPC(enc)) { - if (!CHAR_MATCHES(enc, ptr, "CDATA["[i])) { - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - } - *nextTokPtr = ptr; - return XML_TOK_CDATA_SECT_OPEN; -} - -static -int PREFIX(cdataSectionTok)(const ENCODING *enc, const char *ptr, const char *end, - const char **nextTokPtr) -{ - if (ptr == end) - return XML_TOK_NONE; - if (MINBPC(enc) > 1) { - size_t n = end - ptr; - if (n & (MINBPC(enc) - 1)) { - n &= ~(MINBPC(enc) - 1); - if (n == 0) - return XML_TOK_PARTIAL; - end = ptr + n; - } - } - switch (BYTE_TYPE(enc, ptr)) { - case BT_RSQB: - ptr += MINBPC(enc); - if (ptr == end) - return XML_TOK_PARTIAL; - if (!CHAR_MATCHES(enc, ptr, ']')) - break; - ptr += MINBPC(enc); - if (ptr == end) - return XML_TOK_PARTIAL; - if (!CHAR_MATCHES(enc, ptr, '>')) { - ptr -= MINBPC(enc); - break; - } - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_CDATA_SECT_CLOSE; - case BT_CR: - ptr += MINBPC(enc); - if (ptr == end) - return XML_TOK_PARTIAL; - if (BYTE_TYPE(enc, ptr) == BT_LF) - ptr += MINBPC(enc); - *nextTokPtr = ptr; - return XML_TOK_DATA_NEWLINE; - case BT_LF: - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_DATA_NEWLINE; - INVALID_CASES(ptr, nextTokPtr) - default: - ptr += MINBPC(enc); - break; - } - while (ptr != end) { - switch (BYTE_TYPE(enc, ptr)) { -#define LEAD_CASE(n) \ - case BT_LEAD ## n: \ - if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \ - *nextTokPtr = ptr; \ - return XML_TOK_DATA_CHARS; \ - } \ - ptr += n; \ - break; - LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) -#undef LEAD_CASE - case BT_NONXML: - case BT_MALFORM: - case BT_TRAIL: - case BT_CR: - case BT_LF: - case BT_RSQB: - *nextTokPtr = ptr; - return XML_TOK_DATA_CHARS; - default: - ptr += MINBPC(enc); - break; - } - } - *nextTokPtr = ptr; - return XML_TOK_DATA_CHARS; -} - -/* ptr points to character following "</" */ - -static -int PREFIX(scanEndTag)(const ENCODING *enc, const char *ptr, const char *end, - const char **nextTokPtr) -{ - if (ptr == end) - return XML_TOK_PARTIAL; - switch (BYTE_TYPE(enc, ptr)) { - CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - while (ptr != end) { - switch (BYTE_TYPE(enc, ptr)) { - CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) -case BT_S: case BT_CR: case BT_LF: - for (ptr += MINBPC(enc); ptr != end; ptr += MINBPC(enc)) { - switch (BYTE_TYPE(enc, ptr)) { - case BT_S: case BT_CR: case BT_LF: - break; - case BT_GT: - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_END_TAG; - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - } - return XML_TOK_PARTIAL; -#ifdef XML_NS - case BT_COLON: - /* no need to check qname syntax here, since end-tag must match exactly */ - ptr += MINBPC(enc); - break; -#endif - case BT_GT: - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_END_TAG; - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - } - return XML_TOK_PARTIAL; -} - -/* ptr points to character following "&#X" */ - -static -int PREFIX(scanHexCharRef)(const ENCODING *enc, const char *ptr, const char *end, - const char **nextTokPtr) -{ - if (ptr != end) { - switch (BYTE_TYPE(enc, ptr)) { - case BT_DIGIT: - case BT_HEX: - break; - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - for (ptr += MINBPC(enc); ptr != end; ptr += MINBPC(enc)) { - switch (BYTE_TYPE(enc, ptr)) { - case BT_DIGIT: - case BT_HEX: - break; - case BT_SEMI: - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_CHAR_REF; - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - } - } - return XML_TOK_PARTIAL; -} - -/* ptr points to character following "&#" */ - -static -int PREFIX(scanCharRef)(const ENCODING *enc, const char *ptr, const char *end, - const char **nextTokPtr) -{ - if (ptr != end) { - if (CHAR_MATCHES(enc, ptr, 'x')) - return PREFIX(scanHexCharRef)(enc, ptr + MINBPC(enc), end, nextTokPtr); - switch (BYTE_TYPE(enc, ptr)) { - case BT_DIGIT: - break; - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - for (ptr += MINBPC(enc); ptr != end; ptr += MINBPC(enc)) { - switch (BYTE_TYPE(enc, ptr)) { - case BT_DIGIT: - break; - case BT_SEMI: - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_CHAR_REF; - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - } - } - return XML_TOK_PARTIAL; -} - -/* ptr points to character following "&" */ - -static -int PREFIX(scanRef)(const ENCODING *enc, const char *ptr, const char *end, - const char **nextTokPtr) -{ - if (ptr == end) - return XML_TOK_PARTIAL; - switch (BYTE_TYPE(enc, ptr)) { - CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) - case BT_NUM: - return PREFIX(scanCharRef)(enc, ptr + MINBPC(enc), end, nextTokPtr); - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - while (ptr != end) { - switch (BYTE_TYPE(enc, ptr)) { - CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) - case BT_SEMI: - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_ENTITY_REF; - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - } - return XML_TOK_PARTIAL; -} - -/* ptr points to character following first character of attribute name */ - -static -int PREFIX(scanAtts)(const ENCODING *enc, const char *ptr, const char *end, - const char **nextTokPtr) -{ -#ifdef XML_NS - int hadColon = 0; -#endif - while (ptr != end) { - switch (BYTE_TYPE(enc, ptr)) { - CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) -#ifdef XML_NS - case BT_COLON: - if (hadColon) { - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - hadColon = 1; - ptr += MINBPC(enc); - if (ptr == end) - return XML_TOK_PARTIAL; - switch (BYTE_TYPE(enc, ptr)) { - CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - break; -#endif -case BT_S: case BT_CR: case BT_LF: - for (;;) { - int t; - - ptr += MINBPC(enc); - if (ptr == end) - return XML_TOK_PARTIAL; - t = BYTE_TYPE(enc, ptr); - if (t == BT_EQUALS) - break; - switch (t) { - case BT_S: - case BT_LF: - case BT_CR: - break; - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - } - /* fall through */ - case BT_EQUALS: - { - int open; -#ifdef XML_NS - hadColon = 0; -#endif - for (;;) { - - ptr += MINBPC(enc); - if (ptr == end) - return XML_TOK_PARTIAL; - open = BYTE_TYPE(enc, ptr); - if (open == BT_QUOT || open == BT_APOS) - break; - switch (open) { - case BT_S: - case BT_LF: - case BT_CR: - break; - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - } - ptr += MINBPC(enc); - /* in attribute value */ - for (;;) { - int t; - if (ptr == end) - return XML_TOK_PARTIAL; - t = BYTE_TYPE(enc, ptr); - if (t == open) - break; - switch (t) { - INVALID_CASES(ptr, nextTokPtr) - case BT_AMP: - { - int tok = PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, &ptr); - if (tok <= 0) { - if (tok == XML_TOK_INVALID) - *nextTokPtr = ptr; - return tok; - } - break; - } - case BT_LT: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - default: - ptr += MINBPC(enc); - break; - } - } - ptr += MINBPC(enc); - if (ptr == end) - return XML_TOK_PARTIAL; - switch (BYTE_TYPE(enc, ptr)) { - case BT_S: - case BT_CR: - case BT_LF: - break; - case BT_SOL: - goto sol; - case BT_GT: - goto gt; - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - /* ptr points to closing quote */ - for (;;) { - ptr += MINBPC(enc); - if (ptr == end) - return XML_TOK_PARTIAL; - switch (BYTE_TYPE(enc, ptr)) { - CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) - case BT_S: case BT_CR: case BT_LF: - continue; - case BT_GT: -gt: - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_START_TAG_WITH_ATTS; - case BT_SOL: -sol: - ptr += MINBPC(enc); - if (ptr == end) - return XML_TOK_PARTIAL; - if (!CHAR_MATCHES(enc, ptr, '>')) { - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_EMPTY_ELEMENT_WITH_ATTS; - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - break; - } - break; - } - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - } - return XML_TOK_PARTIAL; -} - -/* ptr points to character following "<" */ - -static -int PREFIX(scanLt)(const ENCODING *enc, const char *ptr, const char *end, - const char **nextTokPtr) -{ -#ifdef XML_NS - int hadColon; -#endif - if (ptr == end) - return XML_TOK_PARTIAL; - switch (BYTE_TYPE(enc, ptr)) { - CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) - case BT_EXCL: - if ((ptr += MINBPC(enc)) == end) - return XML_TOK_PARTIAL; - switch (BYTE_TYPE(enc, ptr)) { - case BT_MINUS: - return PREFIX(scanComment)(enc, ptr + MINBPC(enc), end, nextTokPtr); - case BT_LSQB: - return PREFIX(scanCdataSection)(enc, ptr + MINBPC(enc), end, nextTokPtr); - } - *nextTokPtr = ptr; - return XML_TOK_INVALID; - case BT_QUEST: - return PREFIX(scanPi)(enc, ptr + MINBPC(enc), end, nextTokPtr); - case BT_SOL: - return PREFIX(scanEndTag)(enc, ptr + MINBPC(enc), end, nextTokPtr); - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } -#ifdef XML_NS - hadColon = 0; -#endif - /* we have a start-tag */ - while (ptr != end) { - switch (BYTE_TYPE(enc, ptr)) { - CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) -#ifdef XML_NS - case BT_COLON: - if (hadColon) { - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - hadColon = 1; - ptr += MINBPC(enc); - if (ptr == end) - return XML_TOK_PARTIAL; - switch (BYTE_TYPE(enc, ptr)) { - CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - break; -#endif -case BT_S: case BT_CR: case BT_LF: - { - ptr += MINBPC(enc); - while (ptr != end) { - switch (BYTE_TYPE(enc, ptr)) { - CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) - case BT_GT: - goto gt; - case BT_SOL: - goto sol; - case BT_S: case BT_CR: case BT_LF: - ptr += MINBPC(enc); - continue; - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - return PREFIX(scanAtts)(enc, ptr, end, nextTokPtr); - } - return XML_TOK_PARTIAL; - } - case BT_GT: -gt: - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_START_TAG_NO_ATTS; - case BT_SOL: -sol: - ptr += MINBPC(enc); - if (ptr == end) - return XML_TOK_PARTIAL; - if (!CHAR_MATCHES(enc, ptr, '>')) { - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_EMPTY_ELEMENT_NO_ATTS; - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - } - return XML_TOK_PARTIAL; -} - -static -int PREFIX(contentTok)(const ENCODING *enc, const char *ptr, const char *end, - const char **nextTokPtr) -{ - if (ptr == end) - return XML_TOK_NONE; - if (MINBPC(enc) > 1) { - size_t n = end - ptr; - if (n & (MINBPC(enc) - 1)) { - n &= ~(MINBPC(enc) - 1); - if (n == 0) - return XML_TOK_PARTIAL; - end = ptr + n; - } - } - switch (BYTE_TYPE(enc, ptr)) { - case BT_LT: - return PREFIX(scanLt)(enc, ptr + MINBPC(enc), end, nextTokPtr); - case BT_AMP: - return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr); - case BT_CR: - ptr += MINBPC(enc); - if (ptr == end) - return XML_TOK_TRAILING_CR; - if (BYTE_TYPE(enc, ptr) == BT_LF) - ptr += MINBPC(enc); - *nextTokPtr = ptr; - return XML_TOK_DATA_NEWLINE; - case BT_LF: - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_DATA_NEWLINE; - case BT_RSQB: - ptr += MINBPC(enc); - if (ptr == end) - return XML_TOK_TRAILING_RSQB; - if (!CHAR_MATCHES(enc, ptr, ']')) - break; - ptr += MINBPC(enc); - if (ptr == end) - return XML_TOK_TRAILING_RSQB; - if (!CHAR_MATCHES(enc, ptr, '>')) { - ptr -= MINBPC(enc); - break; - } - *nextTokPtr = ptr; - return XML_TOK_INVALID; - INVALID_CASES(ptr, nextTokPtr) - default: - ptr += MINBPC(enc); - break; - } - while (ptr != end) { - switch (BYTE_TYPE(enc, ptr)) { -#define LEAD_CASE(n) \ - case BT_LEAD ## n: \ - if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \ - *nextTokPtr = ptr; \ - return XML_TOK_DATA_CHARS; \ - } \ - ptr += n; \ - break; - LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) -#undef LEAD_CASE - case BT_RSQB: - if (ptr + MINBPC(enc) != end) { - if (!CHAR_MATCHES(enc, ptr + MINBPC(enc), ']')) { - ptr += MINBPC(enc); - break; - } - if (ptr + 2*MINBPC(enc) != end) { - if (!CHAR_MATCHES(enc, ptr + 2*MINBPC(enc), '>')) { - ptr += MINBPC(enc); - break; - } - *nextTokPtr = ptr + 2*MINBPC(enc); - return XML_TOK_INVALID; - } - } - /* fall through */ - case BT_AMP: - case BT_LT: - case BT_NONXML: - case BT_MALFORM: - case BT_TRAIL: - case BT_CR: - case BT_LF: - *nextTokPtr = ptr; - return XML_TOK_DATA_CHARS; - default: - ptr += MINBPC(enc); - break; - } - } - *nextTokPtr = ptr; - return XML_TOK_DATA_CHARS; -} - -/* ptr points to character following "%" */ - -static -int PREFIX(scanPercent)(const ENCODING *enc, const char *ptr, const char *end, - const char **nextTokPtr) -{ - if (ptr == end) - return XML_TOK_PARTIAL; - switch (BYTE_TYPE(enc, ptr)) { - CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) -case BT_S: case BT_LF: case BT_CR: case BT_PERCNT: - *nextTokPtr = ptr; - return XML_TOK_PERCENT; - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - while (ptr != end) { - switch (BYTE_TYPE(enc, ptr)) { - CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) - case BT_SEMI: - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_PARAM_ENTITY_REF; - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - } - return XML_TOK_PARTIAL; -} - -static -int PREFIX(scanPoundName)(const ENCODING *enc, const char *ptr, const char *end, - const char **nextTokPtr) -{ - if (ptr == end) - return XML_TOK_PARTIAL; - switch (BYTE_TYPE(enc, ptr)) { - CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - while (ptr != end) { - switch (BYTE_TYPE(enc, ptr)) { - CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) -case BT_CR: case BT_LF: case BT_S: -case BT_RPAR: case BT_GT: case BT_PERCNT: case BT_VERBAR: - *nextTokPtr = ptr; - return XML_TOK_POUND_NAME; - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - } - return XML_TOK_PARTIAL; -} - -static -int PREFIX(scanLit)(int open, const ENCODING *enc, - const char *ptr, const char *end, - const char **nextTokPtr) -{ - while (ptr != end) { - int t = BYTE_TYPE(enc, ptr); - switch (t) { - INVALID_CASES(ptr, nextTokPtr) - case BT_QUOT: - case BT_APOS: - ptr += MINBPC(enc); - if (t != open) - break; - if (ptr == end) - return XML_TOK_PARTIAL; - *nextTokPtr = ptr; - switch (BYTE_TYPE(enc, ptr)) { - case BT_S: case BT_CR: case BT_LF: - case BT_GT: case BT_PERCNT: case BT_LSQB: - return XML_TOK_LITERAL; - default: - return XML_TOK_INVALID; - } - default: - ptr += MINBPC(enc); - break; - } - } - return XML_TOK_PARTIAL; -} - -static -int PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end, - const char **nextTokPtr) -{ - int tok; - if (ptr == end) - return XML_TOK_NONE; - if (MINBPC(enc) > 1) { - size_t n = end - ptr; - if (n & (MINBPC(enc) - 1)) { - n &= ~(MINBPC(enc) - 1); - if (n == 0) - return XML_TOK_PARTIAL; - end = ptr + n; - } - } - switch (BYTE_TYPE(enc, ptr)) { - case BT_QUOT: - return PREFIX(scanLit)(BT_QUOT, enc, ptr + MINBPC(enc), end, nextTokPtr); - case BT_APOS: - return PREFIX(scanLit)(BT_APOS, enc, ptr + MINBPC(enc), end, nextTokPtr); - case BT_LT: - { - ptr += MINBPC(enc); - if (ptr == end) - return XML_TOK_PARTIAL; - switch (BYTE_TYPE(enc, ptr)) { - case BT_EXCL: - return PREFIX(scanDecl)(enc, ptr + MINBPC(enc), end, nextTokPtr); - case BT_QUEST: - return PREFIX(scanPi)(enc, ptr + MINBPC(enc), end, nextTokPtr); - case BT_NMSTRT: - case BT_HEX: - case BT_NONASCII: - case BT_LEAD2: - case BT_LEAD3: - case BT_LEAD4: - *nextTokPtr = ptr - MINBPC(enc); - return XML_TOK_INSTANCE_START; - } - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - case BT_CR: - if (ptr + MINBPC(enc) == end) - return XML_TOK_TRAILING_CR; - /* fall through */ -case BT_S: case BT_LF: - for (;;) { - ptr += MINBPC(enc); - if (ptr == end) - break; - switch (BYTE_TYPE(enc, ptr)) { - case BT_S: case BT_LF: - break; - case BT_CR: - /* don't split CR/LF pair */ - if (ptr + MINBPC(enc) != end) - break; - /* fall through */ - default: - *nextTokPtr = ptr; - return XML_TOK_PROLOG_S; - } - } - *nextTokPtr = ptr; - return XML_TOK_PROLOG_S; - case BT_PERCNT: - return PREFIX(scanPercent)(enc, ptr + MINBPC(enc), end, nextTokPtr); - case BT_COMMA: - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_COMMA; - case BT_LSQB: - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_OPEN_BRACKET; - case BT_RSQB: - ptr += MINBPC(enc); - if (ptr == end) - return XML_TOK_PARTIAL; - if (CHAR_MATCHES(enc, ptr, ']')) { - if (ptr + MINBPC(enc) == end) - return XML_TOK_PARTIAL; - if (CHAR_MATCHES(enc, ptr + MINBPC(enc), '>')) { - *nextTokPtr = ptr + 2*MINBPC(enc); - return XML_TOK_COND_SECT_CLOSE; - } - } - *nextTokPtr = ptr; - return XML_TOK_CLOSE_BRACKET; - case BT_LPAR: - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_OPEN_PAREN; - case BT_RPAR: - ptr += MINBPC(enc); - if (ptr == end) - return XML_TOK_PARTIAL; - switch (BYTE_TYPE(enc, ptr)) { - case BT_AST: - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_CLOSE_PAREN_ASTERISK; - case BT_QUEST: - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_CLOSE_PAREN_QUESTION; - case BT_PLUS: - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_CLOSE_PAREN_PLUS; -case BT_CR: case BT_LF: case BT_S: -case BT_GT: case BT_COMMA: case BT_VERBAR: - case BT_RPAR: - *nextTokPtr = ptr; - return XML_TOK_CLOSE_PAREN; - } - *nextTokPtr = ptr; - return XML_TOK_INVALID; - case BT_VERBAR: - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_OR; - case BT_GT: - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_DECL_CLOSE; - case BT_NUM: - return PREFIX(scanPoundName)(enc, ptr + MINBPC(enc), end, nextTokPtr); -#define LEAD_CASE(n) \ - case BT_LEAD ## n: \ - if (end - ptr < n) \ - return XML_TOK_PARTIAL_CHAR; \ - if (IS_NMSTRT_CHAR(enc, ptr, n)) { \ - ptr += n; \ - tok = XML_TOK_NAME; \ - break; \ - } \ - if (IS_NAME_CHAR(enc, ptr, n)) { \ - ptr += n; \ - tok = XML_TOK_NMTOKEN; \ - break; \ - } \ - *nextTokPtr = ptr; \ - return XML_TOK_INVALID; - LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) -#undef LEAD_CASE - case BT_NMSTRT: - case BT_HEX: - tok = XML_TOK_NAME; - ptr += MINBPC(enc); - break; - case BT_DIGIT: - case BT_NAME: - case BT_MINUS: -#ifdef XML_NS - case BT_COLON: -#endif - tok = XML_TOK_NMTOKEN; - ptr += MINBPC(enc); - break; - case BT_NONASCII: - if (IS_NMSTRT_CHAR_MINBPC(enc, ptr)) { - ptr += MINBPC(enc); - tok = XML_TOK_NAME; - break; - } - if (IS_NAME_CHAR_MINBPC(enc, ptr)) { - ptr += MINBPC(enc); - tok = XML_TOK_NMTOKEN; - break; - } - /* fall through */ - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - while (ptr != end) { - switch (BYTE_TYPE(enc, ptr)) { - CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) -case BT_GT: case BT_RPAR: case BT_COMMA: -case BT_VERBAR: case BT_LSQB: case BT_PERCNT: -case BT_S: case BT_CR: case BT_LF: - *nextTokPtr = ptr; - return tok; -#ifdef XML_NS - case BT_COLON: - ptr += MINBPC(enc); - switch (tok) { - case XML_TOK_NAME: - if (ptr == end) - return XML_TOK_PARTIAL; - tok = XML_TOK_PREFIXED_NAME; - switch (BYTE_TYPE(enc, ptr)) { - CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) - default: - tok = XML_TOK_NMTOKEN; - break; - } - break; - case XML_TOK_PREFIXED_NAME: - tok = XML_TOK_NMTOKEN; - break; - } - break; -#endif - case BT_PLUS: - if (tok == XML_TOK_NMTOKEN) { - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_NAME_PLUS; - case BT_AST: - if (tok == XML_TOK_NMTOKEN) { - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_NAME_ASTERISK; - case BT_QUEST: - if (tok == XML_TOK_NMTOKEN) { - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_NAME_QUESTION; - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - } - return XML_TOK_PARTIAL; -} - -static -int PREFIX(attributeValueTok)(const ENCODING *enc, const char *ptr, const char *end, - const char **nextTokPtr) -{ - const char *start; - if (ptr == end) - return XML_TOK_NONE; - start = ptr; - while (ptr != end) { - switch (BYTE_TYPE(enc, ptr)) { -#define LEAD_CASE(n) \ - case BT_LEAD ## n: ptr += n; break; - LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) -#undef LEAD_CASE - case BT_AMP: - if (ptr == start) - return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr); - *nextTokPtr = ptr; - return XML_TOK_DATA_CHARS; - case BT_LT: - /* this is for inside entity references */ - *nextTokPtr = ptr; - return XML_TOK_INVALID; - case BT_LF: - if (ptr == start) { - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_DATA_NEWLINE; - } - *nextTokPtr = ptr; - return XML_TOK_DATA_CHARS; - case BT_CR: - if (ptr == start) { - ptr += MINBPC(enc); - if (ptr == end) - return XML_TOK_TRAILING_CR; - if (BYTE_TYPE(enc, ptr) == BT_LF) - ptr += MINBPC(enc); - *nextTokPtr = ptr; - return XML_TOK_DATA_NEWLINE; - } - *nextTokPtr = ptr; - return XML_TOK_DATA_CHARS; - case BT_S: - if (ptr == start) { - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_ATTRIBUTE_VALUE_S; - } - *nextTokPtr = ptr; - return XML_TOK_DATA_CHARS; - default: - ptr += MINBPC(enc); - break; - } - } - *nextTokPtr = ptr; - return XML_TOK_DATA_CHARS; -} - -static -int PREFIX(entityValueTok)(const ENCODING *enc, const char *ptr, const char *end, - const char **nextTokPtr) -{ - const char *start; - if (ptr == end) - return XML_TOK_NONE; - start = ptr; - while (ptr != end) { - switch (BYTE_TYPE(enc, ptr)) { -#define LEAD_CASE(n) \ - case BT_LEAD ## n: ptr += n; break; - LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) -#undef LEAD_CASE - case BT_AMP: - if (ptr == start) - return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr); - *nextTokPtr = ptr; - return XML_TOK_DATA_CHARS; - case BT_PERCNT: - if (ptr == start) - return PREFIX(scanPercent)(enc, ptr + MINBPC(enc), end, nextTokPtr); - *nextTokPtr = ptr; - return XML_TOK_DATA_CHARS; - case BT_LF: - if (ptr == start) { - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_DATA_NEWLINE; - } - *nextTokPtr = ptr; - return XML_TOK_DATA_CHARS; - case BT_CR: - if (ptr == start) { - ptr += MINBPC(enc); - if (ptr == end) - return XML_TOK_TRAILING_CR; - if (BYTE_TYPE(enc, ptr) == BT_LF) - ptr += MINBPC(enc); - *nextTokPtr = ptr; - return XML_TOK_DATA_NEWLINE; - } - *nextTokPtr = ptr; - return XML_TOK_DATA_CHARS; - default: - ptr += MINBPC(enc); - break; - } - } - *nextTokPtr = ptr; - return XML_TOK_DATA_CHARS; -} - -static -int PREFIX(isPublicId)(const ENCODING *enc, const char *ptr, const char *end, - const char **badPtr) -{ - ptr += MINBPC(enc); - end -= MINBPC(enc); - for (; ptr != end; ptr += MINBPC(enc)) { - switch (BYTE_TYPE(enc, ptr)) { - case BT_DIGIT: - case BT_HEX: - case BT_MINUS: - case BT_APOS: - case BT_LPAR: - case BT_RPAR: - case BT_PLUS: - case BT_COMMA: - case BT_SOL: - case BT_EQUALS: - case BT_QUEST: - case BT_CR: - case BT_LF: - case BT_SEMI: - case BT_EXCL: - case BT_AST: - case BT_PERCNT: - case BT_NUM: -#ifdef XML_NS - case BT_COLON: -#endif - break; - case BT_S: - if (CHAR_MATCHES(enc, ptr, '\t')) { - *badPtr = ptr; - return 0; - } - break; - case BT_NAME: - case BT_NMSTRT: - if (!(BYTE_TO_ASCII(enc, ptr) & ~0x7f)) - break; - default: - switch (BYTE_TO_ASCII(enc, ptr)) { - case 0x24: /* $ */ - case 0x40: /* @ */ - break; - default: - *badPtr = ptr; - return 0; - } - break; - } - } - return 1; -} - -/* This must only be called for a well-formed start-tag or empty element tag. -Returns the number of attributes. Pointers to the first attsMax attributes -are stored in atts. */ - -static -int PREFIX(getAtts)(const ENCODING *enc, const char *ptr, - int attsMax, ATTRIBUTE *atts) -{ - enum { other, inName, inValue } state = inName; - int nAtts = 0; - int open = 0; - - for (ptr += MINBPC(enc);; ptr += MINBPC(enc)) { - switch (BYTE_TYPE(enc, ptr)) { -#define START_NAME \ - if (state == other) { \ - if (nAtts < attsMax) { \ - atts[nAtts].name = ptr; \ - atts[nAtts].normalized = 1; \ - } \ - state = inName; \ - } -#define LEAD_CASE(n) \ - case BT_LEAD ## n: START_NAME ptr += (n - MINBPC(enc)); break; - LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) -#undef LEAD_CASE - case BT_NONASCII: - case BT_NMSTRT: - case BT_HEX: - START_NAME - break; -#undef START_NAME - case BT_QUOT: - if (state != inValue) { - if (nAtts < attsMax) - atts[nAtts].valuePtr = ptr + MINBPC(enc); - state = inValue; - open = BT_QUOT; - } - else if (open == BT_QUOT) { - state = other; - if (nAtts < attsMax) - atts[nAtts].valueEnd = ptr; - nAtts++; - } - break; - case BT_APOS: - if (state != inValue) { - if (nAtts < attsMax) - atts[nAtts].valuePtr = ptr + MINBPC(enc); - state = inValue; - open = BT_APOS; - } - else if (open == BT_APOS) { - state = other; - if (nAtts < attsMax) - atts[nAtts].valueEnd = ptr; - nAtts++; - } - break; - case BT_AMP: - if (nAtts < attsMax) - atts[nAtts].normalized = 0; - break; - case BT_S: - if (state == inName) - state = other; - else if (state == inValue - && nAtts < attsMax - && atts[nAtts].normalized - && (ptr == atts[nAtts].valuePtr - || BYTE_TO_ASCII(enc, ptr) != ' ' - || BYTE_TO_ASCII(enc, ptr + MINBPC(enc)) == ' ' - || BYTE_TYPE(enc, ptr + MINBPC(enc)) == open)) - atts[nAtts].normalized = 0; - break; - case BT_CR: case BT_LF: - /* This case ensures that the first attribute name is counted - Apart from that we could just change state on the quote. */ - if (state == inName) - state = other; - else if (state == inValue && nAtts < attsMax) - atts[nAtts].normalized = 0; - break; - case BT_GT: - case BT_SOL: - if (state != inValue) - return nAtts; - break; - default: - break; - } - } - /* not reached */ -} - -static -int PREFIX(charRefNumber)(const ENCODING *enc, const char *ptr) -{ - int result = 0; - /* skip &# */ - ptr += 2*MINBPC(enc); - if (CHAR_MATCHES(enc, ptr, 'x')) { - for (ptr += MINBPC(enc); !CHAR_MATCHES(enc, ptr, ';'); ptr += MINBPC(enc)) { - int c = BYTE_TO_ASCII(enc, ptr); - switch (c) { -case '0': case '1': case '2': case '3': case '4': -case '5': case '6': case '7': case '8': case '9': - result <<= 4; - result |= (c - '0'); - break; -case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': - result <<= 4; - result += 10 + (c - 'A'); - break; -case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': - result <<= 4; - result += 10 + (c - 'a'); - break; - } - if (result >= 0x110000) - return -1; - } - } - else { - for (; !CHAR_MATCHES(enc, ptr, ';'); ptr += MINBPC(enc)) { - int c = BYTE_TO_ASCII(enc, ptr); - result *= 10; - result += (c - '0'); - if (result >= 0x110000) - return -1; - } - } - return checkCharRefNumber(result); -} - -static -int PREFIX(predefinedEntityName)(const ENCODING *enc, const char *ptr, const char *end) -{ - switch ((end - ptr)/MINBPC(enc)) { - case 2: - if (CHAR_MATCHES(enc, ptr + MINBPC(enc), 't')) { - switch (BYTE_TO_ASCII(enc, ptr)) { - case 'l': - return '<'; - case 'g': - return '>'; - } - } - break; - case 3: - if (CHAR_MATCHES(enc, ptr, 'a')) { - ptr += MINBPC(enc); - if (CHAR_MATCHES(enc, ptr, 'm')) { - ptr += MINBPC(enc); - if (CHAR_MATCHES(enc, ptr, 'p')) - return '&'; - } - } - break; - case 4: - switch (BYTE_TO_ASCII(enc, ptr)) { - case 'q': - ptr += MINBPC(enc); - if (CHAR_MATCHES(enc, ptr, 'u')) { - ptr += MINBPC(enc); - if (CHAR_MATCHES(enc, ptr, 'o')) { - ptr += MINBPC(enc); - if (CHAR_MATCHES(enc, ptr, 't')) - return '"'; - } - } - break; - case 'a': - ptr += MINBPC(enc); - if (CHAR_MATCHES(enc, ptr, 'p')) { - ptr += MINBPC(enc); - if (CHAR_MATCHES(enc, ptr, 'o')) { - ptr += MINBPC(enc); - if (CHAR_MATCHES(enc, ptr, 's')) - return '\''; - } - } - break; - } - } - return 0; -} - -static -int PREFIX(sameName)(const ENCODING *enc, const char *ptr1, const char *ptr2) -{ - for (;;) { - switch (BYTE_TYPE(enc, ptr1)) { -#define LEAD_CASE(n) \ - case BT_LEAD ## n: \ - if (*ptr1++ != *ptr2++) \ - return 0; - LEAD_CASE(4) LEAD_CASE(3) LEAD_CASE(2) -#undef LEAD_CASE - /* fall through */ - if (*ptr1++ != *ptr2++) - return 0; - break; - case BT_NONASCII: - case BT_NMSTRT: -#ifdef XML_NS - case BT_COLON: -#endif - case BT_HEX: - case BT_DIGIT: - case BT_NAME: - case BT_MINUS: - if (*ptr2++ != *ptr1++) - return 0; - if (MINBPC(enc) > 1) { - if (*ptr2++ != *ptr1++) - return 0; - if (MINBPC(enc) > 2) { - if (*ptr2++ != *ptr1++) - return 0; - if (MINBPC(enc) > 3) { - if (*ptr2++ != *ptr1++) - return 0; - } - } - } - break; - default: - if (MINBPC(enc) == 1 && *ptr1 == *ptr2) - return 1; - switch (BYTE_TYPE(enc, ptr2)) { - case BT_LEAD2: - case BT_LEAD3: - case BT_LEAD4: - case BT_NONASCII: - case BT_NMSTRT: -#ifdef XML_NS - case BT_COLON: -#endif - case BT_HEX: - case BT_DIGIT: - case BT_NAME: - case BT_MINUS: - return 0; - default: - return 1; - } - } - } - /* not reached */ -} - -static -int PREFIX(nameMatchesAscii)(const ENCODING *enc, const char *ptr1, const char *ptr2) -{ - for (; *ptr2; ptr1 += MINBPC(enc), ptr2++) { - if (!CHAR_MATCHES(enc, ptr1, *ptr2)) - return 0; - } - switch (BYTE_TYPE(enc, ptr1)) { - case BT_LEAD2: - case BT_LEAD3: - case BT_LEAD4: - case BT_NONASCII: - case BT_NMSTRT: -#ifdef XML_NS - case BT_COLON: -#endif - case BT_HEX: - case BT_DIGIT: - case BT_NAME: - case BT_MINUS: - return 0; - default: - return 1; - } -} - -static -int PREFIX(nameLength)(const ENCODING *enc, const char *ptr) -{ - const char *start = ptr; - for (;;) { - switch (BYTE_TYPE(enc, ptr)) { -#define LEAD_CASE(n) \ - case BT_LEAD ## n: ptr += n; break; - LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) -#undef LEAD_CASE - case BT_NONASCII: - case BT_NMSTRT: -#ifdef XML_NS - case BT_COLON: -#endif - case BT_HEX: - case BT_DIGIT: - case BT_NAME: - case BT_MINUS: - ptr += MINBPC(enc); - break; - default: - return ptr - start; - } - } -} - -static -const char *PREFIX(skipS)(const ENCODING *enc, const char *ptr) -{ - for (;;) { - switch (BYTE_TYPE(enc, ptr)) { - case BT_LF: - case BT_CR: - case BT_S: - ptr += MINBPC(enc); - break; - default: - return ptr; - } - } -} - -static -void PREFIX(updatePosition)(const ENCODING *enc, - const char *ptr, - const char *end, - POSITION *pos) -{ - while (ptr != end) { - switch (BYTE_TYPE(enc, ptr)) { -#define LEAD_CASE(n) \ - case BT_LEAD ## n: \ - ptr += n; \ - break; - LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) -#undef LEAD_CASE - case BT_LF: - pos->columnNumber = (unsigned)-1; - pos->lineNumber++; - ptr += MINBPC(enc); - break; - case BT_CR: - pos->lineNumber++; - ptr += MINBPC(enc); - if (ptr != end && BYTE_TYPE(enc, ptr) == BT_LF) - ptr += MINBPC(enc); - pos->columnNumber = (unsigned)-1; - break; - default: - ptr += MINBPC(enc); - break; - } - pos->columnNumber++; - } -} - -#undef DO_LEAD_CASE -#undef MULTIBYTE_CASES -#undef INVALID_CASES -#undef CHECK_NAME_CASE -#undef CHECK_NAME_CASES -#undef CHECK_NMSTRT_CASE -#undef CHECK_NMSTRT_CASES diff --git a/protocols/jabber/xmltok_impl.h b/protocols/jabber/xmltok_impl.h deleted file mode 100644 index e72b225c..00000000 --- a/protocols/jabber/xmltok_impl.h +++ /dev/null @@ -1,71 +0,0 @@ -/* -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in -compliance with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" -basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -License for the specific language governing rights and limitations -under the License. - -The Original Code is expat. - -The Initial Developer of the Original Code is James Clark. -Portions created by James Clark are Copyright (C) 1998, 1999 -James Clark. All Rights Reserved. - -Contributor(s): - -Alternatively, the contents of this file may be used under the terms -of the GNU General Public License (the "GPL"), in which case the -provisions of the GPL are applicable instead of those above. If you -wish to allow use of your version of this file only under the terms of -the GPL and not to allow others to use your version of this file under -the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the -GPL. If you do not delete the provisions above, a recipient may use -your version of this file under either the MPL or the GPL. -*/ - -enum { - BT_NONXML, - BT_MALFORM, - BT_LT, - BT_AMP, - BT_RSQB, - BT_LEAD2, - BT_LEAD3, - BT_LEAD4, - BT_TRAIL, - BT_CR, - BT_LF, - BT_GT, - BT_QUOT, - BT_APOS, - BT_EQUALS, - BT_QUEST, - BT_EXCL, - BT_SOL, - BT_SEMI, - BT_NUM, - BT_LSQB, - BT_S, - BT_NMSTRT, - BT_COLON, - BT_HEX, - BT_DIGIT, - BT_NAME, - BT_MINUS, - BT_OTHER, /* known not to be a name or name start character */ - BT_NONASCII, /* might be a name or name start character */ - BT_PERCNT, - BT_LPAR, - BT_RPAR, - BT_AST, - BT_PLUS, - BT_COMMA, - BT_VERBAR -}; - -#include <stddef.h> diff --git a/protocols/jabber/xmltok_ns.c b/protocols/jabber/xmltok_ns.c deleted file mode 100644 index ace3e5a4..00000000 --- a/protocols/jabber/xmltok_ns.c +++ /dev/null @@ -1,117 +0,0 @@ -/* -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in -compliance with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" -basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -License for the specific language governing rights and limitations -under the License. - -The Original Code is expat. - -The Initial Developer of the Original Code is James Clark. -Portions created by James Clark are Copyright (C) 1998, 1999 -James Clark. All Rights Reserved. - -Contributor(s): - -*/ - -const ENCODING *NS(XmlGetUtf8InternalEncoding)() -{ - return &ns(internal_utf8_encoding).enc; -} - -const ENCODING *NS(XmlGetUtf16InternalEncoding)() -{ -#if XML_BYTE_ORDER == 12 - return &ns(internal_little2_encoding).enc; -#elif XML_BYTE_ORDER == 21 -return &ns(internal_big2_encoding).enc; -#else -const short n = 1; - return *(const char *)&n ? &ns(internal_little2_encoding).enc : &ns(internal_big2_encoding).enc; -#endif -} - -static -const ENCODING *NS(encodings)[] = { - &ns(latin1_encoding).enc, - &ns(ascii_encoding).enc, - &ns(utf8_encoding).enc, - &ns(big2_encoding).enc, - &ns(big2_encoding).enc, - &ns(little2_encoding).enc, - &ns(utf8_encoding).enc /* NO_ENC */ -}; - -static -int NS(initScanProlog)(const ENCODING *enc, const char *ptr, const char *end, - const char **nextTokPtr) -{ - return initScan(NS(encodings), (const INIT_ENCODING *)enc, XML_PROLOG_STATE, ptr, end, nextTokPtr); -} - -static -int NS(initScanContent)(const ENCODING *enc, const char *ptr, const char *end, - const char **nextTokPtr) -{ - return initScan(NS(encodings), (const INIT_ENCODING *)enc, XML_CONTENT_STATE, ptr, end, nextTokPtr); -} - -int NS(XmlInitEncoding)(INIT_ENCODING *p, const ENCODING **encPtr, const char *name) -{ - int i = getEncodingIndex(name); - if (i == UNKNOWN_ENC) - return 0; - INIT_ENC_INDEX(p) = (char)i; - p->initEnc.scanners[XML_PROLOG_STATE] = NS(initScanProlog); - p->initEnc.scanners[XML_CONTENT_STATE] = NS(initScanContent); - p->initEnc.updatePosition = initUpdatePosition; - p->encPtr = encPtr; - *encPtr = &(p->initEnc); - return 1; -} - -static -const ENCODING *NS(findEncoding)(const ENCODING *enc, const char *ptr, const char *end) -{ -#define ENCODING_MAX 128 - char buf[ENCODING_MAX]; - char *p = buf; - int i; - XmlUtf8Convert(enc, &ptr, end, &p, p + ENCODING_MAX - 1); - if (ptr != end) - return 0; - *p = 0; - if (streqci(buf, "UTF-16") && enc->minBytesPerChar == 2) - return enc; - i = getEncodingIndex(buf); - if (i == UNKNOWN_ENC) - return 0; - return NS(encodings)[i]; -} - -int NS(XmlParseXmlDecl)(int isGeneralTextEntity, - const ENCODING *enc, - const char *ptr, - const char *end, - const char **badPtr, - const char **versionPtr, - const char **encodingName, - const ENCODING **encoding, - int *standalone) -{ - return doParseXmlDecl(NS(findEncoding), - isGeneralTextEntity, - enc, - ptr, - end, - badPtr, - versionPtr, - encodingName, - encoding, - standalone); -} diff --git a/protocols/jabber/xmltree.c b/protocols/jabber/xmltree.c new file mode 100644 index 00000000..7a165a1e --- /dev/null +++ b/protocols/jabber/xmltree.c @@ -0,0 +1,587 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Simple XML (stream) parse tree handling code (Jabber/XMPP, mainly) * +* * +* Copyright 2006 Wilmer van der Gaast <wilmer@gaast.net> * +* * +* This library is free software; you can redistribute it and/or * +* modify it under the terms of the GNU Lesser General Public * +* License as published by the Free Software Foundation, version * +* 2.1. * +* * +* This library 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 * +* Lesser General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this library; if not, write to the Free Software Foundation, * +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * +* * +****************************************************************************/ + +#include <glib.h> +#include <string.h> +#include <unistd.h> +#include <ctype.h> +#include <stdio.h> + +#include "xmltree.h" + +static void xt_start_element( GMarkupParseContext *ctx, const gchar *element_name, const gchar **attr_names, const gchar **attr_values, gpointer data, GError **error ) +{ + struct xt_parser *xt = data; + struct xt_node *node = g_new0( struct xt_node, 1 ), *nt; + int i; + + node->parent = xt->cur; + node->name = g_strdup( element_name ); + + /* First count the number of attributes */ + for( i = 0; attr_names[i]; i ++ ); + + /* Then allocate a NULL-terminated array. */ + node->attr = g_new0( struct xt_attr, i + 1 ); + + /* And fill it, saving one variable by starting at the end. */ + for( i --; i >= 0; i -- ) + { + node->attr[i].key = g_strdup( attr_names[i] ); + node->attr[i].value = g_strdup( attr_values[i] ); + } + + /* Add it to the linked list of children nodes, if we have a current + node yet. */ + if( xt->cur ) + { + if( xt->cur->children ) + { + for( nt = xt->cur->children; nt->next; nt = nt->next ); + nt->next = node; + } + else + { + xt->cur->children = node; + } + } + else if( xt->root ) + { + /* ERROR situation: A second root-element??? */ + } + + /* Now this node will be the new current node. */ + xt->cur = node; + /* And maybe this is the root? */ + if( xt->root == NULL ) + xt->root = node; +} + +static void xt_text( GMarkupParseContext *ctx, const gchar *text, gsize text_len, gpointer data, GError **error ) +{ + struct xt_parser *xt = data; + struct xt_node *node = xt->cur; + + if( node == NULL ) + return; + + /* FIXME: Does g_renew also OFFICIALLY accept NULL arguments? */ + node->text = g_renew( char, node->text, node->text_len + text_len + 1 ); + memcpy( node->text + node->text_len, text, text_len ); + node->text_len += text_len; + /* Zero termination is always nice to have. */ + node->text[node->text_len] = 0; +} + +static void xt_end_element( GMarkupParseContext *ctx, const gchar *element_name, gpointer data, GError **error ) +{ + struct xt_parser *xt = data; + + xt->cur->flags |= XT_COMPLETE; + xt->cur = xt->cur->parent; +} + +GMarkupParser xt_parser_funcs = +{ + xt_start_element, + xt_end_element, + xt_text, + NULL, + NULL +}; + +struct xt_parser *xt_new( gpointer data ) +{ + struct xt_parser *xt = g_new0( struct xt_parser, 1 ); + + xt->data = data; + xt_reset( xt ); + + return xt; +} + +/* Reset the parser, flush everything we have so far. For example, we need + this for XMPP when doing TLS/SASL to restart the stream. */ +void xt_reset( struct xt_parser *xt ) +{ + if( xt->parser ) + g_markup_parse_context_free( xt->parser ); + + xt->parser = g_markup_parse_context_new( &xt_parser_funcs, 0, xt, NULL ); + + if( xt->root ) + { + xt_free_node( xt->root ); + xt->root = NULL; + xt->cur = NULL; + } +} + +/* Feed the parser, don't execute any handler. Returns -1 on errors, 0 on + end-of-stream and 1 otherwise. */ +int xt_feed( struct xt_parser *xt, char *text, int text_len ) +{ + if( !g_markup_parse_context_parse( xt->parser, text, text_len, &xt->gerr ) ) + { + return -1; + } + + return !( xt->root && xt->root->flags & XT_COMPLETE ); +} + +/* Find completed nodes and see if a handler has to be called. Passing + a node isn't necessary if you want to start at the root, just pass + NULL. This second argument is needed for recursive calls. */ +int xt_handle( struct xt_parser *xt, struct xt_node *node, int depth ) +{ + struct xt_node *c; + xt_status st; + int i; + + /* Just in case someone likes infinite loops... */ + if( xt->root == NULL ) + return 0; + + if( node == NULL ) + return xt_handle( xt, xt->root, depth ); + + if( depth != 0 ) + for( c = node->children; c; c = c->next ) + if( !xt_handle( xt, c, depth > 0 ? depth - 1 : depth ) ) + return 0; + + if( node->flags & XT_COMPLETE && !( node->flags & XT_SEEN ) ) + { + for( i = 0; xt->handlers[i].func; i ++ ) + { + /* This one is fun! \o/ */ + + /* If handler.name == NULL it means it should always match. */ + if( ( xt->handlers[i].name == NULL || + /* If it's not, compare. There should always be a name. */ + g_strcasecmp( xt->handlers[i].name, node->name ) == 0 ) && + /* If handler.parent == NULL, it's a match. */ + ( xt->handlers[i].parent == NULL || + /* If there's a parent node, see if the name matches. */ + ( node->parent ? g_strcasecmp( xt->handlers[i].parent, node->parent->name ) == 0 : + /* If there's no parent, the handler should mention <root> as a parent. */ + g_strcasecmp( xt->handlers[i].parent, "<root>" ) == 0 ) ) ) + { + st = xt->handlers[i].func( node, xt->data ); + + if( st == XT_ABORT ) + return 0; + else if( st != XT_NEXT ) + break; + } + } + + node->flags |= XT_SEEN; + } + + return 1; +} + +/* Garbage collection: Cleans up all nodes that are handled. Useful for + streams because there's no reason to keep a complete packet history + in memory. */ +void xt_cleanup( struct xt_parser *xt, struct xt_node *node, int depth ) +{ + struct xt_node *c, *prev; + + if( !xt || !xt->root ) + return; + + if( node == NULL ) + return xt_cleanup( xt, xt->root, depth ); + + if( node->flags & XT_SEEN && node == xt->root ) + { + xt_free_node( xt->root ); + xt->root = xt->cur = NULL; + /* xt->cur should be NULL already, BTW... */ + + return; + } + + /* c contains the current node, prev the previous node (or NULL). + I admit, this one's pretty horrible. */ + for( c = node->children, prev = NULL; c; prev = c, c = c ? c->next : node->children ) + { + if( c->flags & XT_SEEN ) + { + /* Remove the node from the linked list. */ + if( prev ) + prev->next = c->next; + else + node->children = c->next; + + xt_free_node( c ); + + /* Since the for loop wants to get c->next, make sure + c points at something that exists (and that c->next + will actually be the next item we should check). c + can be NULL now, if we just removed the first item. + That explains the ? thing in for(). */ + c = prev; + } + else + { + /* This node can't be cleaned up yet, but maybe a + subnode can. */ + if( depth != 0 ) + xt_cleanup( xt, c, depth > 0 ? depth - 1 : depth ); + } + } +} + +static void xt_to_string_real( struct xt_node *node, GString *str ) +{ + char *buf; + struct xt_node *c; + int i; + + g_string_append_printf( str, "<%s", node->name ); + + for( i = 0; node->attr[i].key; i ++ ) + { + buf = g_markup_printf_escaped( " %s=\"%s\"", node->attr[i].key, node->attr[i].value ); + g_string_append( str, buf ); + g_free( buf ); + } + + if( node->text == NULL && node->children == NULL ) + { + g_string_append( str, "/>" ); + return; + } + + g_string_append( str, ">" ); + if( node->text_len > 0 ) + { + buf = g_markup_escape_text( node->text, node->text_len ); + g_string_append( str, buf ); + g_free( buf ); + } + + for( c = node->children; c; c = c->next ) + xt_to_string_real( c, str ); + + g_string_append_printf( str, "</%s>", node->name ); +} + +char *xt_to_string( struct xt_node *node ) +{ + GString *ret; + char *real; + + ret = g_string_new( "" ); + xt_to_string_real( node, ret ); + + real = ret->str; + g_string_free( ret, FALSE ); + + return real; +} + +void xt_print( struct xt_node *node ) +{ + int i; + struct xt_node *c; + + /* Indentation */ + for( c = node; c->parent; c = c->parent ) + printf( "\t" ); + + /* Start the tag */ + printf( "<%s", node->name ); + + /* Print the attributes */ + for( i = 0; node->attr[i].key; i ++ ) + printf( " %s=\"%s\"", node->attr[i].key, g_markup_escape_text( node->attr[i].value, -1 ) ); + + /* /> in case there's really *nothing* inside this tag, otherwise + just >. */ + /* If this tag doesn't have any content at all... */ + if( node->text == NULL && node->children == NULL ) + { + printf( "/>\n" ); + return; + /* Then we're finished! */ + } + + /* Otherwise... */ + printf( ">" ); + + /* Only print the text if it contains more than whitespace (TEST). */ + if( node->text_len > 0 ) + { + for( i = 0; node->text[i] && isspace( node->text[i] ); i ++ ); + if( node->text[i] ) + printf( "%s", g_markup_escape_text( node->text, -1 ) ); + } + + if( node->children ) + printf( "\n" ); + + for( c = node->children; c; c = c->next ) + xt_print( c ); + + if( node->children ) + for( c = node; c->parent; c = c->parent ) + printf( "\t" ); + + /* Non-empty tag is now finished. */ + printf( "</%s>\n", node->name ); +} + +struct xt_node *xt_dup( struct xt_node *node ) +{ + struct xt_node *dup = g_new0( struct xt_node, 1 ); + struct xt_node *c, *dc = NULL; + int i; + + /* Let's NOT copy the parent element here BTW! Only do it for children. */ + + dup->name = g_strdup( node->name ); + dup->flags = node->flags; + if( node->text ) + { + dup->text = g_memdup( node->text, node->text_len + 1 ); + dup->text_len = node->text_len; + } + + /* Count the number of attributes and allocate the new array. */ + for( i = 0; node->attr[i].key; i ++ ); + dup->attr = g_new0( struct xt_attr, i + 1 ); + + /* Copy them all! */ + for( i --; i >= 0; i -- ) + { + dup->attr[i].key = g_strdup( node->attr[i].key ); + dup->attr[i].value = g_strdup( node->attr[i].value ); + } + + /* This nice mysterious loop takes care of the children. */ + for( c = node->children; c; c = c->next ) + { + if( dc == NULL ) + dc = dup->children = xt_dup( c ); + else + dc = ( dc->next = xt_dup( c ) ); + + dc->parent = dup; + } + + return dup; +} + +/* Frees a node. This doesn't clean up references to itself from parents! */ +void xt_free_node( struct xt_node *node ) +{ + int i; + + if( !node ) + return; + + g_free( node->name ); + g_free( node->text ); + + for( i = 0; node->attr[i].key; i ++ ) + { + g_free( node->attr[i].key ); + g_free( node->attr[i].value ); + } + g_free( node->attr ); + + while( node->children ) + { + struct xt_node *next = node->children->next; + + xt_free_node( node->children ); + node->children = next; + } + + g_free( node ); +} + +void xt_free( struct xt_parser *xt ) +{ + if( !xt ) + return; + + if( xt->root ) + xt_free_node( xt->root ); + + g_markup_parse_context_free( xt->parser ); + + g_free( xt ); +} + +/* To find a node's child with a specific name, pass the node's children + list, not the node itself! The reason you have to do this by hand: So + that you can also use this function as a find-next. */ +struct xt_node *xt_find_node( struct xt_node *node, char *name ) +{ + while( node ) + { + if( g_strcasecmp( node->name, name ) == 0 ) + break; + + node = node->next; + } + + return node; +} + +char *xt_find_attr( struct xt_node *node, char *key ) +{ + int i; + + if( !node ) + return NULL; + + for( i = 0; node->attr[i].key; i ++ ) + if( g_strcasecmp( node->attr[i].key, key ) == 0 ) + break; + + return node->attr[i].value; +} + +struct xt_node *xt_new_node( char *name, char *text, struct xt_node *children ) +{ + struct xt_node *node, *c; + + node = g_new0( struct xt_node, 1 ); + node->name = g_strdup( name ); + node->children = children; + node->attr = g_new0( struct xt_attr, 1 ); + + if( text ) + { + node->text_len = strlen( text ); + node->text = g_memdup( text, node->text_len + 1 ); + } + + for( c = children; c; c = c->next ) + { + if( c->parent != NULL ) + { + /* ERROR CONDITION: They seem to have a parent already??? */ + } + + c->parent = node; + } + + return node; +} + +void xt_add_child( struct xt_node *parent, struct xt_node *child ) +{ + struct xt_node *node; + + /* This function can actually be used to add more than one child, so + do handle this properly. */ + for( node = child; node; node = node->next ) + { + if( node->parent != NULL ) + { + /* ERROR CONDITION: They seem to have a parent already??? */ + } + + node->parent = parent; + } + + if( parent->children == NULL ) + { + parent->children = child; + } + else + { + for( node = parent->children; node->next; node = node->next ); + node->next = child; + } +} + +void xt_add_attr( struct xt_node *node, char *key, char *value ) +{ + int i; + + /* Now actually it'd be nice if we can also change existing attributes + (which actually means this function doesn't have the right name). + So let's find out if we have this attribute already... */ + for( i = 0; node->attr[i].key; i ++ ) + if( strcmp( node->attr[i].key, key ) == 0 ) + break; + + if( node->attr[i].key == NULL ) + { + /* If not, allocate space for a new attribute. */ + node->attr = g_renew( struct xt_attr, node->attr, i + 2 ); + node->attr[i].key = g_strdup( key ); + node->attr[i+1].key = NULL; + } + else + { + /* Otherwise, free the old value before setting the new one. */ + g_free( node->attr[i].value ); + } + + node->attr[i].value = g_strdup( value ); +} + +int xt_remove_attr( struct xt_node *node, char *key ) +{ + int i, last; + + for( i = 0; node->attr[i].key; i ++ ) + if( strcmp( node->attr[i].key, key ) == 0 ) + break; + + /* If we didn't find the attribute... */ + if( node->attr[i].key == NULL ) + return 0; + + g_free( node->attr[i].key ); + g_free( node->attr[i].value ); + + /* If it's the last, this is easy: */ + if( node->attr[i+1].key == NULL ) + { + node->attr[i].key = node->attr[i].value = NULL; + } + else /* It's also pretty easy, actually. */ + { + /* Find the last item. */ + for( last = i + 1; node->attr[last+1].key; last ++ ); + + node->attr[i] = node->attr[last]; + node->attr[last].key = NULL; + node->attr[last].value = NULL; + } + + /* Let's not bother with reallocating memory here. It takes time and + most packets don't stay in memory for long anyway. */ + + return 1; +} diff --git a/protocols/jabber/xmltree.h b/protocols/jabber/xmltree.h new file mode 100644 index 00000000..70850c1d --- /dev/null +++ b/protocols/jabber/xmltree.h @@ -0,0 +1,97 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Simple XML (stream) parse tree handling code (Jabber/XMPP, mainly) * +* * +* Copyright 2006 Wilmer van der Gaast <wilmer@gaast.net> * +* * +* This library is free software; you can redistribute it and/or * +* modify it under the terms of the GNU Lesser General Public * +* License as published by the Free Software Foundation, version * +* 2.1. * +* * +* This library 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 * +* Lesser General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this library; if not, write to the Free Software Foundation, * +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * +* * +****************************************************************************/ + +#ifndef _XMLTREE_H +#define _XMLTREE_H + +typedef enum +{ + XT_COMPLETE = 1, /* </tag> reached */ + XT_SEEN = 2, /* Handler called (or not defined) */ +} xt_flags; + +typedef enum +{ + XT_ABORT, /* Abort, don't handle the rest anymore */ + XT_HANDLED, /* Handled this tag properly, go to the next one */ + XT_NEXT /* Try if there's another matching handler */ +} xt_status; + +struct xt_attr +{ + char *key, *value; +}; + +struct xt_node +{ + struct xt_node *parent; + struct xt_node *children; + + char *name; + struct xt_attr *attr; + char *text; + int text_len; + + struct xt_node *next; + xt_flags flags; +}; + +typedef xt_status (*xt_handler_func) ( struct xt_node *node, gpointer data ); + +struct xt_handler_entry +{ + char *name, *parent; + xt_handler_func func; +}; + +struct xt_parser +{ + GMarkupParseContext *parser; + struct xt_node *root; + struct xt_node *cur; + + struct xt_handler_entry *handlers; + gpointer data; + + GError *gerr; +}; + +struct xt_parser *xt_new( gpointer data ); +void xt_reset( struct xt_parser *xt ); +int xt_feed( struct xt_parser *xt, char *text, int text_len ); +int xt_handle( struct xt_parser *xt, struct xt_node *node, int depth ); +void xt_cleanup( struct xt_parser *xt, struct xt_node *node, int depth ); +char *xt_to_string( struct xt_node *node ); +void xt_print( struct xt_node *node ); +struct xt_node *xt_dup( struct xt_node *node ); +void xt_free_node( struct xt_node *node ); +void xt_free( struct xt_parser *xt ); +struct xt_node *xt_find_node( struct xt_node *node, char *name ); +char *xt_find_attr( struct xt_node *node, char *key ); + +struct xt_node *xt_new_node( char *name, char *text, struct xt_node *children ); +void xt_add_child( struct xt_node *parent, struct xt_node *child ); +void xt_add_attr( struct xt_node *node, char *key, char *value ); +int xt_remove_attr( struct xt_node *node, char *key ); + +#endif diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c index f8686835..df04e30d 100644 --- a/protocols/msn/msn.c +++ b/protocols/msn/msn.c @@ -28,7 +28,7 @@ static char *msn_set_display_name( set_t *set, char *value ); -static void msn_acc_init( account_t *acc ) +static void msn_init( account_t *acc ) { set_t *s; @@ -38,38 +38,38 @@ static void msn_acc_init( account_t *acc ) static void msn_login( account_t *acc ) { - struct gaim_connection *gc = new_gaim_conn( acc ); + struct im_connection *ic = imcb_new( acc ); struct msn_data *md = g_new0( struct msn_data, 1 ); - gc->proto_data = md; + ic->proto_data = md; md->fd = -1; if( strchr( acc->user, '@' ) == NULL ) { - hide_login_progress( gc, "Invalid account name" ); - signoff( gc ); + imcb_error( ic, "Invalid account name" ); + imc_logout( ic, FALSE ); return; } - set_login_progress( gc, 1, "Connecting" ); + imcb_log( ic, "Connecting" ); - md->fd = proxy_connect( "messenger.hotmail.com", 1863, msn_ns_connected, gc ); + md->fd = proxy_connect( "messenger.hotmail.com", 1863, msn_ns_connected, ic ); if( md->fd < 0 ) { - hide_login_progress( gc, "Could not connect to server" ); - signoff( gc ); + imcb_error( ic, "Could not connect to server" ); + imc_logout( ic, TRUE ); return; } - md->gc = gc; + md->ic = ic; md->away_state = msn_away_state_list; - msn_connections = g_slist_append( msn_connections, gc ); + msn_connections = g_slist_append( msn_connections, ic ); } -static void msn_close( struct gaim_connection *gc ) +static void msn_logout( struct im_connection *ic ) { - struct msn_data *md = gc->proto_data; + struct msn_data *md = ic->proto_data; GSList *l; if( md ) @@ -95,7 +95,7 @@ static void msn_close( struct gaim_connection *gc ) { m = l->data; - serv_got_crap( gc, "Warning: Closing down MSN connection with unsent message to %s, you'll have to resend it.", m->who ); + imcb_log( ic, "Warning: Closing down MSN connection with unsent message to %s, you'll have to resend it.", m->who ); g_free( m->who ); g_free( m->text ); g_free( m ); @@ -110,23 +110,23 @@ static void msn_close( struct gaim_connection *gc ) g_free( md ); } - for( l = gc->permit; l; l = l->next ) + for( l = ic->permit; l; l = l->next ) g_free( l->data ); - g_slist_free( gc->permit ); + g_slist_free( ic->permit ); - for( l = gc->deny; l; l = l->next ) + for( l = ic->deny; l; l = l->next ) g_free( l->data ); - g_slist_free( gc->deny ); + g_slist_free( ic->deny ); - msn_connections = g_slist_remove( msn_connections, gc ); + msn_connections = g_slist_remove( msn_connections, ic ); } -static int msn_send_im( struct gaim_connection *gc, char *who, char *message, int len, int away ) +static int msn_buddy_msg( struct im_connection *ic, char *who, char *message, int away ) { struct msn_switchboard *sb; - struct msn_data *md = gc->proto_data; + struct msn_data *md = ic->proto_data; - if( ( sb = msn_sb_by_handle( gc, who ) ) ) + if( ( sb = msn_sb_by_handle( ic, who ) ) ) { return( msn_sb_sendmessage( sb, message ) ); } @@ -141,7 +141,7 @@ static int msn_send_im( struct gaim_connection *gc, char *who, char *message, in m->text = g_strdup( message ); /* FIXME: *CHECK* the reliability of using spare sb's! */ - if( ( sb = msn_sb_spare( gc ) ) ) + if( ( sb = msn_sb_spare( ic ) ) ) { debug( "Trying to use a spare switchboard to message %s", who ); @@ -159,7 +159,7 @@ static int msn_send_im( struct gaim_connection *gc, char *who, char *message, in /* If we reach this line, there was no spare switchboard, so let's make one. */ g_snprintf( buf, sizeof( buf ), "XFR %d SB\r\n", ++md->trId ); - if( !msn_write( gc, buf, strlen( buf ) ) ) + if( !msn_write( ic, buf, strlen( buf ) ) ) { g_free( m->who ); g_free( m->text ); @@ -179,31 +179,22 @@ static int msn_send_im( struct gaim_connection *gc, char *who, char *message, in return( 0 ); } -static GList *msn_away_states( struct gaim_connection *gc ) +static GList *msn_away_states( struct im_connection *ic ) { - GList *l = NULL; + static GList *l = NULL; int i; - for( i = 0; msn_away_state_list[i].number > -1; i ++ ) - l = g_list_append( l, (void*) msn_away_state_list[i].name ); + if( l == NULL ) + for( i = 0; msn_away_state_list[i].number > -1; i ++ ) + l = g_list_append( l, (void*) msn_away_state_list[i].name ); - return( l ); + return l; } -static char *msn_get_status_string( struct gaim_connection *gc, int number ) -{ - const struct msn_away_state *st = msn_away_state_by_number( number ); - - if( st ) - return( (char*) st->name ); - else - return( "" ); -} - -static void msn_set_away( struct gaim_connection *gc, char *state, char *message ) +static void msn_set_away( struct im_connection *ic, char *state, char *message ) { char buf[1024]; - struct msn_data *md = gc->proto_data; + struct msn_data *md = ic->proto_data; const struct msn_away_state *st; if( strcmp( state, GAIM_AWAY_CUSTOM ) == 0 ) @@ -215,43 +206,43 @@ static void msn_set_away( struct gaim_connection *gc, char *state, char *message md->away_state = st; g_snprintf( buf, sizeof( buf ), "CHG %d %s\r\n", ++md->trId, st->code ); - msn_write( gc, buf, strlen( buf ) ); + msn_write( ic, buf, strlen( buf ) ); } -static void msn_set_info( struct gaim_connection *gc, char *info ) +static void msn_set_my_name( struct im_connection *ic, char *info ) { - msn_set_display_name( set_find( &gc->acc->set, "display_name" ), info ); + msn_set_display_name( set_find( &ic->acc->set, "display_name" ), info ); } -static void msn_get_info(struct gaim_connection *gc, char *who) +static void msn_get_info(struct im_connection *ic, char *who) { /* Just make an URL and let the user fetch the info */ - serv_got_crap( gc, "%s\n%s: %s%s", _("User Info"), _("For now, fetch yourself"), PROFILE_URL, who ); + imcb_log( ic, "%s\n%s: %s%s", _("User Info"), _("For now, fetch yourself"), PROFILE_URL, who ); } -static void msn_add_buddy( struct gaim_connection *gc, char *who ) +static void msn_add_buddy( struct im_connection *ic, char *who, char *group ) { - msn_buddy_list_add( gc, "FL", who, who ); + msn_buddy_list_add( ic, "FL", who, who ); } -static void msn_remove_buddy( struct gaim_connection *gc, char *who, char *group ) +static void msn_remove_buddy( struct im_connection *ic, char *who, char *group ) { - msn_buddy_list_remove( gc, "FL", who ); + msn_buddy_list_remove( ic, "FL", who ); } -static int msn_chat_send( struct gaim_connection *gc, int id, char *message ) +static void msn_chat_msg( struct groupchat *c, char *message, int flags ) { - struct msn_switchboard *sb = msn_sb_by_id( gc, id ); + struct msn_switchboard *sb = msn_sb_by_chat( c ); if( sb ) - return( msn_sb_sendmessage( sb, message ) ); - else - return( 0 ); + msn_sb_sendmessage( sb, message ); + /* FIXME: Error handling (although this can't happen unless something's + already severely broken) disappeared here! */ } -static void msn_chat_invite( struct gaim_connection *gc, int id, char *msg, char *who ) +static void msn_chat_invite( struct groupchat *c, char *msg, char *who ) { - struct msn_switchboard *sb = msn_sb_by_id( gc, id ); + struct msn_switchboard *sb = msn_sb_by_chat( c ); char buf[1024]; if( sb ) @@ -261,39 +252,35 @@ static void msn_chat_invite( struct gaim_connection *gc, int id, char *msg, char } } -static void msn_chat_leave( struct gaim_connection *gc, int id ) +static void msn_chat_leave( struct groupchat *c ) { - struct msn_switchboard *sb = msn_sb_by_id( gc, id ); + struct msn_switchboard *sb = msn_sb_by_chat( c ); if( sb ) msn_sb_write( sb, "OUT\r\n", 5 ); } -static int msn_chat_open( struct gaim_connection *gc, char *who ) +static struct groupchat *msn_chat_with( struct im_connection *ic, char *who ) { struct msn_switchboard *sb; - struct msn_data *md = gc->proto_data; + struct msn_data *md = ic->proto_data; char buf[1024]; - if( ( sb = msn_sb_by_handle( gc, who ) ) ) + if( ( sb = msn_sb_by_handle( ic, who ) ) ) { debug( "Converting existing switchboard to %s to a groupchat", who ); - msn_sb_to_chat( sb ); - return( 1 ); + return msn_sb_to_chat( sb ); } else { struct msn_message *m; - if( ( sb = msn_sb_spare( gc ) ) ) + if( ( sb = msn_sb_spare( ic ) ) ) { debug( "Trying to reuse an existing switchboard as a groupchat with %s", who ); g_snprintf( buf, sizeof( buf ), "CAL %d %s\r\n", ++sb->trId, who ); if( msn_sb_write( sb, buf, strlen( buf ) ) ) - { - msn_sb_to_chat( sb ); - return( 1 ); - } + return msn_sb_to_chat( sb ); } /* If the stuff above failed for some reason: */ @@ -301,7 +288,7 @@ static int msn_chat_open( struct gaim_connection *gc, char *who ) /* Request a new switchboard. */ g_snprintf( buf, sizeof( buf ), "XFR %d SB\r\n", ++md->trId ); - if( !msn_write( gc, buf, strlen( buf ) ) ) + if( !msn_write( ic, buf, strlen( buf ) ) ) return( 0 ); /* Create a magic message. This is quite hackish, but who cares? :-P */ @@ -312,49 +299,50 @@ static int msn_chat_open( struct gaim_connection *gc, char *who ) /* Queue the magic message and cross your fingers. */ md->msgq = g_slist_append( md->msgq, m ); - return( 1 ); + /* FIXME: Can I try to return something here already? */ + return NULL; } - return( 0 ); + return NULL; } -static void msn_keepalive( struct gaim_connection *gc ) +static void msn_keepalive( struct im_connection *ic ) { - msn_write( gc, "PNG\r\n", strlen( "PNG\r\n" ) ); + msn_write( ic, "PNG\r\n", strlen( "PNG\r\n" ) ); } -static void msn_add_permit( struct gaim_connection *gc, char *who ) +static void msn_add_permit( struct im_connection *ic, char *who ) { - msn_buddy_list_add( gc, "AL", who, who ); + msn_buddy_list_add( ic, "AL", who, who ); } -static void msn_rem_permit( struct gaim_connection *gc, char *who ) +static void msn_rem_permit( struct im_connection *ic, char *who ) { - msn_buddy_list_remove( gc, "AL", who ); + msn_buddy_list_remove( ic, "AL", who ); } -static void msn_add_deny( struct gaim_connection *gc, char *who ) +static void msn_add_deny( struct im_connection *ic, char *who ) { struct msn_switchboard *sb; - msn_buddy_list_add( gc, "BL", who, who ); + msn_buddy_list_add( ic, "BL", who, who ); /* If there's still a conversation with this person, close it. */ - if( ( sb = msn_sb_by_handle( gc, who ) ) ) + if( ( sb = msn_sb_by_handle( ic, who ) ) ) { msn_sb_destroy( sb ); } } -static void msn_rem_deny( struct gaim_connection *gc, char *who ) +static void msn_rem_deny( struct im_connection *ic, char *who ) { - msn_buddy_list_remove( gc, "BL", who ); + msn_buddy_list_remove( ic, "BL", who ); } -static int msn_send_typing( struct gaim_connection *gc, char *who, int typing ) +static int msn_send_typing( struct im_connection *ic, char *who, int typing ) { - if( typing ) - return( msn_send_im( gc, who, TYPING_NOTIFICATION_MESSAGE, strlen( TYPING_NOTIFICATION_MESSAGE ), 0 ) ); + if( typing & OPT_TYPING ) + return( msn_buddy_msg( ic, who, TYPING_NOTIFICATION_MESSAGE, 0 ) ); else return( 1 ); } @@ -362,26 +350,26 @@ static int msn_send_typing( struct gaim_connection *gc, char *who, int typing ) static char *msn_set_display_name( set_t *set, char *value ) { account_t *acc = set->data; - struct gaim_connection *gc = acc->gc; + struct im_connection *ic = acc->ic; struct msn_data *md; char buf[1024], *fn; /* Double-check. */ - if( gc == NULL ) + if( ic == NULL ) return NULL; - md = gc->proto_data; + md = ic->proto_data; if( strlen( value ) > 129 ) { - serv_got_crap( gc, "Maximum name length exceeded" ); + imcb_log( ic, "Maximum name length exceeded" ); return NULL; } fn = msn_http_encode( value ); - g_snprintf( buf, sizeof( buf ), "REA %d %s %s\r\n", ++md->trId, gc->username, fn ); - msn_write( gc, buf, strlen( buf ) ); + g_snprintf( buf, sizeof( buf ), "REA %d %s %s\r\n", ++md->trId, ic->acc->user, fn ); + msn_write( ic, buf, strlen( buf ) ); g_free( fn ); /* Returning NULL would be better, because the server still has to @@ -390,26 +378,25 @@ static char *msn_set_display_name( set_t *set, char *value ) return value; } -void msn_init() +void msn_initmodule() { struct prpl *ret = g_new0(struct prpl, 1); ret->name = "msn"; ret->login = msn_login; - ret->acc_init = msn_acc_init; - ret->close = msn_close; - ret->send_im = msn_send_im; + ret->init = msn_init; + ret->logout = msn_logout; + ret->buddy_msg = msn_buddy_msg; ret->away_states = msn_away_states; - ret->get_status_string = msn_get_status_string; ret->set_away = msn_set_away; - ret->set_info = msn_set_info; ret->get_info = msn_get_info; + ret->set_my_name = msn_set_my_name; ret->add_buddy = msn_add_buddy; ret->remove_buddy = msn_remove_buddy; - ret->chat_send = msn_chat_send; + ret->chat_msg = msn_chat_msg; ret->chat_invite = msn_chat_invite; ret->chat_leave = msn_chat_leave; - ret->chat_open = msn_chat_open; + ret->chat_with = msn_chat_with; ret->keepalive = msn_keepalive; ret->add_permit = msn_add_permit; ret->rem_permit = msn_rem_permit; diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h index b4777d41..721466d6 100644 --- a/protocols/msn/msn.h +++ b/protocols/msn/msn.h @@ -56,7 +56,7 @@ struct msn_data { - struct gaim_connection *gc; + struct im_connection *ic; int fd; struct msn_handler_data *handler; @@ -74,7 +74,7 @@ struct msn_data struct msn_switchboard { - struct gaim_connection *gc; + struct im_connection *ic; int fd; gint inp; @@ -88,7 +88,7 @@ struct msn_switchboard GSList *msgq; char *who; - struct conversation *chat; + struct groupchat *chat; }; struct msn_away_state @@ -148,11 +148,11 @@ GSList *msn_switchboards; gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ); /* msn_util.c */ -int msn_write( struct gaim_connection *gc, char *s, int len ); -int msn_logged_in( struct gaim_connection *gc ); -int msn_buddy_list_add( struct gaim_connection *gc, char *list, char *who, char *realname ); -int msn_buddy_list_remove( struct gaim_connection *gc, char *list, char *who ); -void msn_buddy_ask( struct gaim_connection *gc, char *handle, char *realname ); +int msn_write( struct im_connection *ic, char *s, int len ); +int msn_logged_in( struct im_connection *ic ); +int msn_buddy_list_add( struct im_connection *ic, char *list, char *who, char *realname ); +int msn_buddy_list_remove( struct im_connection *ic, char *list, char *who ); +void msn_buddy_ask( struct im_connection *ic, char *handle, char *realname ); char *msn_findheader( char *text, char *header, int len ); char **msn_linesplit( char *line ); int msn_handler( struct msn_handler_data *h ); @@ -166,11 +166,11 @@ const struct msn_status_code *msn_status_by_number( int number ); /* sb.c */ int msn_sb_write( struct msn_switchboard *sb, char *s, int len ); -struct msn_switchboard *msn_sb_create( struct gaim_connection *gc, char *host, int port, char *key, int session ); -struct msn_switchboard *msn_sb_by_handle( struct gaim_connection *gc, char *handle ); -struct msn_switchboard *msn_sb_by_id( struct gaim_connection *gc, int id ); -struct msn_switchboard *msn_sb_spare( struct gaim_connection *gc ); +struct msn_switchboard *msn_sb_create( struct im_connection *ic, char *host, int port, char *key, int session ); +struct msn_switchboard *msn_sb_by_handle( struct im_connection *ic, char *handle ); +struct msn_switchboard *msn_sb_by_chat( struct groupchat *c ); +struct msn_switchboard *msn_sb_spare( struct im_connection *ic ); int msn_sb_sendmessage( struct msn_switchboard *sb, char *text ); -void msn_sb_to_chat( struct msn_switchboard *sb ); +struct groupchat *msn_sb_to_chat( struct msn_switchboard *sb ); void msn_sb_destroy( struct msn_switchboard *sb ); gboolean msn_sb_connected( gpointer data, gint source, b_input_condition cond ); diff --git a/protocols/msn/msn_util.c b/protocols/msn/msn_util.c index ff4c148c..c9eb5ee2 100644 --- a/protocols/msn/msn_util.c +++ b/protocols/msn/msn_util.c @@ -27,38 +27,38 @@ #include "msn.h" #include <ctype.h> -int msn_write( struct gaim_connection *gc, char *s, int len ) +int msn_write( struct im_connection *ic, char *s, int len ) { - struct msn_data *md = gc->proto_data; + struct msn_data *md = ic->proto_data; int st; st = write( md->fd, s, len ); if( st != len ) { - hide_login_progress_error( gc, "Short write() to main server" ); - signoff( gc ); + imcb_error( ic, "Short write() to main server" ); + imc_logout( ic, TRUE ); return( 0 ); } return( 1 ); } -int msn_logged_in( struct gaim_connection *gc ) +int msn_logged_in( struct im_connection *ic ) { - account_online( gc ); + imcb_connected( ic ); return( 0 ); } -int msn_buddy_list_add( struct gaim_connection *gc, char *list, char *who, char *realname_ ) +int msn_buddy_list_add( struct im_connection *ic, char *list, char *who, char *realname_ ) { - struct msn_data *md = gc->proto_data; + struct msn_data *md = ic->proto_data; char buf[1024], *realname; realname = msn_http_encode( realname_ ); g_snprintf( buf, sizeof( buf ), "ADD %d %s %s %s\r\n", ++md->trId, list, who, realname ); - if( msn_write( gc, buf, strlen( buf ) ) ) + if( msn_write( ic, buf, strlen( buf ) ) ) { g_free( realname ); @@ -70,13 +70,13 @@ int msn_buddy_list_add( struct gaim_connection *gc, char *list, char *who, char return( 0 ); } -int msn_buddy_list_remove( struct gaim_connection *gc, char *list, char *who ) +int msn_buddy_list_remove( struct im_connection *ic, char *list, char *who ) { - struct msn_data *md = gc->proto_data; + struct msn_data *md = ic->proto_data; char buf[1024]; g_snprintf( buf, sizeof( buf ), "REM %d %s %s\r\n", ++md->trId, list, who ); - if( msn_write( gc, buf, strlen( buf ) ) ) + if( msn_write( ic, buf, strlen( buf ) ) ) return( 1 ); return( 0 ); @@ -84,17 +84,17 @@ int msn_buddy_list_remove( struct gaim_connection *gc, char *list, char *who ) struct msn_buddy_ask_data { - struct gaim_connection *gc; + struct im_connection *ic; char *handle; char *realname; }; 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 ); + msn_buddy_list_add( bla->ic, "AL", bla->handle, bla->realname ); - if( find_buddy( bla->gc, bla->handle ) == NULL ) - show_got_added( bla->gc, bla->handle, NULL ); + if( imcb_find_buddy( bla->ic, bla->handle ) == NULL ) + imcb_ask_add( bla->ic, bla->handle, NULL ); g_free( bla->handle ); g_free( bla->realname ); @@ -103,26 +103,26 @@ static void msn_buddy_ask_yes( gpointer w, struct msn_buddy_ask_data *bla ) static void msn_buddy_ask_no( gpointer w, struct msn_buddy_ask_data *bla ) { - msn_buddy_list_add( bla->gc, "BL", bla->handle, bla->realname ); + msn_buddy_list_add( bla->ic, "BL", bla->handle, bla->realname ); g_free( bla->handle ); g_free( bla->realname ); g_free( bla ); } -void msn_buddy_ask( struct gaim_connection *gc, char *handle, char *realname ) +void msn_buddy_ask( struct im_connection *ic, char *handle, char *realname ) { struct msn_buddy_ask_data *bla = g_new0( struct msn_buddy_ask_data, 1 ); char buf[1024]; - bla->gc = gc; + bla->ic = ic; bla->handle = g_strdup( handle ); bla->realname = g_strdup( realname ); g_snprintf( buf, sizeof( buf ), "The user %s (%s) wants to add you to his/her buddy list.", handle, realname ); - do_ask_dialog( gc, buf, bla, msn_buddy_ask_yes, msn_buddy_ask_no ); + imcb_ask( ic, buf, bla, msn_buddy_ask_yes, msn_buddy_ask_no ); } char *msn_findheader( char *text, char *header, int len ) diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index 9774f3e2..9bd7f152 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -37,26 +37,26 @@ static void msn_auth_got_passport_id( struct passport_reply *rep ); gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ) { - struct gaim_connection *gc = data; + struct im_connection *ic = data; struct msn_data *md; char s[1024]; - if( !g_slist_find( msn_connections, gc ) ) + if( !g_slist_find( msn_connections, ic ) ) return FALSE; if( source == -1 ) { - hide_login_progress( gc, "Could not connect to server" ); - signoff( gc ); + imcb_error( ic, "Could not connect to server" ); + imc_logout( ic, TRUE ); return FALSE; } - md = gc->proto_data; + md = ic->proto_data; if( !md->handler ) { md->handler = g_new0( struct msn_handler_data, 1 ); - md->handler->data = gc; + md->handler->data = ic; md->handler->exec_command = msn_ns_command; md->handler->exec_message = msn_ns_message; } @@ -72,10 +72,10 @@ gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ) md->handler->rxq = g_new0( char, 1 ); g_snprintf( s, sizeof( s ), "VER %d MSNP8 CVR0\r\n", ++md->trId ); - if( msn_write( gc, s, strlen( s ) ) ) + if( msn_write( ic, s, strlen( s ) ) ) { - gc->inpa = b_input_add( md->fd, GAIM_INPUT_READ, msn_ns_callback, gc ); - set_login_progress( gc, 1, "Connected to server, waiting for reply" ); + ic->inpa = b_input_add( md->fd, GAIM_INPUT_READ, msn_ns_callback, ic ); + imcb_log( ic, "Connected to server, waiting for reply" ); } return FALSE; @@ -83,13 +83,13 @@ gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ) static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition cond ) { - struct gaim_connection *gc = data; - struct msn_data *md = gc->proto_data; + struct im_connection *ic = data; + struct msn_data *md = ic->proto_data; if( msn_handler( md->handler ) == -1 ) /* Don't do this on ret == 0, it's already done then. */ { - hide_login_progress( gc, "Error while reading from server" ); - signoff( gc ); + imcb_error( ic, "Error while reading from server" ); + imc_logout( ic, TRUE ); return FALSE; } @@ -99,8 +99,8 @@ static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition c static int msn_ns_command( gpointer data, char **cmd, int num_parts ) { - struct gaim_connection *gc = data; - struct msn_data *md = gc->proto_data; + struct im_connection *ic = data; + struct msn_data *md = ic->proto_data; char buf[1024]; if( num_parts == 0 ) @@ -113,20 +113,20 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) { if( cmd[2] && strncmp( cmd[2], "MSNP8", 5 ) != 0 ) { - hide_login_progress( gc, "Unsupported protocol" ); - signoff( gc ); + imcb_error( ic, "Unsupported protocol" ); + imc_logout( ic, FALSE ); return( 0 ); } g_snprintf( buf, sizeof( buf ), "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s\r\n", - ++md->trId, gc->username ); - return( msn_write( gc, buf, strlen( buf ) ) ); + ++md->trId, ic->acc->user ); + return( msn_write( ic, buf, strlen( buf ) ) ); } else if( strcmp( cmd[0], "CVR" ) == 0 ) { /* We don't give a damn about the information we just received */ - g_snprintf( buf, sizeof( buf ), "USR %d TWN I %s\r\n", ++md->trId, gc->username ); - return( msn_write( gc, buf, strlen( buf ) ) ); + g_snprintf( buf, sizeof( buf ), "USR %d TWN I %s\r\n", ++md->trId, ic->acc->user ); + return( msn_write( ic, buf, strlen( buf ) ) ); } else if( strcmp( cmd[0], "XFR" ) == 0 ) { @@ -135,24 +135,24 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( num_parts == 6 && strcmp( cmd[2], "NS" ) == 0 ) { - b_event_remove( gc->inpa ); - gc->inpa = 0; + b_event_remove( ic->inpa ); + ic->inpa = 0; closesocket( md->fd ); server = strchr( cmd[3], ':' ); if( !server ) { - hide_login_progress_error( gc, "Syntax error" ); - signoff( gc ); + imcb_error( ic, "Syntax error" ); + imc_logout( ic, TRUE ); return( 0 ); } *server = 0; port = atoi( server + 1 ); server = cmd[3]; - set_login_progress( gc, 1, "Transferring to other server" ); + imcb_log( ic, "Transferring to other server" ); - md->fd = proxy_connect( server, port, msn_ns_connected, gc ); + md->fd = proxy_connect( server, port, msn_ns_connected, ic ); } else if( num_parts == 6 && strcmp( cmd[2], "SB" ) == 0 ) { @@ -161,8 +161,8 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) server = strchr( cmd[3], ':' ); if( !server ) { - hide_login_progress_error( gc, "Syntax error" ); - signoff( gc ); + imcb_error( ic, "Syntax error" ); + imc_logout( ic, TRUE ); return( 0 ); } *server = 0; @@ -171,13 +171,13 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( strcmp( cmd[4], "CKI" ) != 0 ) { - hide_login_progress_error( gc, "Unknown authentication method for switchboard" ); - signoff( gc ); + imcb_error( ic, "Unknown authentication method for switchboard" ); + imc_logout( ic, TRUE ); return( 0 ); } debug( "Connecting to a new switchboard with key %s", cmd[5] ); - sb = msn_sb_create( gc, server, port, cmd[5], MSN_SB_NEW ); + sb = msn_sb_create( ic, server, port, cmd[5], MSN_SB_NEW ); if( md->msgq ) { @@ -203,8 +203,8 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) } else { - hide_login_progress_error( gc, "Syntax error" ); - signoff( gc ); + imcb_error( ic, "Syntax error" ); + imc_logout( ic, TRUE ); return( 0 ); } } @@ -213,10 +213,10 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( num_parts == 5 && strcmp( cmd[2], "TWN" ) == 0 && strcmp( cmd[3], "S" ) == 0 ) { /* Time for some Passport black magic... */ - if( !passport_get_id( msn_auth_got_passport_id, gc, gc->username, gc->password, cmd[4] ) ) + if( !passport_get_id( msn_auth_got_passport_id, ic, ic->acc->user, ic->acc->pass, cmd[4] ) ) { - hide_login_progress_error( gc, "Error while contacting Passport server" ); - signoff( gc ); + imcb_error( ic, "Error while contacting Passport server" ); + imc_logout( ic, TRUE ); return( 0 ); } } @@ -226,24 +226,24 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) http_decode( cmd[4] ); - strncpy( gc->displayname, cmd[4], sizeof( gc->displayname ) ); - gc->displayname[sizeof(gc->displayname)-1] = 0; + strncpy( ic->displayname, cmd[4], sizeof( ic->displayname ) ); + ic->displayname[sizeof(ic->displayname)-1] = 0; - if( ( s = set_find( &gc->acc->set, "display_name" ) ) ) + if( ( s = set_find( &ic->acc->set, "display_name" ) ) ) { g_free( s->value ); s->value = g_strdup( cmd[4] ); } - set_login_progress( gc, 1, "Authenticated, getting buddy list" ); + imcb_log( ic, "Authenticated, getting buddy list" ); g_snprintf( buf, sizeof( buf ), "SYN %d 0\r\n", ++md->trId ); - return( msn_write( gc, buf, strlen( buf ) ) ); + return( msn_write( ic, buf, strlen( buf ) ) ); } else { - hide_login_progress( gc, "Unknown authentication type" ); - signoff( gc ); + imcb_error( ic, "Unknown authentication type" ); + imc_logout( ic, FALSE ); return( 0 ); } } @@ -251,8 +251,8 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) { if( num_parts != 4 ) { - hide_login_progress_error( gc, "Syntax error" ); - signoff( gc ); + imcb_error( ic, "Syntax error" ); + imc_logout( ic, TRUE ); return( 0 ); } @@ -260,8 +260,8 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( md->handler->msglen <= 0 ) { - hide_login_progress_error( gc, "Syntax error" ); - signoff( gc ); + imcb_error( ic, "Syntax error" ); + imc_logout( ic, TRUE ); return( 0 ); } } @@ -275,14 +275,14 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) md->grouplist = g_new0( char *, md->groupcount ); if( !*cmd[3] || md->buddycount == 0 ) - msn_logged_in( gc ); + msn_logged_in( ic ); } else { /* Hrrm... This SYN reply doesn't really look like something we expected. Let's assume everything is okay. */ - msn_logged_in( gc ); + msn_logged_in( ic ); } } else if( strcmp( cmd[0], "LST" ) == 0 ) @@ -291,8 +291,8 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( num_parts != 4 && num_parts != 5 ) { - hide_login_progress( gc, "Syntax error" ); - signoff( gc ); + imcb_error( ic, "Syntax error" ); + imc_logout( ic, TRUE ); return( 0 ); } @@ -304,36 +304,37 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) char *group = NULL; int num; - if( cmd[4] != NULL && sscanf( cmd[4], "%d", &num ) == 1 ) + if( cmd[4] != NULL && sscanf( cmd[4], "%d", &num ) == 1 && num < md->groupcount ) group = md->grouplist[num]; - add_buddy( gc, group, cmd[1], cmd[2] ); + imcb_add_buddy( ic, cmd[1], group ); + imcb_rename_buddy( ic, cmd[1], cmd[2] ); } if( list & 2 ) /* AL */ { - gc->permit = g_slist_append( gc->permit, g_strdup( cmd[1] ) ); + ic->permit = g_slist_append( ic->permit, g_strdup( cmd[1] ) ); } if( list & 4 ) /* BL */ { - gc->deny = g_slist_append( gc->deny, g_strdup( cmd[1] ) ); + ic->deny = g_slist_append( ic->deny, g_strdup( cmd[1] ) ); } if( list & 8 ) /* RL */ { if( ( list & 6 ) == 0 ) - msn_buddy_ask( gc, cmd[1], cmd[2] ); + msn_buddy_ask( ic, cmd[1], cmd[2] ); } if( --md->buddycount == 0 ) { - if( gc->flags & OPT_LOGGED_IN ) + if( ic->flags & OPT_LOGGED_IN ) { - serv_got_crap( gc, "Successfully transferred to different server" ); + imcb_log( ic, "Successfully transferred to different server" ); 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( msn_write( ic, buf, strlen( buf ) ) ); } else { - msn_logged_in( gc ); + msn_logged_in( ic ); } } } @@ -343,8 +344,8 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( num_parts != 4 ) { - hide_login_progress_error( gc, "Syntax error" ); - signoff( gc ); + imcb_error( ic, "Syntax error" ); + imc_logout( ic, TRUE ); return( 0 ); } @@ -362,8 +363,8 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( num_parts != 3 ) { - hide_login_progress_error( gc, "Syntax error" ); - signoff( gc ); + imcb_error( ic, "Syntax error" ); + imc_logout( ic, TRUE ); return( 0 ); } @@ -376,7 +377,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) for( i = 0; i < 16; i ++ ) g_snprintf( buf + strlen( buf ), 3, "%02x", digest[i] ); - return( msn_write( gc, buf, strlen( buf ) ) ); + return( msn_write( ic, buf, strlen( buf ) ) ); } else if( strcmp( cmd[0], "ILN" ) == 0 ) { @@ -384,13 +385,13 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( num_parts != 6 ) { - hide_login_progress_error( gc, "Syntax error" ); - signoff( gc ); + imcb_error( ic, "Syntax error" ); + imc_logout( ic, TRUE ); return( 0 ); } http_decode( cmd[4] ); - serv_buddy_rename( gc, cmd[3], cmd[4] ); + imcb_rename_buddy( ic, cmd[3], cmd[4] ); st = msn_away_state_by_code( cmd[2] ); if( !st ) @@ -399,12 +400,13 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) st = msn_away_state_list; } - serv_got_update( gc, cmd[3], 1, 0, 0, 0, st->number, 0 ); + imcb_buddy_status( ic, cmd[3], OPT_LOGGED_IN | + ( st->number ? OPT_AWAY : 0 ), st->name, NULL ); } else if( strcmp( cmd[0], "FLN" ) == 0 ) { if( cmd[1] ) - serv_got_update( gc, cmd[1], 0, 0, 0, 0, 0, 0 ); + imcb_buddy_status( ic, cmd[1], 0, NULL, NULL ); } else if( strcmp( cmd[0], "NLN" ) == 0 ) { @@ -412,13 +414,13 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( num_parts != 5 ) { - hide_login_progress_error( gc, "Syntax error" ); - signoff( gc ); + imcb_error( ic, "Syntax error" ); + imc_logout( ic, TRUE ); return( 0 ); } http_decode( cmd[3] ); - serv_buddy_rename( gc, cmd[2], cmd[3] ); + imcb_rename_buddy( ic, cmd[2], cmd[3] ); st = msn_away_state_by_code( cmd[1] ); if( !st ) @@ -427,7 +429,8 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) st = msn_away_state_list; } - serv_got_update( gc, cmd[2], 1, 0, 0, 0, st->number, 0 ); + imcb_buddy_status( ic, cmd[2], OPT_LOGGED_IN | + ( st->number ? OPT_AWAY : 0 ), st->name, NULL ); } else if( strcmp( cmd[0], "RNG" ) == 0 ) { @@ -437,8 +440,8 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( num_parts != 7 ) { - hide_login_progress_error( gc, "Syntax error" ); - signoff( gc ); + imcb_error( ic, "Syntax error" ); + imc_logout( ic, TRUE ); return( 0 ); } @@ -447,8 +450,8 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) server = strchr( cmd[2], ':' ); if( !server ) { - hide_login_progress_error( gc, "Syntax error" ); - signoff( gc ); + imcb_error( ic, "Syntax error" ); + imc_logout( ic, TRUE ); return( 0 ); } *server = 0; @@ -457,14 +460,14 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( strcmp( cmd[3], "CKI" ) != 0 ) { - hide_login_progress_error( gc, "Unknown authentication method for switchboard" ); - signoff( gc ); + imcb_error( ic, "Unknown authentication method for switchboard" ); + imc_logout( ic, TRUE ); return( 0 ); } debug( "Got a call from %s (session %d). Key = %s", cmd[5], session, cmd[4] ); - sb = msn_sb_create( gc, server, port, cmd[4], session ); + sb = msn_sb_create( ic, server, port, cmd[4], session ); sb->who = g_strdup( cmd[5] ); } else if( strcmp( cmd[0], "ADD" ) == 0 ) @@ -477,60 +480,69 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( strchr( cmd[4], '@' ) == NULL ) { - hide_login_progress_error( gc, "Syntax error" ); - signoff( gc ); - return( 0 ); + imcb_error( ic, "Syntax error" ); + imc_logout( ic, TRUE ); + return 0; } - /* We got added by someone. If we don't have this person in permit/deny yet, inform the user. */ - for( l = gc->permit; l; l = l->next ) + /* We got added by someone. If we don't have this + person in permit/deny yet, inform the user. */ + for( l = ic->permit; l; l = l->next ) if( g_strcasecmp( l->data, cmd[4] ) == 0 ) - return( 1 ); + return 1; - for( l = gc->deny; l; l = l->next ) + for( l = ic->deny; l; l = l->next ) if( g_strcasecmp( l->data, cmd[4] ) == 0 ) - return( 1 ); + return 1; - msn_buddy_ask( gc, cmd[4], cmd[5] ); + msn_buddy_ask( ic, cmd[4], cmd[5] ); + } + else if( num_parts >= 6 && strcmp( cmd[2], "FL" ) == 0 ) + { + http_decode( cmd[5] ); + imcb_add_buddy( ic, cmd[4], NULL ); + imcb_rename_buddy( ic, cmd[4], cmd[5] ); } } else if( strcmp( cmd[0], "OUT" ) == 0 ) { + int allow_reconnect = TRUE; + if( cmd[1] && strcmp( cmd[1], "OTH" ) == 0 ) { - hide_login_progress_error( gc, "Someone else logged in with your account" ); - gc->wants_to_die = 1; + imcb_error( ic, "Someone else logged in with your account" ); + allow_reconnect = FALSE; } else if( cmd[1] && strcmp( cmd[1], "SSD" ) == 0 ) { - hide_login_progress_error( gc, "Terminating session because of server shutdown" ); + imcb_error( ic, "Terminating session because of server shutdown" ); } else { - hide_login_progress_error( gc, "Session terminated by remote server (reason unknown)" ); + imcb_error( ic, "Session terminated by remote server (reason unknown)" ); } - signoff( gc ); + imc_logout( ic, allow_reconnect ); return( 0 ); } else if( strcmp( cmd[0], "REA" ) == 0 ) { if( num_parts != 5 ) { - hide_login_progress_error( gc, "Syntax error" ); - signoff( gc ); + imcb_error( ic, "Syntax error" ); + imc_logout( ic, TRUE ); return( 0 ); } - if( g_strcasecmp( cmd[3], gc->username ) == 0 ) + if( g_strcasecmp( cmd[3], ic->acc->user ) == 0 ) { set_t *s; http_decode( cmd[4] ); - strncpy( gc->displayname, cmd[4], sizeof( gc->displayname ) ); - gc->displayname[sizeof(gc->displayname)-1] = 0; + strncpy( ic->displayname, cmd[4], sizeof( ic->displayname ) ); + ic->displayname[sizeof(ic->displayname)-1] = 0; - if( ( s = set_find( &gc->acc->set, "display_name" ) ) ) + if( ( s = set_find( &ic->acc->set, "display_name" ) ) ) { g_free( s->value ); s->value = g_strdup( cmd[4] ); @@ -540,19 +552,19 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) { /* This is not supposed to happen, but let's handle it anyway... */ http_decode( cmd[4] ); - serv_buddy_rename( gc, cmd[3], cmd[4] ); + imcb_rename_buddy( ic, cmd[3], cmd[4] ); } } else if( strcmp( cmd[0], "IPG" ) == 0 ) { - do_error_dialog( gc, "Received IPG command, we don't handle them yet.", "MSN" ); + imcb_error( ic, "Received IPG command, we don't handle them yet." ); md->handler->msglen = atoi( cmd[1] ); if( md->handler->msglen <= 0 ) { - hide_login_progress_error( gc, "Syntax error" ); - signoff( gc ); + imcb_error( ic, "Syntax error" ); + imc_logout( ic, TRUE ); return( 0 ); } } @@ -561,12 +573,11 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) int num = atoi( cmd[0] ); const struct msn_status_code *err = msn_status_by_number( num ); - g_snprintf( buf, sizeof( buf ), "Error reported by MSN server: %s", err->text ); - do_error_dialog( gc, buf, "MSN" ); + imcb_error( ic, "Error reported by MSN server: %s", err->text ); if( err->flags & STATUS_FATAL ) { - signoff( gc ); + imc_logout( ic, TRUE ); return( 0 ); } } @@ -580,7 +591,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts ) { - struct gaim_connection *gc = data; + struct im_connection *ic = data; char *body; int blen = 0; @@ -616,7 +627,7 @@ static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int if( mtype && strcmp( mtype, "1" ) == 0 ) { if( arg1 ) - serv_got_crap( gc, "The server is going down for maintenance in %s minutes.", arg1 ); + imcb_log( ic, "The server is going down for maintenance in %s minutes.", arg1 ); } if( arg1 ) g_free( arg1 ); @@ -633,7 +644,7 @@ static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int if( inbox && folders ) { - serv_got_crap( gc, "INBOX contains %s new messages, plus %s messages in other folders.", inbox, folders ); + imcb_log( ic, "INBOX contains %s new messages, plus %s messages in other folders.", inbox, folders ); } } else if( g_strncasecmp( ct, "text/x-msmsgsemailnotification", 30 ) == 0 ) @@ -643,7 +654,7 @@ static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int if( from && fromname ) { - serv_got_crap( gc, "Received an e-mail message from %s <%s>.", fromname, from ); + imcb_log( ic, "Received an e-mail message from %s <%s>.", fromname, from ); } } else if( g_strncasecmp( ct, "text/x-msmsgsactivemailnotification", 35 ) == 0 ) @@ -664,26 +675,20 @@ static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int static void msn_auth_got_passport_id( struct passport_reply *rep ) { - struct gaim_connection *gc = rep->data; - struct msn_data *md = gc->proto_data; + struct im_connection *ic = rep->data; + struct msn_data *md = ic->proto_data; char *key = rep->result; char buf[1024]; if( key == NULL ) { - 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 ); + imcb_error( ic, "Error during Passport authentication (%s)", + rep->error_string ? rep->error_string : "Unknown error" ); + imc_logout( ic, TRUE ); } else { g_snprintf( buf, sizeof( buf ), "USR %d TWN S %s\r\n", ++md->trId, key ); - msn_write( gc, buf, strlen( buf ) ); + msn_write( ic, buf, strlen( buf ) ); } } diff --git a/protocols/msn/sb.c b/protocols/msn/sb.c index 7ec340bd..1693cb95 100644 --- a/protocols/msn/sb.c +++ b/protocols/msn/sb.c @@ -47,9 +47,9 @@ int msn_sb_write( struct msn_switchboard *sb, char *s, int len ) return( 1 ); } -struct msn_switchboard *msn_sb_create( struct gaim_connection *gc, char *host, int port, char *key, int session ) +struct msn_switchboard *msn_sb_create( struct im_connection *ic, char *host, int port, char *key, int session ) { - struct msn_data *md = gc->proto_data; + struct msn_data *md = ic->proto_data; struct msn_switchboard *sb = g_new0( struct msn_switchboard, 1 ); sb->fd = proxy_connect( host, port, msn_sb_connected, sb ); @@ -59,7 +59,7 @@ struct msn_switchboard *msn_sb_create( struct gaim_connection *gc, char *host, i return( NULL ); } - sb->gc = gc; + sb->ic = ic; sb->key = g_strdup( key ); sb->session = session; @@ -69,9 +69,9 @@ struct msn_switchboard *msn_sb_create( struct gaim_connection *gc, char *host, i return( sb ); } -struct msn_switchboard *msn_sb_by_handle( struct gaim_connection *gc, char *handle ) +struct msn_switchboard *msn_sb_by_handle( struct im_connection *ic, char *handle ) { - struct msn_data *md = gc->proto_data; + struct msn_data *md = ic->proto_data; struct msn_switchboard *sb; GSList *l; @@ -85,25 +85,25 @@ struct msn_switchboard *msn_sb_by_handle( struct gaim_connection *gc, char *hand return( NULL ); } -struct msn_switchboard *msn_sb_by_id( struct gaim_connection *gc, int id ) +struct msn_switchboard *msn_sb_by_chat( struct groupchat *c ) { - struct msn_data *md = gc->proto_data; + struct msn_data *md = c->ic->proto_data; struct msn_switchboard *sb; GSList *l; for( l = md->switchboards; l; l = l->next ) { sb = l->data; - if( sb->chat && sb->chat->id == id ) + if( sb->chat == c ) return( sb ); } return( NULL ); } -struct msn_switchboard *msn_sb_spare( struct gaim_connection *gc ) +struct msn_switchboard *msn_sb_spare( struct im_connection *ic ) { - struct msn_data *md = gc->proto_data; + struct msn_data *md = ic->proto_data; struct msn_switchboard *sb; GSList *l; @@ -141,9 +141,9 @@ int msn_sb_sendmessage( struct msn_switchboard *sb, char *text ) } else { - i = strlen( MSN_TYPING_HEADERS ) + strlen( sb->gc->username ); + i = strlen( MSN_TYPING_HEADERS ) + strlen( sb->ic->acc->user ); buf = g_new0( char, i ); - i = g_snprintf( buf, i, MSN_TYPING_HEADERS, sb->gc->username ); + i = g_snprintf( buf, i, MSN_TYPING_HEADERS, sb->ic->acc->user ); } /* Build the final packet (MSG command + the message). */ @@ -176,18 +176,18 @@ int msn_sb_sendmessage( struct msn_switchboard *sb, char *text ) } } -void msn_sb_to_chat( struct msn_switchboard *sb ) +struct groupchat *msn_sb_to_chat( struct msn_switchboard *sb ) { - struct gaim_connection *gc = sb->gc; + struct im_connection *ic = sb->ic; char buf[1024]; /* Create the groupchat structure. */ g_snprintf( buf, sizeof( buf ), "MSN groupchat session %d", sb->session ); - sb->chat = serv_got_joined_chat( gc, ++msn_chat_id, buf ); + sb->chat = imcb_chat_new( ic, buf ); /* Populate the channel. */ - if( sb->who ) add_chat_buddy( sb->chat, sb->who ); - add_chat_buddy( sb->chat, gc->username ); + if( sb->who ) imcb_chat_add_buddy( sb->chat, sb->who ); + imcb_chat_add_buddy( sb->chat, ic->acc->user ); /* And make sure the switchboard doesn't look like a regular chat anymore. */ if( sb->who ) @@ -195,12 +195,14 @@ void msn_sb_to_chat( struct msn_switchboard *sb ) g_free( sb->who ); sb->who = NULL; } + + return sb->chat; } void msn_sb_destroy( struct msn_switchboard *sb ) { - struct gaim_connection *gc = sb->gc; - struct msn_data *md = gc->proto_data; + struct im_connection *ic = sb->ic; + struct msn_data *md = ic->proto_data; debug( "Destroying switchboard: %s", sb->who ? sb->who : sb->key ? sb->key : "" ); @@ -219,7 +221,7 @@ void msn_sb_destroy( struct msn_switchboard *sb ) } g_slist_free( sb->msgq ); - serv_got_crap( gc, "Warning: Closing down MSN switchboard connection with " + imcb_log( ic, "Warning: Closing down MSN switchboard connection with " "unsent message to %s, you'll have to resend it.", sb->who ? sb->who : "(unknown)" ); } @@ -229,7 +231,7 @@ void msn_sb_destroy( struct msn_switchboard *sb ) if( sb->chat ) { - serv_got_chat_left( gc, sb->chat->id ); + imcb_chat_removed( sb->chat ); } if( sb->handler ) @@ -250,7 +252,7 @@ void msn_sb_destroy( struct msn_switchboard *sb ) gboolean msn_sb_connected( gpointer data, gint source, b_input_condition cond ) { struct msn_switchboard *sb = data; - struct gaim_connection *gc; + struct im_connection *ic; struct msn_data *md; char buf[1024]; @@ -258,8 +260,8 @@ gboolean msn_sb_connected( gpointer data, gint source, b_input_condition cond ) if( !g_slist_find( msn_switchboards, sb ) ) return FALSE; - gc = sb->gc; - md = gc->proto_data; + ic = sb->ic; + md = ic->proto_data; if( source != sb->fd ) { @@ -277,9 +279,9 @@ gboolean msn_sb_connected( gpointer data, gint source, b_input_condition cond ) sb->handler->exec_message = msn_sb_message; if( sb->session == MSN_SB_NEW ) - g_snprintf( buf, sizeof( buf ), "USR %d %s %s\r\n", ++sb->trId, gc->username, sb->key ); + g_snprintf( buf, sizeof( buf ), "USR %d %s %s\r\n", ++sb->trId, ic->acc->user, sb->key ); else - g_snprintf( buf, sizeof( buf ), "ANS %d %s %s %d\r\n", ++sb->trId, gc->username, sb->key, sb->session ); + g_snprintf( buf, sizeof( buf ), "ANS %d %s %s %d\r\n", ++sb->trId, ic->acc->user, sb->key, sb->session ); if( msn_sb_write( sb, buf, strlen( buf ) ) ) sb->inp = b_input_add( sb->fd, GAIM_INPUT_READ, msn_sb_callback, sb ); @@ -307,7 +309,7 @@ static gboolean msn_sb_callback( gpointer data, gint source, b_input_condition c static int msn_sb_command( gpointer data, char **cmd, int num_parts ) { struct msn_switchboard *sb = data; - struct gaim_connection *gc = sb->gc; + struct im_connection *ic = sb->ic; char buf[1024]; if( !num_parts ) @@ -318,8 +320,8 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts ) if( strcmp( cmd[0], "XFR" ) == 0 ) { - hide_login_progress_error( gc, "Received an XFR from a switchboard server, unable to comply! This is likely to be a bug, please report it!" ); - signoff( gc ); + imcb_error( ic, "Received an XFR from a switchboard server, unable to comply! This is likely to be a bug, please report it!" ); + imc_logout( ic, TRUE ); return( 0 ); } else if( strcmp( cmd[0], "USR" ) == 0 ) @@ -371,17 +373,17 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts ) if( num == 1 ) { g_snprintf( buf, sizeof( buf ), "MSN groupchat session %d", sb->session ); - sb->chat = serv_got_joined_chat( gc, ++msn_chat_id, buf ); + sb->chat = imcb_chat_new( ic, buf ); g_free( sb->who ); sb->who = NULL; } - add_chat_buddy( sb->chat, cmd[4] ); + imcb_chat_add_buddy( sb->chat, cmd[4] ); if( num == tot ) { - add_chat_buddy( sb->chat, gc->username ); + imcb_chat_add_buddy( sb->chat, ic->acc->user ); } } } @@ -459,11 +461,11 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts ) /* This SB is a one-to-one chat right now, but someone else is joining. */ msn_sb_to_chat( sb ); - add_chat_buddy( sb->chat, cmd[1] ); + imcb_chat_add_buddy( sb->chat, cmd[1] ); } else if( sb->chat ) { - add_chat_buddy( sb->chat, cmd[1] ); + imcb_chat_add_buddy( sb->chat, cmd[1] ); sb->ready = 1; } else @@ -513,7 +515,7 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts ) } else if( sb->chat ) { - remove_chat_buddy( sb->chat, cmd[1], "" ); + imcb_chat_remove_buddy( sb->chat, cmd[1], "" ); } else { @@ -525,8 +527,7 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts ) int num = atoi( cmd[0] ); const struct msn_status_code *err = msn_status_by_number( num ); - g_snprintf( buf, sizeof( buf ), "Error reported by switchboard server: %s", err->text ); - do_error_dialog( gc, buf, "MSN" ); + imcb_error( ic, "Error reported by switchboard server: %s", err->text ); if( err->flags & STATUS_SB_FATAL ) { @@ -535,7 +536,7 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts ) } else if( err->flags & STATUS_FATAL ) { - signoff( gc ); + imc_logout( ic, TRUE ); return 0; } else if( err->flags & STATUS_SB_IM_SPARE ) @@ -576,7 +577,7 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts ) static int msn_sb_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts ) { struct msn_switchboard *sb = data; - struct gaim_connection *gc = sb->gc; + struct im_connection *ic = sb->ic; char *body; int blen = 0; @@ -605,11 +606,11 @@ static int msn_sb_message( gpointer data, char *msg, int msglen, char **cmd, int if( sb->who ) { - serv_got_im( gc, cmd[1], body, 0, 0, blen ); + imcb_buddy_msg( ic, cmd[1], body, 0, 0 ); } else if( sb->chat ) { - serv_got_chat_in( gc, sb->chat->id, cmd[1], 0, body, 0 ); + imcb_chat_msg( sb->chat, cmd[1], body, 0, 0 ); } else { @@ -664,11 +665,11 @@ static int msn_sb_message( gpointer data, char *msg, int msglen, char **cmd, int if( sb->who ) { - serv_got_im( gc, cmd[1], buf, 0, 0, strlen( buf ) ); + imcb_buddy_msg( ic, cmd[1], buf, 0, 0 ); } else if( sb->chat ) { - serv_got_chat_in( gc, sb->chat->id, cmd[1], 0, buf, 0 ); + imcb_chat_msg( sb->chat, cmd[1], buf, 0, 0 ); } else { @@ -681,7 +682,7 @@ static int msn_sb_message( gpointer data, char *msg, int msglen, char **cmd, int if( who ) { - serv_got_typing( gc, who, 5, 1 ); + imcb_buddy_typing( ic, who, OPT_TYPING ); g_free( who ); } diff --git a/protocols/nogaim.c b/protocols/nogaim.c index 0270d5a0..a70d6eca 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -35,7 +35,7 @@ #include "nogaim.h" #include <ctype.h> -static int remove_chat_buddy_silent( struct conversation *b, char *handle ); +static int remove_chat_buddy_silent( struct groupchat *b, char *handle ); GSList *connections; @@ -114,25 +114,25 @@ struct prpl *find_protocol(const char *name) /* nogaim.c */ void nogaim_init() { - extern void msn_init(); - extern void oscar_init(); - extern void byahoo_init(); - extern void jabber_init(); + extern void msn_initmodule(); + extern void oscar_initmodule(); + extern void byahoo_initmodule(); + extern void jabber_initmodule(); #ifdef WITH_MSN - msn_init(); + msn_initmodule(); #endif #ifdef WITH_OSCAR - oscar_init(); + oscar_initmodule(); #endif #ifdef WITH_YAHOO - byahoo_init(); + byahoo_initmodule(); #endif #ifdef WITH_JABBER - jabber_init(); + jabber_initmodule(); #endif #ifdef WITH_PLUGINS @@ -144,59 +144,38 @@ GSList *get_connections() { return connections; } /* multi.c */ -struct gaim_connection *new_gaim_conn( account_t *acc ) +struct im_connection *imcb_new( account_t *acc ) { - struct gaim_connection *gc; + struct im_connection *ic; - gc = g_new0( struct gaim_connection, 1 ); + ic = g_new0( struct im_connection, 1 ); - /* Maybe we should get rid of this memory waste later. ;-) */ - g_snprintf( gc->username, sizeof( gc->username ), "%s", acc->user ); - g_snprintf( gc->password, sizeof( gc->password ), "%s", acc->pass ); + ic->irc = acc->irc; + ic->acc = acc; + acc->ic = ic; - gc->irc = acc->irc; - gc->acc = acc; - acc->gc = gc; + connections = g_slist_append( connections, ic ); - connections = g_slist_append( connections, gc ); - - return( gc ); + return( ic ); } -void destroy_gaim_conn( struct gaim_connection *gc ) +void imc_free( struct im_connection *ic ) { account_t *a; /* Destroy the pointer to this connection from the account list */ - for( a = gc->irc->accounts; a; a = a->next ) - if( a->gc == gc ) + for( a = ic->irc->accounts; a; a = a->next ) + if( a->ic == ic ) { - a->gc = NULL; + a->ic = NULL; break; } - connections = g_slist_remove( connections, gc ); - g_free( gc ); -} - -void set_login_progress( struct gaim_connection *gc, int step, char *msg ) -{ - serv_got_crap( gc, "Logging in: %s", msg ); + connections = g_slist_remove( connections, ic ); + g_free( ic ); } -/* Errors *while* logging in */ -void hide_login_progress( struct gaim_connection *gc, char *msg ) -{ - serv_got_crap( gc, "Login error: %s", msg ); -} - -/* Errors *after* logging in */ -void hide_login_progress_error( struct gaim_connection *gc, char *msg ) -{ - serv_got_crap( gc, "Logged out: %s", msg ); -} - -void serv_got_crap( struct gaim_connection *gc, char *format, ... ) +static void serv_got_crap( struct im_connection *ic, char *format, ... ) { va_list params; char *text; @@ -206,54 +185,88 @@ void serv_got_crap( struct gaim_connection *gc, char *format, ... ) text = g_strdup_vprintf( format, params ); va_end( params ); - if( ( g_strcasecmp( set_getstr( &gc->irc->set, "strip_html" ), "always" ) == 0 ) || - ( ( gc->flags & OPT_CONN_HTML ) && set_getbool( &gc->irc->set, "strip_html" ) ) ) + if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) || + ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) ) strip_html( text ); /* Try to find a different connection on the same protocol. */ - for( a = gc->irc->accounts; a; a = a->next ) - if( a->prpl == gc->acc->prpl && a->gc != gc ) + for( a = ic->irc->accounts; a; a = a->next ) + if( a->prpl == ic->acc->prpl && a->ic != ic ) break; /* If we found one, include the screenname in the message. */ if( a ) - irc_usermsg( gc->irc, "%s(%s) - %s", gc->acc->prpl->name, gc->username, text ); + irc_usermsg( ic->irc, "%s(%s) - %s", ic->acc->prpl->name, ic->acc->user, text ); else - irc_usermsg( gc->irc, "%s - %s", gc->acc->prpl->name, text ); + irc_usermsg( ic->irc, "%s - %s", ic->acc->prpl->name, text ); + + g_free( text ); +} + +void imcb_log( struct im_connection *ic, char *format, ... ) +{ + va_list params; + char *text; + + va_start( params, format ); + text = g_strdup_vprintf( format, params ); + va_end( params ); + + if( ic->flags & OPT_LOGGED_IN ) + serv_got_crap( ic, "%s", text ); + else + serv_got_crap( ic, "Logging in: %s", text ); + + g_free( text ); +} + +void imcb_error( struct im_connection *ic, char *format, ... ) +{ + va_list params; + char *text; + + va_start( params, format ); + text = g_strdup_vprintf( format, params ); + va_end( params ); + + if( ic->flags & OPT_LOGGED_IN ) + serv_got_crap( ic, "Error: %s", text ); + else + serv_got_crap( ic, "Couldn't log in: %s", text ); g_free( text ); } static gboolean send_keepalive( gpointer d, gint fd, b_input_condition cond ) { - struct gaim_connection *gc = d; + struct im_connection *ic = d; - if( gc->acc->prpl->keepalive ) - gc->acc->prpl->keepalive( gc ); + if( ic->acc->prpl->keepalive ) + ic->acc->prpl->keepalive( ic ); return TRUE; } -void account_online( struct gaim_connection *gc ) +void imcb_connected( struct im_connection *ic ) { user_t *u; /* MSN servers sometimes redirect you to a different server and do the whole login sequence again, so these "late" calls to this function should be handled correctly. (IOW, ignored) */ - if( gc->flags & OPT_LOGGED_IN ) + if( ic->flags & OPT_LOGGED_IN ) return; - u = user_find( gc->irc, gc->irc->nick ); + u = user_find( ic->irc, ic->irc->nick ); - serv_got_crap( gc, "Logged in" ); + imcb_log( ic, "Logged in" ); - gc->keepalive = b_timeout_add( 60000, send_keepalive, gc ); - gc->flags |= OPT_LOGGED_IN; + ic->keepalive = b_timeout_add( 60000, send_keepalive, ic ); + ic->flags |= OPT_LOGGED_IN; /* Also necessary when we're not away, at least for some of the protocols. */ - bim_set_away( gc, u->away ); + imc_set_away( ic, u->away ); } gboolean auto_reconnect( gpointer data, gint fd, b_input_condition cond ) @@ -268,29 +281,33 @@ gboolean auto_reconnect( gpointer data, gint fd, b_input_condition cond ) void cancel_auto_reconnect( account_t *a ) { - /* while( b_event_remove_by_data( (gpointer) a ) ); */ b_event_remove( a->reconnect ); a->reconnect = 0; } -void signoff( struct gaim_connection *gc ) +void imc_logout( struct im_connection *ic, int allow_reconnect ) { - irc_t *irc = gc->irc; + irc_t *irc = ic->irc; user_t *t, *u = irc->users; account_t *a; - serv_got_crap( gc, "Signing off.." ); + /* Nested calls might happen sometimes, this is probably the best + place to catch them. */ + if( ic->flags & OPT_LOGGING_OUT ) + return; + else + ic->flags |= OPT_LOGGING_OUT; - b_event_remove( gc->keepalive ); - gc->flags |= OPT_LOGGING_OUT; + imcb_log( ic, "Signing off.." ); - gc->keepalive = 0; - gc->acc->prpl->close( gc ); - b_event_remove( gc->inpa ); + b_event_remove( ic->keepalive ); + ic->keepalive = 0; + ic->acc->prpl->logout( ic ); + b_event_remove( ic->inpa ); while( u ) { - if( u->gc == gc ) + if( u->ic == ic ) { t = u->next; user_del( irc, u->nick ); @@ -300,94 +317,74 @@ void signoff( struct gaim_connection *gc ) u = u->next; } - query_del_by_gc( gc->irc, gc ); + query_del_by_conn( ic->irc, ic ); for( a = irc->accounts; a; a = a->next ) - if( a->gc == gc ) + if( a->ic == ic ) break; if( !a ) { /* Uhm... This is very sick. */ } - else if( !gc->wants_to_die && set_getbool( &irc->set, "auto_reconnect" ) && + else if( allow_reconnect && set_getbool( &irc->set, "auto_reconnect" ) && set_getbool( &a->set, "auto_reconnect" ) ) { int delay = set_getint( &irc->set, "auto_reconnect_delay" ); - serv_got_crap( gc, "Reconnecting in %d seconds..", delay ); + imcb_log( ic, "Reconnecting in %d seconds..", delay ); a->reconnect = b_timeout_add( delay * 1000, auto_reconnect, a ); } - destroy_gaim_conn( gc ); + imc_free( ic ); } /* dialogs.c */ -void do_error_dialog( struct gaim_connection *gc, char *msg, char *title ) +void imcb_ask( struct im_connection *ic, char *msg, void *data, void *doit, void *dont ) { - if( msg && title ) - serv_got_crap( gc, "Error: %s: %s", title, msg ); - else if( msg ) - serv_got_crap( gc, "Error: %s", msg ); - else if( title ) - serv_got_crap( gc, "Error: %s", title ); - else - serv_got_crap( gc, "Error" ); -} - -void do_ask_dialog( struct gaim_connection *gc, char *msg, void *data, void *doit, void *dont ) -{ - query_add( gc->irc, gc, msg, doit, dont, data ); + query_add( ic->irc, ic, msg, doit, dont, data ); } /* list.c */ -void add_buddy( struct gaim_connection *gc, char *group, char *handle, char *realname ) +void imcb_add_buddy( struct im_connection *ic, char *handle, char *group ) { user_t *u; - char nick[MAX_NICK_LENGTH+1]; - char *s; - irc_t *irc = gc->irc; + char nick[MAX_NICK_LENGTH+1], *s; + irc_t *irc = ic->irc; - if( set_getbool( &irc->set, "debug" ) && 0 ) /* This message is too useless */ - serv_got_crap( gc, "Receiving user add from handle: %s", handle ); - - if( user_findhandle( gc, handle ) ) + if( user_findhandle( ic, handle ) ) { if( set_getbool( &irc->set, "debug" ) ) - serv_got_crap( gc, "User already exists, ignoring add request: %s", handle ); + imcb_log( ic, "User already exists, ignoring add request: %s", handle ); return; - /* Buddy seems to exist already. Let's ignore this request then... */ + /* Buddy seems to exist already. Let's ignore this request then... + Eventually subsequent calls to this function *should* be possible + when a buddy is in multiple groups. But for now BitlBee doesn't + even support groups so let's silently ignore this for now. */ } memset( nick, 0, MAX_NICK_LENGTH + 1 ); - strcpy( nick, nick_get( gc->acc, handle, realname ) ); + strcpy( nick, nick_get( ic->acc, handle ) ); - u = user_add( gc->irc, nick ); + u = user_add( ic->irc, nick ); - if( !realname || !*realname ) realname = nick; - u->realname = g_strdup( realname ); +// if( !realname || !*realname ) realname = nick; +// u->realname = g_strdup( realname ); if( ( s = strchr( handle, '@' ) ) ) { u->host = g_strdup( s + 1 ); u->user = g_strndup( handle, s - handle ); } - else if( gc->acc->server ) + else if( ic->acc->server ) { - char *colon; - - if( ( colon = strchr( gc->acc->server, ':' ) ) ) - u->host = g_strndup( gc->acc->server, - colon - gc->acc->server ); - else - u->host = g_strdup( gc->acc->server ); - + u->host = g_strdup( ic->acc->server ); u->user = g_strdup( handle ); /* s/ /_/ ... important for AOL screennames */ @@ -397,47 +394,42 @@ void add_buddy( struct gaim_connection *gc, char *group, char *handle, char *rea } else { - u->host = g_strdup( gc->acc->prpl->name ); + u->host = g_strdup( ic->acc->prpl->name ); u->user = g_strdup( handle ); } - u->gc = gc; + u->ic = ic; u->handle = g_strdup( handle ); if( group ) u->group = g_strdup( group ); u->send_handler = buddy_send_handler; u->last_typing_notice = 0; } -struct buddy *find_buddy( struct gaim_connection *gc, char *handle ) +struct buddy *imcb_find_buddy( struct im_connection *ic, char *handle ) { static struct buddy b[1]; user_t *u; - u = user_findhandle( gc, handle ); + u = user_findhandle( ic, handle ); if( !u ) return( NULL ); - + memset( b, 0, sizeof( b ) ); strncpy( b->name, handle, 80 ); strncpy( b->show, u->realname, BUDDY_ALIAS_MAXLEN ); b->present = u->online; - b->gc = u->gc; + b->ic = u->ic; return( b ); } -void signoff_blocked( struct gaim_connection *gc ) +void imcb_rename_buddy( struct im_connection *ic, char *handle, char *realname ) { - return; /* Make all blocked users look invisible (TODO?) */ -} - - -void serv_buddy_rename( struct gaim_connection *gc, char *handle, char *realname ) -{ - user_t *u = user_findhandle( gc, handle ); + user_t *u = user_findhandle( ic, handle ); + char *s, newnick[MAX_NICK_LENGTH+1]; - if( !u ) return; + if( !u || !realname ) return; if( g_strcasecmp( u->realname, realname ) != 0 ) { @@ -445,8 +437,29 @@ void serv_buddy_rename( struct gaim_connection *gc, char *handle, char *realname u->realname = g_strdup( realname ); - if( ( gc->flags & OPT_LOGGED_IN ) && set_getbool( &gc->irc->set, "display_namechanges" ) ) - serv_got_crap( gc, "User `%s' changed name to `%s'", u->nick, u->realname ); + if( ( ic->flags & OPT_LOGGED_IN ) && set_getbool( &ic->irc->set, "display_namechanges" ) ) + imcb_log( ic, "User `%s' changed name to `%s'", u->nick, u->realname ); + + if( !u->online && !nick_saved( ic->acc, handle ) ) + { + /* Detect numeric handles: */ + for( s = u->user; isdigit( *s ); s++ ); + + if( *s == 0 ) + { + /* If we reached the end of the string, it only contained numbers. + Seems to be an ICQ# then, so hopefully realname contains + something more useful. */ + strcpy( newnick, realname ); + + /* Some processing to make sure this string is a valid IRC nickname. */ + nick_strip( newnick ); + if( set_getbool( &ic->irc->set, "lcnicks" ) ) + nick_lc( newnick ); + + u->nick = g_strdup( newnick ); + } + } } } @@ -455,7 +468,7 @@ void serv_buddy_rename( struct gaim_connection *gc, char *handle, char *realname struct show_got_added_data { - struct gaim_connection *gc; + struct im_connection *ic; char *handle; }; @@ -467,57 +480,56 @@ void show_got_added_no( gpointer w, struct show_got_added_data *data ) void show_got_added_yes( gpointer w, struct show_got_added_data *data ) { - data->gc->acc->prpl->add_buddy( data->gc, data->handle ); - add_buddy( data->gc, NULL, data->handle, data->handle ); + data->ic->acc->prpl->add_buddy( data->ic, data->handle, NULL ); + /* imcb_add_buddy( data->ic, NULL, data->handle, data->handle ); */ return show_got_added_no( w, data ); } -void show_got_added( struct gaim_connection *gc, char *handle, const char *realname ) +void imcb_ask_add( struct im_connection *ic, char *handle, const char *realname ) { struct show_got_added_data *data = g_new0( struct show_got_added_data, 1 ); char *s; /* TODO: Make a setting for this! */ - if( user_findhandle( gc, handle ) != NULL ) + if( user_findhandle( ic, handle ) != NULL ) return; s = g_strdup_printf( "The user %s is not in your buddy list yet. Do you want to add him/her now?", handle ); - data->gc = gc; + data->ic = ic; data->handle = g_strdup( handle ); - query_add( gc->irc, gc, s, show_got_added_yes, show_got_added_no, data ); + query_add( ic->irc, ic, s, show_got_added_yes, show_got_added_no, data ); } /* server.c */ -void serv_got_update( struct gaim_connection *gc, char *handle, int loggedin, int evil, time_t signon, time_t idle, int type, guint caps ) +void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, const char *state, const char *message ) { user_t *u; int oa, oo; - u = user_findhandle( gc, handle ); + u = user_findhandle( ic, (char*) handle ); if( !u ) { - if( g_strcasecmp( set_getstr( &gc->irc->set, "handle_unknown" ), "add" ) == 0 ) + if( g_strcasecmp( set_getstr( &ic->irc->set, "handle_unknown" ), "add" ) == 0 ) { - add_buddy( gc, NULL, handle, NULL ); - u = user_findhandle( gc, handle ); + imcb_add_buddy( ic, (char*) handle, NULL ); + u = user_findhandle( ic, (char*) handle ); } else { - if( set_getbool( &gc->irc->set, "debug" ) || g_strcasecmp( set_getstr( &gc->irc->set, "handle_unknown" ), "ignore" ) != 0 ) + if( set_getbool( &ic->irc->set, "debug" ) || g_strcasecmp( set_getstr( &ic->irc->set, "handle_unknown" ), "ignore" ) != 0 ) { - serv_got_crap( gc, "serv_got_update() for handle %s:", handle ); - serv_got_crap( gc, "loggedin = %d, type = %d", loggedin, type ); + imcb_log( ic, "imcb_buddy_status() for unknown handle %s:", handle ); + imcb_log( ic, "flags = %d, state = %s, message = %s", flags, + state ? state : "NULL", message ? message : "NULL" ); } return; } - /* Why did we have this here.... - return; */ } oa = u->away != NULL; @@ -529,60 +541,61 @@ void serv_got_update( struct gaim_connection *gc, char *handle, int loggedin, in u->away = NULL; } - if( loggedin && !u->online ) + if( ( flags & OPT_LOGGED_IN ) && !u->online ) { - irc_spawn( gc->irc, u ); + irc_spawn( ic->irc, u ); u->online = 1; } - else if( !loggedin && u->online ) + else if( !( flags & OPT_LOGGED_IN ) && u->online ) { - struct conversation *c; + struct groupchat *c; - irc_kill( gc->irc, u ); + irc_kill( ic->irc, u ); u->online = 0; /* Remove him/her from the conversations to prevent PART messages after he/she QUIT already */ - for( c = gc->conversations; c; c = c->next ) - remove_chat_buddy_silent( c, handle ); + for( c = ic->conversations; c; c = c->next ) + remove_chat_buddy_silent( c, (char*) handle ); } - if( ( type & UC_UNAVAILABLE ) && ( strcmp( gc->acc->prpl->name, "oscar" ) == 0 || strcmp( gc->acc->prpl->name, "icq" ) == 0 ) ) - { - u->away = g_strdup( "Away" ); - } - else if( ( type & UC_UNAVAILABLE ) && ( strcmp( gc->acc->prpl->name, "jabber" ) == 0 ) ) + if( flags & OPT_AWAY ) { - if( type & UC_DND ) - u->away = g_strdup( "Do Not Disturb" ); - else if( type & UC_XA ) - u->away = g_strdup( "Extended Away" ); - else // if( type & UC_AWAY ) + if( state && message ) + { + u->away = g_strdup_printf( "%s (%s)", state, message ); + } + else if( state ) + { + u->away = g_strdup( state ); + } + else if( message ) + { + u->away = g_strdup( message ); + } + else + { u->away = g_strdup( "Away" ); + } } - else if( ( type & UC_UNAVAILABLE ) && gc->acc->prpl->get_status_string ) - { - u->away = g_strdup( gc->acc->prpl->get_status_string( gc, type ) ); - } - else - u->away = NULL; + /* else waste_any_state_information_for_now(); */ /* LISPy... */ - if( ( set_getbool( &gc->irc->set, "away_devoice" ) ) && /* Don't do a thing when user doesn't want it */ + if( ( set_getbool( &ic->irc->set, "away_devoice" ) ) && /* Don't do a thing when user doesn't want it */ ( u->online ) && /* Don't touch offline people */ ( ( ( u->online != oo ) && !u->away ) || /* Voice joining people */ ( ( u->online == oo ) && ( oa == !u->away ) ) ) ) /* (De)voice people changing state */ { - irc_write( gc->irc, ":%s MODE %s %cv %s", gc->irc->myhost, - gc->irc->channel, u->away?'-':'+', u->nick ); + irc_write( ic->irc, ":%s MODE %s %cv %s", ic->irc->myhost, + ic->irc->channel, u->away?'-':'+', u->nick ); } } -void serv_got_im( struct gaim_connection *gc, char *handle, char *msg, guint32 flags, time_t mtime, gint len ) +void imcb_buddy_msg( struct im_connection *ic, char *handle, char *msg, u_int32_t flags, time_t sent_at ) { - irc_t *irc = gc->irc; + irc_t *irc = ic->irc; user_t *u; - u = user_findhandle( gc, handle ); + u = user_findhandle( ic, handle ); if( !u ) { @@ -591,7 +604,7 @@ void serv_got_im( struct gaim_connection *gc, char *handle, char *msg, guint32 f if( g_strcasecmp( h, "ignore" ) == 0 ) { if( set_getbool( &irc->set, "debug" ) ) - serv_got_crap( gc, "Ignoring message from unknown handle %s", handle ); + imcb_log( ic, "Ignoring message from unknown handle %s", handle ); return; } @@ -607,19 +620,19 @@ void serv_got_im( struct gaim_connection *gc, char *handle, char *msg, guint32 f private = 0; } - add_buddy( gc, NULL, handle, NULL ); - u = user_findhandle( gc, handle ); + imcb_add_buddy( ic, handle, NULL ); + u = user_findhandle( ic, handle ); u->is_private = private; } else { - serv_got_crap( gc, "Message from unknown handle %s:", handle ); + imcb_log( ic, "Message from unknown handle %s:", handle ); u = user_find( irc, irc->mynick ); } } - if( ( g_strcasecmp( set_getstr( &gc->irc->set, "strip_html" ), "always" ) == 0 ) || - ( ( gc->flags & OPT_CONN_HTML ) && set_getbool( &gc->irc->set, "strip_html" ) ) ) + if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) || + ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) ) strip_html( msg ); while( strlen( msg ) > 425 ) @@ -655,36 +668,30 @@ void serv_got_im( struct gaim_connection *gc, char *handle, char *msg, guint32 f irc_msgfrom( irc, u->nick, msg ); } -void serv_got_typing( struct gaim_connection *gc, char *handle, int timeout, int type ) +void imcb_buddy_typing( struct im_connection *ic, char *handle, u_int32_t flags ) { user_t *u; - if( !set_getbool( &gc->irc->set, "typing_notice" ) ) + if( !set_getbool( &ic->irc->set, "typing_notice" ) ) return; - if( ( u = user_findhandle( gc, handle ) ) ) { - /* If type is: - * 0: user has stopped typing - * 1: user is actively typing - * 2: user has entered text, but is not actively typing - */ - if (type == 0 || type == 1 || type == 2) { - char buf[256]; - g_snprintf(buf, 256, "\1TYPING %d\1", type); - irc_privmsg( gc->irc, u, "PRIVMSG", gc->irc->nick, NULL, buf ); - } + if( ( u = user_findhandle( ic, handle ) ) ) + { + char buf[256]; + + g_snprintf( buf, 256, "\1TYPING %d\1", ( flags >> 8 ) & 3 ); + irc_privmsg( ic->irc, u, "PRIVMSG", ic->irc->nick, NULL, buf ); } } -void serv_got_chat_left( struct gaim_connection *gc, int id ) +void imcb_chat_removed( struct groupchat *c ) { - struct conversation *c, *l = NULL; + struct im_connection *ic = c->ic; + struct groupchat *l = NULL; GList *ir; - if( set_getbool( &gc->irc->set, "debug" ) ) - serv_got_crap( gc, "You were removed from conversation %d", (int) id ); - - for( c = gc->conversations; c && c->id != id; c = (l=c)->next ); + if( set_getbool( &ic->irc->set, "debug" ) ) + imcb_log( ic, "You were removed from conversation 0x%x", (int) c ); if( c ) { @@ -692,18 +699,18 @@ void serv_got_chat_left( struct gaim_connection *gc, int id ) { user_t *u, *r; - r = user_find( gc->irc, gc->irc->mynick ); - irc_privmsg( gc->irc, r, "PRIVMSG", c->channel, "", "Cleaning up channel, bye!" ); + r = user_find( ic->irc, ic->irc->mynick ); + irc_privmsg( ic->irc, r, "PRIVMSG", c->channel, "", "Cleaning up channel, bye!" ); - u = user_find( gc->irc, gc->irc->nick ); - irc_kick( gc->irc, u, c->channel, r ); - /* irc_part( gc->irc, u, c->channel ); */ + u = user_find( ic->irc, ic->irc->nick ); + irc_kick( ic->irc, u, c->channel, r ); + /* irc_part( ic->irc, u, c->channel ); */ } if( l ) l->next = c->next; else - gc->conversations = c->next; + ic->conversations = c->next; for( ir = c->in_room; ir; ir = ir->next ) g_free( ir->data ); @@ -714,75 +721,68 @@ void serv_got_chat_left( struct gaim_connection *gc, int id ) } } -void serv_got_chat_in( struct gaim_connection *gc, int id, char *who, int whisper, char *msg, time_t mtime ) +void imcb_chat_msg( struct groupchat *c, char *who, char *msg, u_int32_t flags, time_t sent_at ) { - struct conversation *c; + struct im_connection *ic = c->ic; user_t *u; /* Gaim sends own messages through this too. IRC doesn't want this, so kill them */ - if( g_strcasecmp( who, gc->username ) == 0 ) + if( g_strcasecmp( who, ic->acc->user ) == 0 ) return; - u = user_findhandle( gc, who ); - for( c = gc->conversations; c && c->id != id; c = c->next ); + u = user_findhandle( ic, who ); - if( ( g_strcasecmp( set_getstr( &gc->irc->set, "strip_html" ), "always" ) == 0 ) || - ( ( gc->flags & OPT_CONN_HTML ) && set_getbool( &gc->irc->set, "strip_html" ) ) ) + if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) || + ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) ) strip_html( msg ); if( c && u ) - irc_privmsg( gc->irc, u, "PRIVMSG", c->channel, "", msg ); + irc_privmsg( ic->irc, u, "PRIVMSG", c->channel, "", msg ); else - serv_got_crap( gc, "Message from/to conversation %s@%d (unknown conv/user): %s", who, id, msg ); + imcb_log( ic, "Message from/to conversation %s@0x%x (unknown conv/user): %s", who, (int) c, msg ); } -struct conversation *serv_got_joined_chat( struct gaim_connection *gc, int id, char *handle ) +struct groupchat *imcb_chat_new( struct im_connection *ic, char *handle ) { - struct conversation *c; - char *s; + struct groupchat *c; /* This one just creates the conversation structure, user won't see anything yet */ - if( gc->conversations ) + if( ic->conversations ) { - for( c = gc->conversations; c->next; c = c->next ); - c = c->next = g_new0( struct conversation, 1 ); + for( c = ic->conversations; c->next; c = c->next ); + c = c->next = g_new0( struct groupchat, 1 ); } else - gc->conversations = c = g_new0( struct conversation, 1); + ic->conversations = c = g_new0( struct groupchat, 1 ); - c->id = id; - c->gc = gc; + c->ic = ic; c->title = g_strdup( handle ); + c->channel = g_strdup_printf( "&chat_%03d", ic->irc->c_id++ ); - s = g_new( char, 16 ); - sprintf( s, "&chat_%03d", gc->irc->c_id++ ); - c->channel = g_strdup( s ); - g_free( s ); + if( set_getbool( &ic->irc->set, "debug" ) ) + imcb_log( ic, "Creating new conversation: (id=0x%x,handle=%s)", (int) c, handle ); - if( set_getbool( &gc->irc->set, "debug" ) ) - serv_got_crap( gc, "Creating new conversation: (id=%d,handle=%s)", id, handle ); - - return( c ); + return c; } /* buddy_chat.c */ -void add_chat_buddy( struct conversation *b, char *handle ) +void imcb_chat_add_buddy( struct groupchat *b, char *handle ) { - user_t *u = user_findhandle( b->gc, handle ); + user_t *u = user_findhandle( b->ic, handle ); int me = 0; - if( set_getbool( &b->gc->irc->set, "debug" ) ) - serv_got_crap( b->gc, "User %s added to conversation %d", handle, b->id ); + if( set_getbool( &b->ic->irc->set, "debug" ) ) + imcb_log( b->ic, "User %s added to conversation 0x%x", handle, (int) b ); /* It might be yourself! */ - if( b->gc->acc->prpl->handle_cmp( handle, b->gc->username ) == 0 ) + if( b->ic->acc->prpl->handle_cmp( handle, b->ic->acc->user ) == 0 ) { - u = user_find( b->gc->irc, b->gc->irc->nick ); + u = user_find( b->ic->irc, b->ic->irc->nick ); if( !b->joined ) - irc_join( b->gc->irc, u, b->channel ); + irc_join( b->ic->irc, u, b->channel ); b->joined = me = 1; } @@ -790,45 +790,45 @@ void add_chat_buddy( struct conversation *b, char *handle ) your contact list. Try to handle that here */ if( !u ) { - add_buddy( b->gc, NULL, handle, NULL ); - u = user_findhandle( b->gc, handle ); + imcb_add_buddy( b->ic, handle, NULL ); + u = user_findhandle( b->ic, handle ); } /* Add the handle to the room userlist, if it's not 'me' */ if( !me ) { if( b->joined ) - irc_join( b->gc->irc, u, b->channel ); + irc_join( b->ic->irc, u, b->channel ); b->in_room = g_list_append( b->in_room, g_strdup( handle ) ); } } -void remove_chat_buddy( struct conversation *b, char *handle, char *reason ) +void imcb_chat_remove_buddy( struct groupchat *b, char *handle, char *reason ) { user_t *u; int me = 0; - if( set_getbool( &b->gc->irc->set, "debug" ) ) - serv_got_crap( b->gc, "User %s removed from conversation %d (%s)", handle, b->id, reason ? reason : "" ); + if( set_getbool( &b->ic->irc->set, "debug" ) ) + imcb_log( b->ic, "User %s removed from conversation 0x%x (%s)", handle, (int) b, reason ? reason : "" ); /* It might be yourself! */ - if( g_strcasecmp( handle, b->gc->username ) == 0 ) + if( g_strcasecmp( handle, b->ic->acc->user ) == 0 ) { - u = user_find( b->gc->irc, b->gc->irc->nick ); + u = user_find( b->ic->irc, b->ic->irc->nick ); b->joined = 0; me = 1; } else { - u = user_findhandle( b->gc, handle ); + u = user_findhandle( b->ic, handle ); } if( remove_chat_buddy_silent( b, handle ) ) if( ( b->joined || me ) && u ) - irc_part( b->gc->irc, u, b->channel ); + irc_part( b->ic->irc, u, b->channel ); } -static int remove_chat_buddy_silent( struct conversation *b, char *handle ) +static int remove_chat_buddy_silent( struct groupchat *b, char *handle ) { GList *i; @@ -852,22 +852,22 @@ static int remove_chat_buddy_silent( struct conversation *b, char *handle ) /* Misc. BitlBee stuff which shouldn't really be here */ -struct conversation *conv_findchannel( char *channel ) +struct groupchat *chat_by_channel( char *channel ) { - struct gaim_connection *gc; - struct conversation *c; + struct im_connection *ic; + struct groupchat *c; GSList *l; /* This finds the connection which has a conversation which belongs to this channel */ for( l = connections; l; l = l->next ) { - gc = l->data; - for( c = gc->conversations; c && g_strcasecmp( c->channel, channel ) != 0; c = c->next ); + ic = l->data; + for( c = ic->conversations; c && g_strcasecmp( c->channel, channel ) != 0; c = c->next ); if( c ) - return( c ); + return c; } - return( NULL ); + return NULL; } char *set_eval_away_devoice( set_t *set, char *value ) @@ -901,7 +901,7 @@ char *set_eval_away_devoice( set_t *set, char *value ) while( u ) { - if( u->gc && u->online && !u->away ) + if( u->ic && u->online && !u->away ) { if( ( strlen( list ) + strlen( u->nick ) ) >= 79 ) { @@ -935,49 +935,48 @@ char *set_eval_away_devoice( set_t *set, char *value ) /* The plan is to not allow straight calls to prpl functions anymore, but do them all from some wrappers. We'll start to define some down here: */ -int bim_buddy_msg( struct gaim_connection *gc, char *handle, char *msg, int flags ) +int imc_buddy_msg( struct im_connection *ic, char *handle, char *msg, int flags ) { char *buf = NULL; int st; - if( ( gc->flags & OPT_CONN_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) ) + if( ( ic->flags & OPT_DOES_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) ) { buf = escape_html( msg ); msg = buf; } - st = gc->acc->prpl->send_im( gc, handle, msg, strlen( msg ), flags ); + st = ic->acc->prpl->buddy_msg( ic, handle, msg, flags ); g_free( buf ); return st; } -int bim_chat_msg( struct gaim_connection *gc, int id, char *msg ) +int imc_chat_msg( struct groupchat *c, char *msg, int flags ) { char *buf = NULL; - int st; - if( ( gc->flags & OPT_CONN_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) ) + if( ( c->ic->flags & OPT_DOES_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) ) { buf = escape_html( msg ); msg = buf; } - st = gc->acc->prpl->chat_send( gc, id, msg ); + c->ic->acc->prpl->chat_msg( c, msg, flags ); g_free( buf ); - return st; + return 1; } -static char *bim_away_alias_find( GList *gcm, char *away ); +static char *imc_away_alias_find( GList *gcm, char *away ); -int bim_set_away( struct gaim_connection *gc, char *away ) +int imc_set_away( struct im_connection *ic, char *away ) { GList *m, *ms; char *s; if( !away ) away = ""; - ms = m = gc->acc->prpl->away_states( gc ); + ms = m = ic->acc->prpl->away_states( ic ); while( m ) { @@ -998,27 +997,25 @@ int bim_set_away( struct gaim_connection *gc, char *away ) if( m ) { - gc->acc->prpl->set_away( gc, m->data, *away ? away : NULL ); + ic->acc->prpl->set_away( ic, m->data, *away ? away : NULL ); } else { - s = bim_away_alias_find( ms, away ); + s = imc_away_alias_find( ms, away ); if( s ) { - gc->acc->prpl->set_away( gc, s, away ); - if( set_getbool( &gc->irc->set, "debug" ) ) - serv_got_crap( gc, "Setting away state to %s", s ); + ic->acc->prpl->set_away( ic, s, away ); + if( set_getbool( &ic->irc->set, "debug" ) ) + imcb_log( ic, "Setting away state to %s", s ); } else - gc->acc->prpl->set_away( gc, GAIM_AWAY_CUSTOM, away ); + ic->acc->prpl->set_away( ic, GAIM_AWAY_CUSTOM, away ); } - g_list_free( ms ); - return( 1 ); } -static char *bim_away_alias_list[8][5] = +static char *imc_away_alias_list[8][5] = { { "Away from computer", "Away", "Extended away", NULL }, { "NA", "N/A", "Not available", NULL }, @@ -1030,28 +1027,28 @@ static char *bim_away_alias_list[8][5] = { NULL } }; -static char *bim_away_alias_find( GList *gcm, char *away ) +static char *imc_away_alias_find( GList *gcm, char *away ) { GList *m; int i, j; - for( i = 0; *bim_away_alias_list[i]; i ++ ) + for( i = 0; *imc_away_alias_list[i]; i ++ ) { - for( j = 0; bim_away_alias_list[i][j]; j ++ ) - if( g_strncasecmp( away, bim_away_alias_list[i][j], strlen( bim_away_alias_list[i][j] ) ) == 0 ) + for( j = 0; imc_away_alias_list[i][j]; j ++ ) + if( g_strncasecmp( away, imc_away_alias_list[i][j], strlen( imc_away_alias_list[i][j] ) ) == 0 ) break; - if( !bim_away_alias_list[i][j] ) /* If we reach the end, this row */ + if( !imc_away_alias_list[i][j] ) /* If we reach the end, this row */ continue; /* is not what we want. Next! */ /* Now find an entry in this row which exists in gcm */ - for( j = 0; bim_away_alias_list[i][j]; j ++ ) + for( j = 0; imc_away_alias_list[i][j]; j ++ ) { m = gcm; while( m ) { - if( g_strcasecmp( bim_away_alias_list[i][j], m->data ) == 0 ) - return( bim_away_alias_list[i][j] ); + if( g_strcasecmp( imc_away_alias_list[i][j], m->data ) == 0 ) + return( imc_away_alias_list[i][j] ); m = m->next; } } @@ -1060,48 +1057,48 @@ static char *bim_away_alias_find( GList *gcm, char *away ) return( NULL ); } -void bim_add_allow( struct gaim_connection *gc, char *handle ) +void imc_add_allow( struct im_connection *ic, char *handle ) { - if( g_slist_find_custom( gc->permit, handle, (GCompareFunc) gc->acc->prpl->handle_cmp ) == NULL ) + if( g_slist_find_custom( ic->permit, handle, (GCompareFunc) ic->acc->prpl->handle_cmp ) == NULL ) { - gc->permit = g_slist_prepend( gc->permit, g_strdup( handle ) ); + ic->permit = g_slist_prepend( ic->permit, g_strdup( handle ) ); } - gc->acc->prpl->add_permit( gc, handle ); + ic->acc->prpl->add_permit( ic, handle ); } -void bim_rem_allow( struct gaim_connection *gc, char *handle ) +void imc_rem_allow( struct im_connection *ic, char *handle ) { GSList *l; - if( ( l = g_slist_find_custom( gc->permit, handle, (GCompareFunc) gc->acc->prpl->handle_cmp ) ) ) + if( ( l = g_slist_find_custom( ic->permit, handle, (GCompareFunc) ic->acc->prpl->handle_cmp ) ) ) { g_free( l->data ); - gc->permit = g_slist_delete_link( gc->permit, l ); + ic->permit = g_slist_delete_link( ic->permit, l ); } - gc->acc->prpl->rem_permit( gc, handle ); + ic->acc->prpl->rem_permit( ic, handle ); } -void bim_add_block( struct gaim_connection *gc, char *handle ) +void imc_add_block( struct im_connection *ic, char *handle ) { - if( g_slist_find_custom( gc->deny, handle, (GCompareFunc) gc->acc->prpl->handle_cmp ) == NULL ) + if( g_slist_find_custom( ic->deny, handle, (GCompareFunc) ic->acc->prpl->handle_cmp ) == NULL ) { - gc->deny = g_slist_prepend( gc->deny, g_strdup( handle ) ); + ic->deny = g_slist_prepend( ic->deny, g_strdup( handle ) ); } - gc->acc->prpl->add_deny( gc, handle ); + ic->acc->prpl->add_deny( ic, handle ); } -void bim_rem_block( struct gaim_connection *gc, char *handle ) +void imc_rem_block( struct im_connection *ic, char *handle ) { GSList *l; - if( ( l = g_slist_find_custom( gc->deny, handle, (GCompareFunc) gc->acc->prpl->handle_cmp ) ) ) + if( ( l = g_slist_find_custom( ic->deny, handle, (GCompareFunc) ic->acc->prpl->handle_cmp ) ) ) { g_free( l->data ); - gc->deny = g_slist_delete_link( gc->deny, l ); + ic->deny = g_slist_delete_link( ic->deny, l ); } - gc->acc->prpl->rem_deny( gc, handle ); + ic->acc->prpl->rem_deny( ic, handle ); } diff --git a/protocols/nogaim.h b/protocols/nogaim.h index bae4489f..59f9e870 100644 --- a/protocols/nogaim.h +++ b/protocols/nogaim.h @@ -5,7 +5,8 @@ \********************************************************************/ /* - * nogaim + * nogaim, soon to be known as im_api. Not a separate product (unless + * someone would be interested in such a thing), just a new name. * * Gaim without gaim - for BitlBee * @@ -14,7 +15,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 <wilmer@gaast.net> + * Copyright 2002-2007 Wilmer van der Gaast <wilmer@gaast.net> */ /* @@ -43,28 +44,30 @@ #include "md5.h" #include "sha.h" - #define BUF_LEN MSG_LEN #define BUF_LONG ( BUF_LEN * 2 ) #define MSG_LEN 2048 #define BUF_LEN MSG_LEN -#define SELF_ALIAS_LEN 400 #define BUDDY_ALIAS_MAXLEN 388 /* because MSN names can be 387 characters */ #define WEBSITE "http://www.bitlbee.org/" -#define IM_FLAG_AWAY 0x0020 #define GAIM_AWAY_CUSTOM "Custom" -#define OPT_CONN_HTML 0x00000001 -#define OPT_LOGGED_IN 0x00010000 -#define OPT_LOGGING_OUT 0x00020000 +/* Sharing flags between all kinds of things. I just hope I won't hit any + limits before 32-bit machines become extinct. ;-) */ +#define OPT_LOGGED_IN 0x00000001 +#define OPT_LOGGING_OUT 0x00000002 +#define OPT_AWAY 0x00000004 +#define OPT_DOES_HTML 0x00000010 +#define OPT_TYPING 0x00000100 /* Some pieces of code make assumptions */ +#define OPT_THINKING 0x00000200 /* about these values... Stupid me! */ /* ok. now the fun begins. first we create a connection structure */ -struct gaim_connection +struct im_connection { account_t *acc; - guint32 flags; + u_int32_t flags; /* each connection then can have its own protocol-specific data */ void *proto_data; @@ -79,159 +82,147 @@ struct gaim_connection GSList *deny; int permdeny; - char username[64]; char displayname[128]; - char password[32]; - char *away; int evil; - gboolean wants_to_die; /* defaults to FALSE */ /* BitlBee */ irc_t *irc; - struct conversation *conversations; + struct groupchat *conversations; }; -/* struct buddy_chat went away and got merged with this. */ -struct conversation { - struct gaim_connection *gc; +struct groupchat { + struct im_connection *ic; /* stuff used just for chat */ - GList *in_room; - GList *ignored; - int id; - - /* BitlBee */ - struct conversation *next; - char *channel; - char *title; - char joined; - void *data; + GList *in_room; + GList *ignored; + + /* BitlBee */ + struct groupchat *next; + char *channel; + char *title; + char joined; + void *data; }; struct buddy { char name[80]; char show[BUDDY_ALIAS_MAXLEN]; - int present; + int present; int evil; time_t signon; time_t idle; - int uc; + int uc; guint caps; /* woohoo! */ void *proto_data; /* what a hack */ - struct gaim_connection *gc; /* the connection it belongs to */ + struct im_connection *ic; /* the connection it belongs to */ }; struct prpl { int options; const char *name; - void (* acc_init) (account_t *); + /* Added this one to be able to add per-account settings, don't think + it should be used for anything else. */ + void (* init) (account_t *); + /* These should all be pretty obvious. */ void (* login) (account_t *); - void (* keepalive) (struct gaim_connection *); - void (* close) (struct gaim_connection *); + void (* keepalive) (struct im_connection *); + void (* logout) (struct im_connection *); - int (* send_im) (struct gaim_connection *, char *who, char *message, int len, int away); - void (* set_away) (struct gaim_connection *, char *state, char *message); - void (* get_away) (struct gaim_connection *, char *who); - int (* send_typing) (struct gaim_connection *, char *who, int typing); + int (* buddy_msg) (struct im_connection *, char *to, char *message, int flags); + void (* set_away) (struct im_connection *, char *state, char *message); + void (* get_away) (struct im_connection *, char *who); + int (* send_typing) (struct im_connection *, char *who, int flags); - 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 *); + /* For now BitlBee doesn't really handle groups, just set it to NULL. */ + void (* add_buddy) (struct im_connection *, char *name, char *group); + void (* remove_buddy) (struct im_connection *, char *name, char *group); - 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 */ + /* Block list stuff. */ + void (* add_permit) (struct im_connection *, char *who); + void (* add_deny) (struct im_connection *, char *who); + void (* rem_permit) (struct im_connection *, char *who); + void (* rem_deny) (struct im_connection *, char *who); + /* Doesn't actually have UI hooks. */ + void (* set_permit_deny)(struct im_connection *); - /* 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); - int (* chat_send) (struct gaim_connection *, int id, char *message); - int (* chat_open) (struct gaim_connection *, char *who); + /* Request profile info. Free-formatted stuff, the IM module gives back + this info via imcb_log(). */ + void (* get_info) (struct im_connection *, char *who); + void (* set_my_name) (struct im_connection *, char *name); + void (* set_name) (struct im_connection *, char *who, char *name); - /* DIE! */ - char *(* get_status_string) (struct gaim_connection *gc, int stat); + /* Group chat stuff. */ + void (* chat_invite) (struct groupchat *, char *who, char *message); + void (* chat_leave) (struct groupchat *); + void (* chat_msg) (struct groupchat *, char *message, int flags); + struct groupchat * + (* chat_with) (struct im_connection *, char *who); + struct groupchat * + (* chat_join) (struct im_connection *, char *room, char *nick, char *password); - GList *(* away_states)(struct gaim_connection *gc); + GList *(* away_states)(struct im_connection *ic); /* Mainly for AOL, since they think "Bung hole" == "Bu ngho le". *sigh* */ int (* handle_cmp) (const char *who1, const char *who2); }; -#define UC_UNAVAILABLE 1 - -/* JABBER */ -#define UC_AWAY (0x02 | UC_UNAVAILABLE) -#define UC_CHAT 0x04 -#define UC_XA (0x08 | UC_UNAVAILABLE) -#define UC_DND (0x10 | UC_UNAVAILABLE) - -G_MODULE_EXPORT GSList *get_connections(); -G_MODULE_EXPORT struct prpl *find_protocol(const char *name); -G_MODULE_EXPORT void register_protocol(struct prpl *); - -/* nogaim.c */ -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 ); - -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 ); - +/* im_api core stuff. */ void nogaim_init(); +G_MODULE_EXPORT GSList *get_connections(); +G_MODULE_EXPORT struct prpl *find_protocol( const char *name ); +G_MODULE_EXPORT void register_protocol( struct prpl * ); + +/* Connection management. */ +G_MODULE_EXPORT struct im_connection *imcb_new( account_t *acc ); +G_MODULE_EXPORT void imcb_free( struct im_connection *ic ); +G_MODULE_EXPORT void imcb_connected( struct im_connection *ic ); +G_MODULE_EXPORT void imc_logout( struct im_connection *ic, int allow_reconnect ); + +/* Communicating with the user. */ +G_MODULE_EXPORT void imcb_log( struct im_connection *ic, char *format, ... ) G_GNUC_PRINTF( 2, 3 ); +G_MODULE_EXPORT void imcb_error( struct im_connection *ic, char *format, ... ) G_GNUC_PRINTF( 2, 3 ); +G_MODULE_EXPORT void imcb_ask( struct im_connection *ic, char *msg, void *data, void *doit, void *dont ); +G_MODULE_EXPORT void imcb_ask_add( struct im_connection *ic, char *handle, const char *realname ); + +/* Buddy management */ +G_MODULE_EXPORT void imcb_add_buddy( struct im_connection *ic, char *handle, char *group ); +G_MODULE_EXPORT void imcb_remove_buddy( struct im_connection *ic, char *handle, char *group ); +G_MODULE_EXPORT struct buddy *imcb_find_buddy( struct im_connection *ic, char *handle ); +G_MODULE_EXPORT void imcb_rename_buddy( struct im_connection *ic, char *handle, char *realname ); + +/* Buddy activity */ +G_MODULE_EXPORT void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, const char *state, const char *message ); +/* Not implemented yet! */ G_MODULE_EXPORT void imcb_buddy_times( struct im_connection *ic, const char *handle, time_t login, time_t idle ); +G_MODULE_EXPORT void imcb_buddy_msg( struct im_connection *ic, char *handle, char *msg, u_int32_t flags, time_t sent_at ); +G_MODULE_EXPORT void imcb_buddy_typing( struct im_connection *ic, char *handle, u_int32_t flags ); + +/* Groupchats */ +G_MODULE_EXPORT void imcb_chat_invited( struct im_connection *ic, char *handle, char *who, char *msg, GList *data ); +G_MODULE_EXPORT struct groupchat *imcb_chat_new( struct im_connection *ic, char *handle ); +G_MODULE_EXPORT void imcb_chat_add_buddy( struct groupchat *b, char *handle ); +G_MODULE_EXPORT void imcb_chat_remove_buddy( struct groupchat *b, char *handle, char *reason ); +G_MODULE_EXPORT void imcb_chat_msg( struct groupchat *c, char *who, char *msg, u_int32_t flags, time_t sent_at ); +G_MODULE_EXPORT void imcb_chat_removed( struct groupchat *c ); +struct groupchat *chat_by_channel( char *channel ); + +/* Actions, or whatever. */ +int imc_set_away( struct im_connection *ic, char *away ); +int imc_buddy_msg( struct im_connection *ic, char *handle, char *msg, int flags ); +int imc_chat_msg( struct groupchat *c, char *msg, int flags ); + +void imc_add_allow( struct im_connection *ic, char *handle ); +void imc_rem_allow( struct im_connection *ic, char *handle ); +void imc_add_block( struct im_connection *ic, char *handle ); +void imc_rem_block( struct im_connection *ic, char *handle ); + +/* Misc. stuff */ char *set_eval_away_devoice( set_t *set, char *value ); - gboolean auto_reconnect( gpointer data, gint fd, b_input_condition cond ); void cancel_auto_reconnect( struct account *a ); -/* multi.c */ -G_MODULE_EXPORT struct gaim_connection *new_gaim_conn( account_t *acc ); -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_GNUC_PRINTF( 2, 3 ); -G_MODULE_EXPORT void account_online( struct gaim_connection *gc ); -G_MODULE_EXPORT void signoff( struct gaim_connection *gc ); - -/* dialogs.c */ -G_MODULE_EXPORT void do_error_dialog( struct gaim_connection *gc, char *msg, char *title ); -G_MODULE_EXPORT void do_ask_dialog( struct gaim_connection *gc, char *msg, void *data, void *doit, void *dont ); - -/* list.c */ -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 signoff_blocked( struct gaim_connection *gc ); - -G_MODULE_EXPORT void serv_buddy_rename( struct gaim_connection *gc, char *handle, char *realname ); - -/* buddy_chat.c */ -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 *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 ); -G_MODULE_EXPORT void serv_got_im( struct gaim_connection *gc, char *handle, char *msg, guint32 flags, time_t mtime, gint len ); -G_MODULE_EXPORT void serv_got_typing( struct gaim_connection *gc, char *handle, int timeout, int type ); -G_MODULE_EXPORT void serv_got_chat_invite( struct gaim_connection *gc, char *handle, char *who, char *msg, GList *data ); -G_MODULE_EXPORT struct conversation *serv_got_joined_chat( struct gaim_connection *gc, int id, char *handle ); -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 ); - -struct conversation *conv_findchannel( char *channel ); - #endif diff --git a/protocols/oscar/aim.h b/protocols/oscar/aim.h index 93887103..81ea5f9e 100644 --- a/protocols/oscar/aim.h +++ b/protocols/oscar/aim.h @@ -573,7 +573,7 @@ struct aim_chat_roominfo { }; struct aim_chat_invitation { - struct gaim_connection * gc; + struct im_connection * ic; char * name; guint8 exchange; }; diff --git a/protocols/oscar/chat.c b/protocols/oscar/chat.c index df535c4f..fbf45693 100644 --- a/protocols/oscar/chat.c +++ b/protocols/oscar/chat.c @@ -53,7 +53,7 @@ aim_conn_t *aim_chat_getconn(aim_session_t *sess, const char *name) if (cur->type != AIM_CONN_TYPE_CHAT) continue; if (!cur->priv) { - do_error_dialog(sess->aux_data, "chat connection with no name!", "Gaim"); + imcb_error(sess->aux_data, "chat connection with no name!"); continue; } @@ -396,7 +396,7 @@ static int infoupdate(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, a detaillevel = aimbs_get8(bs); if (detaillevel != 0x02) { - do_error_dialog(sess->aux_data, "Only detaillevel 0x2 is support at the moment", "Gaim"); + imcb_error(sess->aux_data, "Only detaillevel 0x2 is support at the moment"); return 1; } @@ -614,7 +614,7 @@ static int incomingmsg(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, channel = aimbs_get16(bs); if (channel != 0x0003) { - do_error_dialog(sess->aux_data, "unknown channel!", "Gaim"); + imcb_error(sess->aux_data, "unknown channel!"); return 0; } diff --git a/protocols/oscar/chatnav.c b/protocols/oscar/chatnav.c index c7e11765..d94d3c7b 100644 --- a/protocols/oscar/chatnav.c +++ b/protocols/oscar/chatnav.c @@ -285,7 +285,7 @@ static int parseinfo_create(aim_session_t *sess, aim_module_t *mod, aim_frame_t tlvlist = aim_readtlvchain(bs); if (!(bigblock = aim_gettlv(tlvlist, 0x0004, 1))) { - do_error_dialog(sess->aux_data, "no bigblock in top tlv in create room response", "Gaim"); + imcb_error(sess->aux_data, "no bigblock in top tlv in create room response"); aim_freetlvchain(&tlvlist); return 0; @@ -300,7 +300,7 @@ static int parseinfo_create(aim_session_t *sess, aim_module_t *mod, aim_frame_t detaillevel = aimbs_get8(&bbbs); if (detaillevel != 0x02) { - do_error_dialog(sess->aux_data, "unknown detaillevel in create room response", "Gaim"); + imcb_error(sess->aux_data, "unknown detaillevel in create room response"); aim_freetlvchain(&tlvlist); g_free(ck); return 0; @@ -366,12 +366,12 @@ static int parseinfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, ai int ret = 0; if (!(snac2 = aim_remsnac(sess, snac->id))) { - do_error_dialog(sess->aux_data, "received response to unknown request!", "Gaim"); + imcb_error(sess->aux_data, "received response to unknown request!"); return 0; } if (snac2->family != 0x000d) { - do_error_dialog(sess->aux_data, "recieved response that maps to corrupt request!", "Gaim"); + imcb_error(sess->aux_data, "recieved response that maps to corrupt request!"); return 0; } @@ -388,7 +388,7 @@ static int parseinfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, ai else if (snac2->type == 0x0008) /* create room */ ret = parseinfo_create(sess, mod, rx, snac, bs, snac2); else - do_error_dialog(sess->aux_data, "unknown request subtype", "Gaim"); + imcb_error(sess->aux_data, "unknown request subtype"); if (snac2) g_free(snac2->data); diff --git a/protocols/oscar/icq.c b/protocols/oscar/icq.c index 23959b75..f7c02e04 100644 --- a/protocols/oscar/icq.c +++ b/protocols/oscar/icq.c @@ -239,7 +239,7 @@ static int icqresponse(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, if (!(tl = aim_readtlvchain(bs)) || !(datatlv = aim_gettlv(tl, 0x0001, 1))) { aim_freetlvchain(&tl); - do_error_dialog(sess->aux_data, "corrupt ICQ response\n", "Gaim"); + imcb_error(sess->aux_data, "corrupt ICQ response\n"); return 0; } diff --git a/protocols/oscar/im.c b/protocols/oscar/im.c index 7cccabc7..51d8ec74 100644 --- a/protocols/oscar/im.c +++ b/protocols/oscar/im.c @@ -936,7 +936,7 @@ static int outgoingim(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, a channel = aimbs_get16(bs); if (channel != 0x01) { - do_error_dialog(sess->aux_data, "icbm: ICBM recieved on unsupported channel. Ignoring.", "Gaim"); + imcb_error(sess->aux_data, "icbm: ICBM recieved on unsupported channel. Ignoring."); return 0; } @@ -1344,7 +1344,7 @@ static int incomingim_ch1(aim_session_t *sess, aim_module_t *mod, aim_frame_t *r args.extdata = aimbs_getraw(bs, args.extdatalen); } else { - // do_error_dialog(sess->aux_data, "Unknown TLV encountered", "Gaim"); + // imcb_error(sess->aux_data, "Unknown TLV encountered"); } /* @@ -1416,7 +1416,7 @@ static void incomingim_ch2_icqserverrelay(aim_session_t *sess, aim_module_t *mod guint8 msgtype, msgflags; guint8 *plugin; int i = 0, tmp = 0; - struct gaim_connection *gc = sess->aux_data; + struct im_connection *ic = sess->aux_data; /* at the moment we just can deal with requests, not with cancel or accept */ if (args->status != 0) return; @@ -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 ? gc->away : "", sess->aim_icq_state, dc); + ic->away ? ic->away : "", sess->aim_icq_state, dc); break; } @@ -1516,7 +1516,7 @@ static int incomingim_ch2(aim_session_t *sess, aim_module_t *mod, aim_frame_t *r */ cookie2 = aimbs_getraw(&bbs, 8); if (memcmp(cookie, cookie2, 8) != 0) - do_error_dialog(sess->aux_data, "rend: warning cookies don't match!", "Gaim"); + imcb_error(sess->aux_data, "rend: warning cookies don't match!"); memcpy(args.cookie, cookie2, 8); g_free(cookie2); @@ -1782,7 +1782,7 @@ static int incomingim(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, a } else { - do_error_dialog(sess->aux_data, "ICBM received on an unsupported channel. Ignoring.", "Gaim"); + imcb_error(sess->aux_data, "ICBM received on an unsupported channel. Ignoring."); return 0; } diff --git a/protocols/oscar/info.c b/protocols/oscar/info.c index 0f1bcfd2..7cc1dbbc 100644 --- a/protocols/oscar/info.c +++ b/protocols/oscar/info.c @@ -473,7 +473,7 @@ int aim_extractuserinfo(aim_session_t *sess, aim_bstream_t *bs, aim_userinfo_t * * */ #ifdef DEBUG - // do_error_dialog(sess->aux_data, G_STRLOC, "Unknown TLV encountered"); + // imcb_error(sess->aux_data, G_STRLOC); #endif } @@ -634,7 +634,7 @@ static int userinfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim origsnac = aim_remsnac(sess, snac->id); if (!origsnac || !origsnac->data) { - do_error_dialog(sess->aux_data, "major problem: no snac stored!", "Gaim"); + imcb_error(sess->aux_data, "major problem: no snac stored!"); return 0; } @@ -643,7 +643,7 @@ static int userinfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim if ((inforeq->infotype != AIM_GETINFO_GENERALINFO) && (inforeq->infotype != AIM_GETINFO_AWAYMESSAGE) && (inforeq->infotype != AIM_GETINFO_CAPABILITIES)) { - do_error_dialog(sess->aux_data, "unknown infotype in request!", "Gaim"); + imcb_error(sess->aux_data, "unknown infotype in request!"); return 0; } diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c index 72078b3c..426dd4a2 100644 --- a/protocols/oscar/oscar.c +++ b/protocols/oscar/oscar.c @@ -115,21 +115,21 @@ struct chat_connection { aim_conn_t *conn; int inpa; int id; - struct gaim_connection *gc; /* i hate this. */ - struct conversation *cnv; /* bah. */ + struct im_connection *ic; /* i hate this. */ + struct groupchat *cnv; /* bah. */ int maxlen; int maxvis; }; struct ask_direct { - struct gaim_connection *gc; + struct im_connection *ic; char *sn; char ip[64]; guint8 cookie[8]; }; struct icq_auth { - struct gaim_connection *gc; + struct im_connection *ic; guint32 uin; }; @@ -157,25 +157,9 @@ static char *extract_name(const char *name) { return tmp; } -static struct chat_connection *find_oscar_chat(struct gaim_connection *gc, int id) { - GSList *g = ((struct oscar_data *)gc->proto_data)->oscar_chats; - struct chat_connection *c = NULL; - - while (g) { - c = (struct chat_connection *)g->data; - if (c->id == id) - break; - g = g->next; - c = NULL; - } - - return c; -} - - -static struct chat_connection *find_oscar_chat_by_conn(struct gaim_connection *gc, +static struct chat_connection *find_oscar_chat_by_conn(struct im_connection *ic, aim_conn_t *conn) { - GSList *g = ((struct oscar_data *)gc->proto_data)->oscar_chats; + GSList *g = ((struct oscar_data *)ic->proto_data)->oscar_chats; struct chat_connection *c = NULL; while (g) { @@ -258,43 +242,41 @@ static gboolean oscar_callback(gpointer data, gint source, b_input_condition condition) { aim_conn_t *conn = (aim_conn_t *)data; aim_session_t *sess = aim_conn_getsess(conn); - struct gaim_connection *gc = sess ? sess->aux_data : NULL; + struct im_connection *ic = sess ? sess->aux_data : NULL; struct oscar_data *odata; - if (!gc) { - /* gc is null. we return, else we seg SIGSEG on next line. */ + if (!ic) { + /* ic is null. we return, else we seg SIGSEG on next line. */ return FALSE; } - if (!g_slist_find(get_connections(), gc)) { + if (!g_slist_find(get_connections(), ic)) { /* oh boy. this is probably bad. i guess the only thing we * can really do is return? */ return FALSE; } - odata = (struct oscar_data *)gc->proto_data; + odata = (struct oscar_data *)ic->proto_data; if (condition & GAIM_INPUT_READ) { if (aim_get_command(odata->sess, conn) >= 0) { aim_rxdispatch(odata->sess); if (odata->killme) - signoff(gc); + imc_logout(ic, TRUE); } else { if ((conn->type == AIM_CONN_TYPE_BOS) || !(aim_getconn_type(odata->sess, AIM_CONN_TYPE_BOS))) { - hide_login_progress_error(gc, _("Disconnected.")); - signoff(gc); + imcb_error(ic, _("Disconnected.")); + imc_logout(ic, TRUE); } else if (conn->type == AIM_CONN_TYPE_CHAT) { - struct chat_connection *c = find_oscar_chat_by_conn(gc, conn); - char buf[BUF_LONG]; + struct chat_connection *c = find_oscar_chat_by_conn(ic, conn); c->conn = NULL; if (c->inpa > 0) b_event_remove(c->inpa); c->inpa = 0; c->fd = -1; aim_conn_kill(odata->sess, &conn); - sprintf(buf, _("You have been disconnected from chat room %s."), c->name); - do_error_dialog(sess->aux_data, buf, _("Chat Error!")); + imcb_error(sess->aux_data, _("You have been disconnected from chat room %s."), c->name); } else if (conn->type == AIM_CONN_TYPE_CHATNAV) { if (odata->cnpa > 0) b_event_remove(odata->cnpa); @@ -305,8 +287,7 @@ static gboolean oscar_callback(gpointer data, gint source, odata->create_rooms = g_slist_remove(odata->create_rooms, cr); g_free(cr); - do_error_dialog(sess->aux_data, _("Chat is currently unavailable"), - _("Gaim - Chat")); + imcb_error(sess->aux_data, _("Chat is currently unavailable")); } aim_conn_kill(odata->sess, &conn); } else if (conn->type == AIM_CONN_TYPE_AUTH) { @@ -328,34 +309,34 @@ static gboolean oscar_callback(gpointer data, gint source, static gboolean oscar_login_connect(gpointer data, gint source, b_input_condition cond) { - struct gaim_connection *gc = data; + struct im_connection *ic = data; struct oscar_data *odata; aim_session_t *sess; aim_conn_t *conn; - if (!g_slist_find(get_connections(), gc)) { + if (!g_slist_find(get_connections(), ic)) { closesocket(source); return FALSE; } - odata = gc->proto_data; + odata = ic->proto_data; sess = odata->sess; conn = aim_getconn_type_all(sess, AIM_CONN_TYPE_AUTH); if (source < 0) { - hide_login_progress(gc, _("Couldn't connect to host")); - signoff(gc); + imcb_error(ic, _("Couldn't connect to host")); + imc_logout(ic, TRUE); return FALSE; } aim_conn_completeconnect(sess, conn); - gc->inpa = b_input_add(conn->fd, GAIM_INPUT_READ, + ic->inpa = b_input_add(conn->fd, GAIM_INPUT_READ, oscar_callback, conn); return FALSE; } -static void oscar_acc_init(account_t *acc) +static void oscar_init(account_t *acc) { set_t *s; @@ -371,18 +352,19 @@ static void oscar_acc_init(account_t *acc) static void oscar_login(account_t *acc) { aim_session_t *sess; aim_conn_t *conn; - char buf[256]; - struct gaim_connection *gc = new_gaim_conn(acc); - struct oscar_data *odata = gc->proto_data = g_new0(struct oscar_data, 1); + struct im_connection *ic = imcb_new(acc); + struct oscar_data *odata = ic->proto_data = g_new0(struct oscar_data, 1); if (isdigit(acc->user[0])) { odata->icq = TRUE; /* 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... </bitlbee> */ - gc->password[8] = 0; + /* ic->acc->pass[8] = 0; + Not touching this anymore now that it belongs to account_t! + Let's hope nothing will break. ;-) */ } else { - gc->flags |= OPT_CONN_HTML; + ic->flags |= OPT_DOES_HTML; } sess = g_new0(aim_session_t, 1); @@ -393,44 +375,43 @@ static void oscar_login(account_t *acc) { * see if things need to be sent. */ aim_tx_setenqueue(sess, AIM_TX_IMMEDIATE, NULL); odata->sess = sess; - sess->aux_data = gc; + sess->aux_data = ic; conn = aim_newconn(sess, AIM_CONN_TYPE_AUTH, NULL); if (conn == NULL) { - hide_login_progress(gc, _("Unable to login to AIM")); - signoff(gc); + imcb_error(ic, _("Unable to login to AIM")); + imc_logout(ic, TRUE); return; } if (acc->server == NULL) { - hide_login_progress(gc, "No servername specified"); - signoff(gc); + imcb_error(ic, "No servername specified"); + imc_logout(ic, FALSE); return; } if (g_strcasecmp(acc->server, "login.icq.com") != 0 && g_strcasecmp(acc->server, "login.oscar.aol.com") != 0) { - serv_got_crap(gc, "Warning: Unknown OSCAR server: `%s'. Please review your configuration if the connection fails.",acc->server); + imcb_log(ic, "Warning: Unknown OSCAR server: `%s'. Please review your configuration if the connection fails.",acc->server); } - g_snprintf(buf, sizeof(buf), _("Signon: %s"), gc->username); - set_login_progress(gc, 2, buf); + imcb_log(ic, _("Signon: %s"), ic->acc->user); aim_conn_addhandler(sess, conn, 0x0017, 0x0007, gaim_parse_login, 0); aim_conn_addhandler(sess, conn, 0x0017, 0x0003, gaim_parse_auth_resp, 0); conn->status |= AIM_CONN_STATUS_INPROGRESS; - conn->fd = proxy_connect(acc->server, AIM_LOGIN_PORT, oscar_login_connect, gc); + conn->fd = proxy_connect(acc->server, AIM_LOGIN_PORT, oscar_login_connect, ic); if (conn->fd < 0) { - hide_login_progress(gc, _("Couldn't connect to host")); - signoff(gc); + imcb_error(ic, _("Couldn't connect to host")); + imc_logout(ic, TRUE); return; } - aim_request_login(sess, conn, gc->username); + aim_request_login(sess, conn, ic->acc->user); } -static void oscar_close(struct gaim_connection *gc) { - struct oscar_data *odata = (struct oscar_data *)gc->proto_data; +static void oscar_logout(struct im_connection *ic) { + struct oscar_data *odata = (struct oscar_data *)ic->proto_data; while (odata->oscar_chats) { struct chat_connection *n = odata->oscar_chats->data; @@ -453,8 +434,8 @@ static void oscar_close(struct gaim_connection *gc) { g_free(odata->newp); if (odata->oldp) g_free(odata->oldp); - if (gc->inpa > 0) - b_event_remove(gc->inpa); + if (ic->inpa > 0) + b_event_remove(ic->inpa); if (odata->cnpa > 0) b_event_remove(odata->cnpa); if (odata->paspa > 0) @@ -462,35 +443,35 @@ static void oscar_close(struct gaim_connection *gc) { aim_session_kill(odata->sess); g_free(odata->sess); odata->sess = NULL; - g_free(gc->proto_data); - gc->proto_data = NULL; + g_free(ic->proto_data); + ic->proto_data = NULL; } static gboolean oscar_bos_connect(gpointer data, gint source, b_input_condition cond) { - struct gaim_connection *gc = data; + struct im_connection *ic = data; struct oscar_data *odata; aim_session_t *sess; aim_conn_t *bosconn; - if (!g_slist_find(get_connections(), gc)) { + if (!g_slist_find(get_connections(), ic)) { closesocket(source); return FALSE; } - odata = gc->proto_data; + odata = ic->proto_data; sess = odata->sess; bosconn = odata->conn; if (source < 0) { - hide_login_progress(gc, _("Could Not Connect")); - signoff(gc); + imcb_error(ic, _("Could Not Connect")); + imc_logout(ic, TRUE); return FALSE; } aim_conn_completeconnect(sess, bosconn); - gc->inpa = b_input_add(bosconn->fd, GAIM_INPUT_READ, + ic->inpa = b_input_add(bosconn->fd, GAIM_INPUT_READ, oscar_callback, bosconn); - set_login_progress(gc, 4, _("Connection established, cookie sent")); + imcb_log(ic, _("Connection established, cookie sent")); return FALSE; } @@ -501,8 +482,8 @@ static int gaim_parse_auth_resp(aim_session_t *sess, aim_frame_t *fr, ...) { int i; char *host; int port; aim_conn_t *bosconn; - struct gaim_connection *gc = sess->aux_data; - struct oscar_data *od = gc->proto_data; + struct im_connection *ic = sess->aux_data; + struct oscar_data *od = ic->proto_data; port = AIM_LOGIN_PORT; va_start(ap, fr); @@ -513,23 +494,23 @@ static int gaim_parse_auth_resp(aim_session_t *sess, aim_frame_t *fr, ...) { switch (info->errorcode) { case 0x05: /* Incorrect nick/password */ - hide_login_progress(gc, _("Incorrect nickname or password.")); + imcb_error(ic, _("Incorrect nickname or password.")); // plugin_event(event_error, (void *)980, 0, 0, 0); break; case 0x11: /* Suspended account */ - hide_login_progress(gc, _("Your account is currently suspended.")); + imcb_error(ic, _("Your account is currently suspended.")); break; case 0x18: /* connecting too frequently */ - hide_login_progress(gc, _("You have been connecting and disconnecting too frequently. Wait ten minutes and try again. If you continue to try, you will need to wait even longer.")); + imcb_error(ic, _("You have been connecting and disconnecting too frequently. Wait ten minutes and try again. If you continue to try, you will need to wait even longer.")); break; case 0x1c: /* client too old */ - hide_login_progress(gc, _("The client version you are using is too old. Please upgrade at " WEBSITE)); + imcb_error(ic, _("The client version you are using is too old. Please upgrade at " WEBSITE)); break; default: - hide_login_progress(gc, _("Authentication Failed")); + imcb_error(ic, _("Authentication Failed")); break; } od->killme = TRUE; @@ -541,7 +522,7 @@ static int gaim_parse_auth_resp(aim_session_t *sess, aim_frame_t *fr, ...) { bosconn = aim_newconn(sess, AIM_CONN_TYPE_BOS, NULL); if (bosconn == NULL) { - hide_login_progress(gc, _("Internal Error")); + imcb_error(ic, _("Internal Error")); od->killme = TRUE; return 0; } @@ -575,7 +556,7 @@ static int gaim_parse_auth_resp(aim_session_t *sess, aim_frame_t *fr, ...) { aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO, gaim_parseaiminfo, 0); aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_MTN, gaim_parsemtn, 0); - ((struct oscar_data *)gc->proto_data)->conn = bosconn; + ((struct oscar_data *)ic->proto_data)->conn = bosconn; for (i = 0; i < (int)strlen(info->bosip); i++) { if (info->bosip[i] == ':') { port = atoi(&(info->bosip[i+1])); @@ -584,21 +565,21 @@ static int gaim_parse_auth_resp(aim_session_t *sess, aim_frame_t *fr, ...) { } host = g_strndup(info->bosip, i); bosconn->status |= AIM_CONN_STATUS_INPROGRESS; - bosconn->fd = proxy_connect(host, port, oscar_bos_connect, gc); + bosconn->fd = proxy_connect(host, port, oscar_bos_connect, ic); g_free(host); if (bosconn->fd < 0) { - hide_login_progress(gc, _("Could Not Connect")); + imcb_error(ic, _("Could Not Connect")); od->killme = TRUE; return 0; } aim_sendcookie(sess, bosconn, info->cookie); - b_event_remove(gc->inpa); + b_event_remove(ic->inpa); return 1; } struct pieceofcrap { - struct gaim_connection *gc; + struct im_connection *ic; unsigned long offset; unsigned long len; char *modname; @@ -610,7 +591,7 @@ struct pieceofcrap { static gboolean damn_you(gpointer data, gint source, b_input_condition c) { struct pieceofcrap *pos = data; - struct oscar_data *od = pos->gc->proto_data; + struct oscar_data *od = pos->ic->proto_data; char in = '\0'; int x = 0; unsigned char m[17]; @@ -625,8 +606,8 @@ static gboolean damn_you(gpointer data, gint source, b_input_condition c) in = '\0'; } if (in != '\n') { - do_error_dialog(pos->gc, "Gaim was unable to get a valid hash for logging into AIM." - " You may be disconnected shortly.", "Login Error"); + imcb_error(pos->ic, "Gaim was unable to get a valid hash for logging into AIM." + " You may be disconnected shortly."); b_event_remove(pos->inpa); closesocket(pos->fd); g_free(pos); @@ -648,8 +629,8 @@ static gboolean straight_to_hell(gpointer data, gint source, b_input_condition c char buf[BUF_LONG]; if (source < 0) { - do_error_dialog(pos->gc, "Gaim was unable to get a valid hash for logging into AIM." - " You may be disconnected shortly.", "Login Error"); + imcb_error(pos->ic, "Gaim was unable to get a valid hash for logging into AIM." + " You may be disconnected shortly."); if (pos->modname) g_free(pos->modname); g_free(pos); @@ -714,7 +695,7 @@ int gaim_memrequest(aim_session_t *sess, aim_frame_t *fr, ...) { */ pos = g_new0(struct pieceofcrap, 1); - pos->gc = sess->aux_data; + pos->ic = sess->aux_data; pos->conn = fr->conn; pos->offset = offset; @@ -726,8 +707,8 @@ int gaim_memrequest(aim_session_t *sess, aim_frame_t *fr, ...) { if (pos->modname) g_free(pos->modname); g_free(pos); - do_error_dialog(sess->aux_data, "Gaim was unable to get a valid hash for logging into AIM." - " You may be disconnected shortly.", "Login Error"); + imcb_error(sess->aux_data, "Gaim was unable to get a valid hash for logging into AIM." + " You may be disconnected shortly."); } pos->fd = fd; @@ -742,19 +723,19 @@ static int gaim_parse_login(aim_session_t *sess, aim_frame_t *fr, ...) { #endif char *key; va_list ap; - struct gaim_connection *gc = sess->aux_data; + struct im_connection *ic = sess->aux_data; va_start(ap, fr); key = va_arg(ap, char *); va_end(ap); - aim_send_login(sess, fr->conn, gc->username, gc->password, &info, key); + aim_send_login(sess, fr->conn, ic->acc->user, ic->acc->pass, &info, key); return 1; } static int conninitdone_chat(aim_session_t *sess, aim_frame_t *fr, ...) { - struct gaim_connection *gc = sess->aux_data; + struct im_connection *ic = sess->aux_data; struct chat_connection *chatcon; static int id = 1; @@ -766,9 +747,10 @@ static int conninitdone_chat(aim_session_t *sess, aim_frame_t *fr, ...) { aim_clientready(sess, fr->conn); - chatcon = find_oscar_chat_by_conn(gc, fr->conn); + chatcon = find_oscar_chat_by_conn(ic, fr->conn); chatcon->id = id; - chatcon->cnv = serv_got_joined_chat(gc, id++, chatcon->show); + chatcon->cnv = imcb_chat_new(ic, chatcon->show); + chatcon->cnv->data = chatcon; return 1; } @@ -786,17 +768,17 @@ static int conninitdone_chatnav(aim_session_t *sess, aim_frame_t *fr, ...) { } static gboolean oscar_chatnav_connect(gpointer data, gint source, b_input_condition cond) { - struct gaim_connection *gc = data; + struct im_connection *ic = data; struct oscar_data *odata; aim_session_t *sess; aim_conn_t *tstconn; - if (!g_slist_find(get_connections(), gc)) { + if (!g_slist_find(get_connections(), ic)) { closesocket(source); return FALSE; } - odata = gc->proto_data; + odata = ic->proto_data; sess = odata->sess; tstconn = aim_getconn_type_all(sess, AIM_CONN_TYPE_CHATNAV); @@ -814,17 +796,17 @@ static gboolean oscar_chatnav_connect(gpointer data, gint source, b_input_condit static gboolean oscar_auth_connect(gpointer data, gint source, b_input_condition cond) { - struct gaim_connection *gc = data; + struct im_connection *ic = data; struct oscar_data *odata; aim_session_t *sess; aim_conn_t *tstconn; - if (!g_slist_find(get_connections(), gc)) { + if (!g_slist_find(get_connections(), ic)) { closesocket(source); return FALSE; } - odata = gc->proto_data; + odata = ic->proto_data; sess = odata->sess; tstconn = aim_getconn_type_all(sess, AIM_CONN_TYPE_AUTH); @@ -843,12 +825,12 @@ static gboolean oscar_auth_connect(gpointer data, gint source, b_input_condition static gboolean oscar_chat_connect(gpointer data, gint source, b_input_condition cond) { struct chat_connection *ccon = data; - struct gaim_connection *gc = ccon->gc; + struct im_connection *ic = ccon->ic; struct oscar_data *odata; aim_session_t *sess; aim_conn_t *tstconn; - if (!g_slist_find(get_connections(), gc)) { + if (!g_slist_find(get_connections(), ic)) { closesocket(source); g_free(ccon->show); g_free(ccon->name); @@ -856,7 +838,7 @@ static gboolean oscar_chat_connect(gpointer data, gint source, b_input_condition return FALSE; } - odata = gc->proto_data; + odata = ic->proto_data; sess = odata->sess; tstconn = ccon->conn; @@ -881,7 +863,7 @@ static gboolean oscar_chat_connect(gpointer data, gint source, b_input_condition static int gaim_handle_redirect(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; struct aim_redirect_data *redir; - struct gaim_connection *gc = sess->aux_data; + struct im_connection *ic = sess->aux_data; aim_conn_t *tstconn; int i; char *host; @@ -913,7 +895,7 @@ static int gaim_handle_redirect(aim_session_t *sess, aim_frame_t *fr, ...) { // aim_conn_addhandler(sess, tstconn, 0x0007, 0x0007, gaim_account_confirm, 0); tstconn->status |= AIM_CONN_STATUS_INPROGRESS; - tstconn->fd = proxy_connect(host, port, oscar_auth_connect, gc); + tstconn->fd = proxy_connect(host, port, oscar_auth_connect, ic); if (tstconn->fd < 0) { aim_conn_kill(sess, &tstconn); g_free(host); @@ -930,7 +912,7 @@ static int gaim_handle_redirect(aim_session_t *sess, aim_frame_t *fr, ...) { aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_chatnav, 0); tstconn->status |= AIM_CONN_STATUS_INPROGRESS; - tstconn->fd = proxy_connect(host, port, oscar_chatnav_connect, gc); + tstconn->fd = proxy_connect(host, port, oscar_chatnav_connect, ic); if (tstconn->fd < 0) { aim_conn_kill(sess, &tstconn); g_free(host); @@ -952,7 +934,7 @@ static int gaim_handle_redirect(aim_session_t *sess, aim_frame_t *fr, ...) { ccon = g_new0(struct chat_connection, 1); ccon->conn = tstconn; - ccon->gc = gc; + ccon->ic = ic; ccon->fd = -1; ccon->name = g_strdup(redir->chat.room); ccon->exchange = redir->chat.exchange; @@ -981,49 +963,39 @@ static int gaim_handle_redirect(aim_session_t *sess, aim_frame_t *fr, ...) { } static int gaim_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...) { - struct gaim_connection *gc = sess->aux_data; - struct oscar_data *od = gc->proto_data; + struct im_connection *ic = sess->aux_data; + struct oscar_data *od = ic->proto_data; aim_userinfo_t *info; time_t time_idle = 0, signon = 0; - int type = 0; - int caps = 0; - char *tmp; + int flags = OPT_LOGGED_IN; + char *tmp, *state_string = NULL; va_list ap; va_start(ap, fr); info = va_arg(ap, aim_userinfo_t *); va_end(ap); - if (info->present & AIM_USERINFO_PRESENT_CAPABILITIES) - caps = info->capabilities; - if (info->flags & AIM_FLAG_ACTIVEBUDDY) - type |= UC_AB; - if ((!od->icq) && (info->present & AIM_USERINFO_PRESENT_FLAGS)) { - if (info->flags & AIM_FLAG_UNCONFIRMED) - type |= UC_UNCONFIRMED; - if (info->flags & AIM_FLAG_ADMINISTRATOR) - type |= UC_ADMIN; - if (info->flags & AIM_FLAG_AOL) - type |= UC_AOL; - if (info->flags & AIM_FLAG_FREE) - type |= UC_NORMAL; if (info->flags & AIM_FLAG_AWAY) - type |= UC_UNAVAILABLE; - if (info->flags & AIM_FLAG_WIRELESS) - type |= UC_WIRELESS; + flags |= OPT_AWAY; } + if (info->present & AIM_USERINFO_PRESENT_ICQEXTSTATUS) { - type = (info->icqinfo.status << 7); if (!(info->icqinfo.status & AIM_ICQ_STATE_CHAT) && (info->icqinfo.status != AIM_ICQ_STATE_NORMAL)) { - type |= UC_UNAVAILABLE; + flags |= OPT_AWAY; } + + if( info->icqinfo.status & AIM_ICQ_STATE_DND ) + state_string = "Do Not Disturb"; + else if( info->icqinfo.status & AIM_ICQ_STATE_OUT ) + state_string = "Not Available"; + else if( info->icqinfo.status & AIM_ICQ_STATE_BUSY ) + state_string = "Occupied"; + else if( info->icqinfo.status & AIM_ICQ_STATE_INVISIBLE ) + state_string = "Invisible"; } - if (caps & AIM_CAPS_ICQ) - caps ^= AIM_CAPS_ICQ; - if (info->present & AIM_USERINFO_PRESENT_IDLE) { time(&time_idle); time_idle -= info->idletime*60; @@ -1032,13 +1004,13 @@ static int gaim_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...) { if (info->present & AIM_USERINFO_PRESENT_SESSIONLEN) signon = time(NULL) - info->sessionlen; - tmp = g_strdup(normalize(gc->username)); + tmp = g_strdup(normalize(ic->acc->user)); if (!strcmp(tmp, normalize(info->sn))) - g_snprintf(gc->displayname, sizeof(gc->displayname), "%s", info->sn); + g_snprintf(ic->displayname, sizeof(ic->displayname), "%s", info->sn); g_free(tmp); - serv_got_update(gc, info->sn, 1, info->warnlevel/10, signon, - time_idle, type, caps); + imcb_buddy_status(ic, info->sn, flags, state_string, NULL); + /* imcb_buddy_times(ic, info->sn, signon, time_idle); */ return 1; } @@ -1046,24 +1018,24 @@ static int gaim_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...) { static int gaim_parse_offgoing(aim_session_t *sess, aim_frame_t *fr, ...) { aim_userinfo_t *info; va_list ap; - struct gaim_connection *gc = sess->aux_data; + struct im_connection *ic = sess->aux_data; va_start(ap, fr); info = va_arg(ap, aim_userinfo_t *); va_end(ap); - serv_got_update(gc, info->sn, 0, 0, 0, 0, 0, 0); + imcb_buddy_status(ic, info->sn, 0, NULL, NULL ); return 1; } static int incomingim_chan1(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch1_args *args) { char *tmp = g_malloc(BUF_LONG + 1); - struct gaim_connection *gc = sess->aux_data; + struct im_connection *ic = sess->aux_data; int flags = 0; if (args->icbmflags & AIM_IMFLAGS_AWAY) - flags |= IM_FLAG_AWAY; + flags |= OPT_AWAY; if ((args->icbmflags & AIM_IMFLAGS_UNICODE) || (args->icbmflags & AIM_IMFLAGS_ISO_8859_1)) { char *src; @@ -1097,7 +1069,7 @@ static int incomingim_chan1(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_ g_snprintf(tmp, BUF_LONG, "%s", args->msg); strip_linefeed(tmp); - serv_got_im(gc, userinfo->sn, tmp, flags, time(NULL), -1); + imcb_buddy_msg(ic, userinfo->sn, tmp, flags, 0); g_free(tmp); return 1; @@ -1107,7 +1079,7 @@ void oscar_accept_chat(gpointer w, struct aim_chat_invitation * inv); void oscar_reject_chat(gpointer w, struct aim_chat_invitation * inv); static int incomingim_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args) { - struct gaim_connection *gc = sess->aux_data; + struct im_connection *ic = sess->aux_data; if (args->status != AIM_RENDEZVOUS_PROPOSE) return 1; @@ -1125,11 +1097,11 @@ static int incomingim_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_ g_snprintf( txt, 1024, "Got an invitation to chatroom %s from %s: %s", name, userinfo->sn, args->msg ); - inv->gc = gc; + inv->ic = ic; inv->exchange = *exch; inv->name = g_strdup(name); - do_ask_dialog( gc, txt, inv, oscar_accept_chat, oscar_reject_chat); + imcb_ask( ic, txt, inv, oscar_accept_chat, oscar_reject_chat); if (name) g_free(name); @@ -1140,14 +1112,14 @@ static int incomingim_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_ static void gaim_icq_authgrant(gpointer w, struct icq_auth *data) { char *uin, message; - struct oscar_data *od = (struct oscar_data *)data->gc->proto_data; + struct oscar_data *od = (struct oscar_data *)data->ic->proto_data; uin = g_strdup_printf("%u", data->uin); message = 0; aim_ssi_auth_reply(od->sess, od->conn, uin, 1, ""); // aim_send_im_ch4(od->sess, uin, AIM_ICQMSG_AUTHGRANTED, &message); - if(find_buddy(data->gc, uin) == NULL) - show_got_added(data->gc, uin, NULL); + if(imcb_find_buddy(data->ic, uin) == NULL) + imcb_ask_add(data->ic, uin, NULL); g_free(uin); g_free(data); @@ -1155,7 +1127,7 @@ static void gaim_icq_authgrant(gpointer w, struct icq_auth *data) { static void gaim_icq_authdeny(gpointer w, struct icq_auth *data) { char *uin, *message; - struct oscar_data *od = (struct oscar_data *)data->gc->proto_data; + struct oscar_data *od = (struct oscar_data *)data->ic->proto_data; uin = g_strdup_printf("%u", data->uin); message = g_strdup_printf("No reason given."); @@ -1170,7 +1142,7 @@ static void gaim_icq_authdeny(gpointer w, struct icq_auth *data) { /* * For when other people ask you for authorization */ -static void gaim_icq_authask(struct gaim_connection *gc, guint32 uin, char *msg) { +static void gaim_icq_authask(struct im_connection *ic, guint32 uin, char *msg) { struct icq_auth *data = g_new(struct icq_auth, 1); char *reason = NULL; char *dialog_msg; @@ -1179,14 +1151,14 @@ static void gaim_icq_authask(struct gaim_connection *gc, guint32 uin, char *msg) reason = msg + 6; 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->ic = ic; data->uin = uin; - do_ask_dialog(gc, dialog_msg, data, gaim_icq_authgrant, gaim_icq_authdeny); + imcb_ask(ic, dialog_msg, data, gaim_icq_authgrant, gaim_icq_authdeny); g_free(dialog_msg); } static int incomingim_chan4(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch4_args *args) { - struct gaim_connection *gc = sess->aux_data; + struct im_connection *ic = sess->aux_data; switch (args->type) { case 0x0001: { /* An almost-normal instant message. Mac ICQ sends this. It's peculiar. */ @@ -1194,7 +1166,7 @@ static int incomingim_chan4(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_ uin = g_strdup_printf("%u", args->uin); message = g_strdup(args->msg); strip_linefeed(message); - serv_got_im(gc, uin, message, 0, time(NULL), -1); + imcb_buddy_msg(ic, uin, message, 0, 0); g_free(uin); g_free(message); } break; @@ -1213,22 +1185,22 @@ static int incomingim_chan4(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_ } strip_linefeed(message); - serv_got_im(gc, uin, message, 0, time(NULL), -1); + imcb_buddy_msg(ic, uin, message, 0, 0); g_free(uin); g_free(m); g_free(message); } break; case 0x0006: { /* Someone requested authorization */ - gaim_icq_authask(gc, args->uin, args->msg); + gaim_icq_authask(ic, args->uin, args->msg); } break; case 0x0007: { /* Someone has denied you authorization */ - serv_got_crap(sess->aux_data, "The user %u has denied your request to add them to your contact list for the following reason:\n%s", args->uin, args->msg ? args->msg : _("No reason given.") ); + imcb_log(sess->aux_data, "The user %u has denied your request to add them to your contact list for the following reason:\n%s", args->uin, args->msg ? args->msg : _("No reason given.") ); } break; case 0x0008: { /* Someone has granted you authorization */ - serv_got_crap(sess->aux_data, "The user %u has granted your request to add them to your contact list for the following reason:\n%s", args->uin, args->msg ? args->msg : _("No reason given.") ); + imcb_log(sess->aux_data, "The user %u has granted your request to add them to your contact list for the following reason:\n%s", args->uin, args->msg ? args->msg : _("No reason given.") ); } break; case 0x0012: { @@ -1283,7 +1255,6 @@ static int gaim_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; guint16 chan, nummissed, reason; aim_userinfo_t *userinfo; - char buf[1024]; va_start(ap, fr); chan = (guint16)va_arg(ap, unsigned int); @@ -1295,8 +1266,7 @@ static int gaim_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...) { switch(reason) { case 0: /* Invalid (0) */ - g_snprintf(buf, - sizeof(buf), + imcb_error(sess->aux_data, nummissed == 1 ? _("You missed %d message from %s because it was invalid.") : _("You missed %d messages from %s because they were invalid."), @@ -1305,8 +1275,7 @@ static int gaim_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...) { break; case 1: /* Message too large */ - g_snprintf(buf, - sizeof(buf), + imcb_error(sess->aux_data, nummissed == 1 ? _("You missed %d message from %s because it was too large.") : _("You missed %d messages from %s because they were too large."), @@ -1315,8 +1284,7 @@ static int gaim_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...) { break; case 2: /* Rate exceeded */ - g_snprintf(buf, - sizeof(buf), + imcb_error(sess->aux_data, nummissed == 1 ? _("You missed %d message from %s because the rate limit has been exceeded.") : _("You missed %d messages from %s because the rate limit has been exceeded."), @@ -1325,8 +1293,7 @@ static int gaim_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...) { break; case 3: /* Evil Sender */ - g_snprintf(buf, - sizeof(buf), + imcb_error(sess->aux_data, nummissed == 1 ? _("You missed %d message from %s because it was too evil.") : _("You missed %d messages from %s because they are too evil."), @@ -1335,8 +1302,7 @@ static int gaim_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...) { break; case 4: /* Evil Receiver */ - g_snprintf(buf, - sizeof(buf), + imcb_error(sess->aux_data, nummissed == 1 ? _("You missed %d message from %s because you are too evil.") : _("You missed %d messages from %s because you are too evil."), @@ -1344,8 +1310,7 @@ static int gaim_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...) { userinfo->sn); break; default: - g_snprintf(buf, - sizeof(buf), + imcb_error(sess->aux_data, nummissed == 1 ? _("You missed %d message from %s for unknown reasons.") : _("You missed %d messages from %s for unknown reasons."), @@ -1353,7 +1318,6 @@ static int gaim_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...) { userinfo->sn); break; } - do_error_dialog(sess->aux_data, buf, _("Gaim - Error")); return 1; } @@ -1361,16 +1325,13 @@ static int gaim_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...) { static int gaim_parse_genericerr(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; guint16 reason; - char *m; va_start(ap, fr); reason = (guint16)va_arg(ap, unsigned int); va_end(ap); - m = g_strdup_printf(_("SNAC threw error: %s\n"), - reason < msgerrreasonlen ? msgerrreason[reason] : "Unknown error"); - do_error_dialog(sess->aux_data, m, _("Gaim - Oscar SNAC Error")); - g_free(m); + imcb_error(sess->aux_data, _("SNAC threw error: %s"), + reason < msgerrreasonlen ? msgerrreason[reason] : "Unknown error"); return 1; } @@ -1379,16 +1340,14 @@ static int gaim_parse_msgerr(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; char *destn; guint16 reason; - char buf[1024]; va_start(ap, fr); reason = (guint16)va_arg(ap, unsigned int); destn = va_arg(ap, char *); va_end(ap); - sprintf(buf, _("Your message to %s did not get sent: %s"), destn, + imcb_error(sess->aux_data, _("Your message to %s did not get sent: %s"), destn, (reason < msgerrreasonlen) ? msgerrreason[reason] : _("Reason unknown")); - do_error_dialog(sess->aux_data, buf, _("Gaim - Error")); return 1; } @@ -1397,17 +1356,14 @@ static int gaim_parse_locerr(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; char *destn; guint16 reason; - char buf[1024]; va_start(ap, fr); reason = (guint16)va_arg(ap, unsigned int); destn = va_arg(ap, char *); va_end(ap); - sprintf(buf, _("User information for %s unavailable: %s"), destn, + imcb_error(sess->aux_data, _("User information for %s unavailable: %s"), destn, (reason < msgerrreasonlen) ? msgerrreason[reason] : _("Reason unknown")); - do_error_dialog(sess->aux_data, buf, _("Gaim - Error")); - return 1; } @@ -1423,8 +1379,7 @@ static int gaim_parse_motd(aim_session_t *sess, aim_frame_t *fr, ...) { va_end(ap); if (id < 4) - do_error_dialog(sess->aux_data, _("Your connection may be lost."), - _("AOL error")); + imcb_error(sess->aux_data, _("Your connection may be lost.")); return 1; } @@ -1432,8 +1387,8 @@ static int gaim_parse_motd(aim_session_t *sess, aim_frame_t *fr, ...) { static int gaim_chatnav_info(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; guint16 type; - struct gaim_connection *gc = sess->aux_data; - struct oscar_data *odata = (struct oscar_data *)gc->proto_data; + struct im_connection *ic = sess->aux_data; + struct oscar_data *odata = (struct oscar_data *)ic->proto_data; va_start(ap, fr); type = (guint16)va_arg(ap, unsigned int); @@ -1491,7 +1446,7 @@ static int gaim_chat_join(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; int count, i; aim_userinfo_t *info; - struct gaim_connection *g = sess->aux_data; + struct im_connection *g = sess->aux_data; struct chat_connection *c = NULL; @@ -1505,7 +1460,7 @@ static int gaim_chat_join(aim_session_t *sess, aim_frame_t *fr, ...) { return 1; for (i = 0; i < count; i++) - add_chat_buddy(c->cnv, info[i].sn); + imcb_chat_add_buddy(c->cnv, info[i].sn); return 1; } @@ -1514,7 +1469,7 @@ static int gaim_chat_leave(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; int count, i; aim_userinfo_t *info; - struct gaim_connection *g = sess->aux_data; + struct im_connection *g = sess->aux_data; struct chat_connection *c = NULL; @@ -1528,7 +1483,7 @@ static int gaim_chat_leave(aim_session_t *sess, aim_frame_t *fr, ...) { return 1; for (i = 0; i < count; i++) - remove_chat_buddy(c->cnv, info[i].sn, NULL); + imcb_chat_remove_buddy(c->cnv, info[i].sn, NULL); return 1; } @@ -1542,8 +1497,8 @@ static int gaim_chat_info_update(aim_session_t *sess, aim_frame_t *fr, ...) { char *roomdesc; guint16 unknown_c9, unknown_d2, unknown_d5, maxmsglen, maxvisiblemsglen; guint32 creationtime; - struct gaim_connection *gc = sess->aux_data; - struct chat_connection *ccon = find_oscar_chat_by_conn(gc, fr->conn); + struct im_connection *ic = sess->aux_data; + struct chat_connection *ccon = find_oscar_chat_by_conn(ic, fr->conn); va_start(ap, fr); roominfo = va_arg(ap, struct aim_chat_roominfo *); @@ -1569,8 +1524,8 @@ static int gaim_chat_incoming_msg(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; aim_userinfo_t *info; char *msg; - struct gaim_connection *gc = sess->aux_data; - struct chat_connection *ccon = find_oscar_chat_by_conn(gc, fr->conn); + struct im_connection *ic = sess->aux_data; + struct chat_connection *ccon = find_oscar_chat_by_conn(ic, fr->conn); char *tmp; va_start(ap, fr); @@ -1579,7 +1534,7 @@ static int gaim_chat_incoming_msg(aim_session_t *sess, aim_frame_t *fr, ...) { tmp = g_malloc(BUF_LONG); g_snprintf(tmp, BUF_LONG, "%s", msg); - serv_got_chat_in(gc, ccon->id, info->sn, 0, tmp, time((time_t)NULL)); + imcb_chat_msg(ccon->cnv, info->sn, tmp, 0, 0); g_free(tmp); return 1; @@ -1618,8 +1573,8 @@ static int gaim_parse_ratechange(aim_session_t *sess, aim_frame_t *fr, ...) { } else if (code == AIM_RATE_CODE_WARNING) { aim_conn_setlatency(fr->conn, windowsize/4); } else if (code == AIM_RATE_CODE_LIMIT) { - do_error_dialog(sess->aux_data, _("The last message was not sent because you are over the rate limit. " - "Please wait 10 seconds and try again."), _("Gaim - Error")); + imcb_error(sess->aux_data, _("The last message was not sent because you are over the rate limit. " + "Please wait 10 seconds and try again.")); aim_conn_setlatency(fr->conn, windowsize/2); } else if (code == AIM_RATE_CODE_CLEARLIMIT) { aim_conn_setlatency(fr->conn, 0); @@ -1631,14 +1586,14 @@ static int gaim_parse_ratechange(aim_session_t *sess, aim_frame_t *fr, ...) { static int gaim_selfinfo(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; aim_userinfo_t *info; - struct gaim_connection *gc = sess->aux_data; + struct im_connection *ic = sess->aux_data; va_start(ap, fr); info = va_arg(ap, aim_userinfo_t *); va_end(ap); - gc->evil = info->warnlevel/10; - /* gc->correction_time = (info->onlinesince - gc->login_time); */ + ic->evil = info->warnlevel/10; + /* ic->correction_time = (info->onlinesince - ic->login_time); */ return 1; } @@ -1660,8 +1615,8 @@ static int conninitdone_bos(aim_session_t *sess, aim_frame_t *fr, ...) { } static int conninitdone_admin(aim_session_t *sess, aim_frame_t *fr, ...) { - struct gaim_connection *gc = sess->aux_data; - struct oscar_data *od = gc->proto_data; + struct im_connection *ic = sess->aux_data; + struct oscar_data *od = ic->proto_data; aim_clientready(sess, fr->conn); @@ -1718,8 +1673,8 @@ static int gaim_parse_locaterights(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; guint16 maxsiglen; - struct gaim_connection *gc = sess->aux_data; - struct oscar_data *odata = (struct oscar_data *)gc->proto_data; + struct im_connection *ic = sess->aux_data; + struct oscar_data *odata = (struct oscar_data *)ic->proto_data; va_start(ap, fr); maxsiglen = va_arg(ap, int); @@ -1729,7 +1684,7 @@ static int gaim_parse_locaterights(aim_session_t *sess, aim_frame_t *fr, ...) /* FIXME: It seems we're not really using this, and it broke now that struct aim_user is dead. - aim_bos_setprofile(sess, fr->conn, gc->user->user_info, NULL, gaim_caps); + aim_bos_setprofile(sess, fr->conn, ic->user->user_info, NULL, gaim_caps); */ return 1; @@ -1738,8 +1693,8 @@ static int gaim_parse_locaterights(aim_session_t *sess, aim_frame_t *fr, ...) static int gaim_parse_buddyrights(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; guint16 maxbuddies, maxwatchers; - struct gaim_connection *gc = sess->aux_data; - struct oscar_data *odata = (struct oscar_data *)gc->proto_data; + struct im_connection *ic = sess->aux_data; + struct oscar_data *odata = (struct oscar_data *)ic->proto_data; va_start(ap, fr); maxbuddies = (guint16)va_arg(ap, unsigned int); @@ -1755,8 +1710,8 @@ static int gaim_parse_buddyrights(aim_session_t *sess, aim_frame_t *fr, ...) { static int gaim_bosrights(aim_session_t *sess, aim_frame_t *fr, ...) { guint16 maxpermits, maxdenies; va_list ap; - struct gaim_connection *gc = sess->aux_data; - struct oscar_data *odata = (struct oscar_data *)gc->proto_data; + struct im_connection *ic = sess->aux_data; + struct oscar_data *odata = (struct oscar_data *)ic->proto_data; va_start(ap, fr); maxpermits = (guint16)va_arg(ap, unsigned int); @@ -1779,7 +1734,7 @@ static int gaim_bosrights(aim_session_t *sess, aim_frame_t *fr, ...) { static int gaim_offlinemsg(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; struct aim_icq_offlinemsg *msg; - struct gaim_connection *gc = sess->aux_data; + struct im_connection *ic = sess->aux_data; va_start(ap, fr); msg = va_arg(ap, struct aim_icq_offlinemsg *); @@ -1792,7 +1747,7 @@ static int gaim_offlinemsg(aim_session_t *sess, aim_frame_t *fr, ...) { time_t t = get_time(msg->year, msg->month, msg->day, msg->hour, msg->minute, 0); g_snprintf(sender, sizeof(sender), "%u", msg->sender); strip_linefeed(dialog_msg); - serv_got_im(gc, sender, dialog_msg, 0, t, -1); + imcb_buddy_msg(ic, sender, dialog_msg, 0, t); g_free(dialog_msg); } break; @@ -1813,21 +1768,21 @@ static int gaim_offlinemsg(aim_session_t *sess, aim_frame_t *fr, ...) { } strip_linefeed(dialog_msg); - serv_got_im(gc, sender, dialog_msg, 0, t, -1); + imcb_buddy_msg(ic, sender, dialog_msg, 0, t); g_free(dialog_msg); g_free(m); } break; case 0x0006: { /* Authorization request */ - gaim_icq_authask(gc, msg->sender, msg->msg); + gaim_icq_authask(ic, msg->sender, msg->msg); } break; case 0x0007: { /* Someone has denied you authorization */ - serv_got_crap(sess->aux_data, "The user %u has denied your request to add them to your contact list for the following reason:\n%s", msg->sender, msg->msg ? msg->msg : _("No reason given.") ); + imcb_log(sess->aux_data, "The user %u has denied your request to add them to your contact list for the following reason:\n%s", msg->sender, msg->msg ? msg->msg : _("No reason given.") ); } break; case 0x0008: { /* Someone has granted you authorization */ - serv_got_crap(sess->aux_data, "The user %u has granted your request to add them to your contact list for the following reason:\n%s", msg->sender, msg->msg ? msg->msg : _("No reason given.") ); + imcb_log(sess->aux_data, "The user %u has granted your request to add them to your contact list for the following reason:\n%s", msg->sender, msg->msg ? msg->msg : _("No reason given.") ); } break; case 0x0012: { @@ -1847,15 +1802,15 @@ static int gaim_offlinemsgdone(aim_session_t *sess, aim_frame_t *fr, ...) return 1; } -static void oscar_keepalive(struct gaim_connection *gc) { - struct oscar_data *odata = (struct oscar_data *)gc->proto_data; +static void oscar_keepalive(struct im_connection *ic) { + struct oscar_data *odata = (struct oscar_data *)ic->proto_data; aim_flap_nop(odata->sess, odata->conn); } -static int oscar_send_im(struct gaim_connection *gc, char *name, char *message, int len, int imflags) { - struct oscar_data *odata = (struct oscar_data *)gc->proto_data; - int ret = 0; - if (imflags & IM_FLAG_AWAY) { +static int oscar_buddy_msg(struct im_connection *ic, char *name, char *message, int imflags) { + struct oscar_data *odata = (struct oscar_data *)ic->proto_data; + int ret = 0, len = strlen(message); + if (imflags & OPT_AWAY) { ret = aim_send_im(odata->sess, name, AIM_IMFLAGS_AWAY, message); } else { struct aim_sendimext_args args; @@ -1906,7 +1861,7 @@ static int oscar_send_im(struct gaim_connection *gc, char *name, char *message, return ret; } -static void oscar_get_info(struct gaim_connection *g, char *name) { +static void oscar_get_info(struct im_connection *g, char *name) { struct oscar_data *odata = (struct oscar_data *)g->proto_data; if (odata->icq) aim_icq_getallinfo(odata->sess, name); @@ -1916,10 +1871,10 @@ static void oscar_get_info(struct gaim_connection *g, char *name) { } } -static void oscar_get_away(struct gaim_connection *g, char *who) { +static void oscar_get_away(struct im_connection *g, char *who) { struct oscar_data *odata = (struct oscar_data *)g->proto_data; if (odata->icq) { - struct buddy *budlight = find_buddy(g, who); + struct buddy *budlight = imcb_find_buddy(g, who); if (budlight) if ((budlight->uc & 0xff80) >> 7) if (budlight->caps & AIM_CAPS_ICQSERVERRELAY) @@ -1928,7 +1883,7 @@ static void oscar_get_away(struct gaim_connection *g, char *who) { aim_getinfo(odata->sess, odata->conn, who, AIM_GETINFO_AWAYMESSAGE); } -static void oscar_set_away_aim(struct gaim_connection *gc, struct oscar_data *od, const char *state, const char *message) +static void oscar_set_away_aim(struct im_connection *ic, struct oscar_data *od, const char *state, const char *message) { if (!g_strcasecmp(state, _("Visible"))) { @@ -1940,13 +1895,13 @@ static void oscar_set_away_aim(struct gaim_connection *gc, struct oscar_data *od } /* else... */ if (od->rights.maxawaymsglen == 0) - do_error_dialog(gc, "oscar_set_away_aim called before locate rights received", "Protocol Error"); + imcb_error(ic, "oscar_set_away_aim called before locate rights received"); aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_NORMAL); - if (gc->away) - g_free(gc->away); - gc->away = NULL; + if (ic->away) + g_free(ic->away); + ic->away = NULL; if (!message) { aim_bos_setprofile(od->sess, od->conn, NULL, "", gaim_caps); @@ -1954,30 +1909,24 @@ static void oscar_set_away_aim(struct gaim_connection *gc, struct oscar_data *od } if (strlen(message) > od->rights.maxawaymsglen) { - gchar *errstr; - - errstr = g_strdup_printf("Maximum away message length of %d bytes exceeded, truncating", od->rights.maxawaymsglen); - - do_error_dialog(gc, errstr, "Away Message Too Long"); - - g_free(errstr); + imcb_error(ic, "Maximum away message length of %d bytes exceeded, truncating", od->rights.maxawaymsglen); } - gc->away = g_strndup(message, od->rights.maxawaymsglen); - aim_bos_setprofile(od->sess, od->conn, NULL, gc->away, gaim_caps); + ic->away = g_strndup(message, od->rights.maxawaymsglen); + aim_bos_setprofile(od->sess, od->conn, NULL, ic->away, gaim_caps); return; } -static void oscar_set_away_icq(struct gaim_connection *gc, struct oscar_data *od, const char *state, const char *message) +static void oscar_set_away_icq(struct im_connection *ic, struct oscar_data *od, const char *state, const char *message) { const char *msg = NULL; gboolean no_message = FALSE; /* clean old states */ - if (gc->away) { - g_free(gc->away); - gc->away = NULL; + if (ic->away) { + g_free(ic->away); + ic->away = NULL; } od->sess->aim_icq_state = 0; @@ -1993,33 +1942,33 @@ static void oscar_set_away_icq(struct gaim_connection *gc, struct oscar_data *od aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_NORMAL); } else if (!g_strcasecmp(state, "Away")) { aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_AWAY); - gc->away = g_strdup(msg); + ic->away = g_strdup(msg); od->sess->aim_icq_state = AIM_MTYPE_AUTOAWAY; } else if (!g_strcasecmp(state, "Do Not Disturb")) { aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_DND | AIM_ICQ_STATE_BUSY); - gc->away = g_strdup(msg); + ic->away = g_strdup(msg); od->sess->aim_icq_state = AIM_MTYPE_AUTODND; } else if (!g_strcasecmp(state, "Not Available")) { aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_OUT | AIM_ICQ_STATE_AWAY); - gc->away = g_strdup(msg); + ic->away = g_strdup(msg); od->sess->aim_icq_state = AIM_MTYPE_AUTONA; } else if (!g_strcasecmp(state, "Occupied")) { aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_BUSY); - gc->away = g_strdup(msg); + ic->away = g_strdup(msg); od->sess->aim_icq_state = AIM_MTYPE_AUTOBUSY; } else if (!g_strcasecmp(state, "Free For Chat")) { aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_CHAT); - gc->away = g_strdup(msg); + ic->away = g_strdup(msg); od->sess->aim_icq_state = AIM_MTYPE_AUTOFFC; } else if (!g_strcasecmp(state, "Invisible")) { aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_INVISIBLE); - gc->away = g_strdup(msg); + ic->away = g_strdup(msg); } else if (!g_strcasecmp(state, GAIM_AWAY_CUSTOM)) { if (no_message) { aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_NORMAL); } else { aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_AWAY); - gc->away = g_strdup(msg); + ic->away = g_strdup(msg); od->sess->aim_icq_state = AIM_MTYPE_AUTOAWAY; } } @@ -2027,23 +1976,23 @@ static void oscar_set_away_icq(struct gaim_connection *gc, struct oscar_data *od return; } -static void oscar_set_away(struct gaim_connection *gc, char *state, char *message) +static void oscar_set_away(struct im_connection *ic, char *state, char *message) { - struct oscar_data *od = (struct oscar_data *)gc->proto_data; + struct oscar_data *od = (struct oscar_data *)ic->proto_data; - oscar_set_away_aim(gc, od, state, message); + oscar_set_away_aim(ic, od, state, message); if (od->icq) - oscar_set_away_icq(gc, od, state, message); + oscar_set_away_icq(ic, od, state, message); return; } -static void oscar_add_buddy(struct gaim_connection *g, char *name) { +static void oscar_add_buddy(struct im_connection *g, char *name, char *group) { struct oscar_data *odata = (struct oscar_data *)g->proto_data; aim_ssi_addbuddies(odata->sess, odata->conn, OSCAR_GROUP, &name, 1, 0); } -static void oscar_remove_buddy(struct gaim_connection *g, char *name, char *group) { +static void oscar_remove_buddy(struct im_connection *g, char *name, char *group) { struct oscar_data *odata = (struct oscar_data *)g->proto_data; struct aim_ssi_item *ssigroup; while ((ssigroup = aim_ssi_itemlist_findparent(odata->sess->ssi.items, name)) && !aim_ssi_delbuddies(odata->sess, odata->conn, ssigroup->name, &name, 1)); @@ -2054,7 +2003,7 @@ static int gaim_ssi_parserights(aim_session_t *sess, aim_frame_t *fr, ...) { } static int gaim_ssi_parselist(aim_session_t *sess, aim_frame_t *fr, ...) { - struct gaim_connection *gc = sess->aux_data; + struct im_connection *ic = sess->aux_data; struct aim_ssi_item *curitem; int tmp; @@ -2063,27 +2012,29 @@ static int gaim_ssi_parselist(aim_session_t *sess, aim_frame_t *fr, ...) { for (curitem=sess->ssi.items; curitem; curitem=curitem->next) { switch (curitem->type) { case 0x0000: /* Buddy */ - if ((curitem->name) && (!find_buddy(gc, curitem->name))) { + if ((curitem->name) && (!imcb_find_buddy(ic, curitem->name))) { char *realname = NULL; if (curitem->data && aim_gettlv(curitem->data, 0x0131, 1)) realname = aim_gettlv_str(curitem->data, 0x0131, 1); - add_buddy(gc, NULL, curitem->name, realname); + imcb_add_buddy(ic, curitem->name, NULL); - if (realname) - g_free(realname); + if (realname) { + imcb_rename_buddy(ic, curitem->name, realname); + g_free(realname); + } } break; case 0x0002: /* Permit buddy */ if (curitem->name) { GSList *list; - for (list=gc->permit; (list && aim_sncmp(curitem->name, list->data)); list=list->next); + for (list=ic->permit; (list && aim_sncmp(curitem->name, list->data)); list=list->next); if (!list) { char *name; name = g_strdup(normalize(curitem->name)); - gc->permit = g_slist_append(gc->permit, name); + ic->permit = g_slist_append(ic->permit, name); tmp++; } } @@ -2092,11 +2043,11 @@ static int gaim_ssi_parselist(aim_session_t *sess, aim_frame_t *fr, ...) { case 0x0003: /* Deny buddy */ if (curitem->name) { GSList *list; - for (list=gc->deny; (list && aim_sncmp(curitem->name, list->data)); list=list->next); + for (list=ic->deny; (list && aim_sncmp(curitem->name, list->data)); list=list->next); if (!list) { char *name; name = g_strdup(normalize(curitem->name)); - gc->deny = g_slist_append(gc->deny, name); + ic->deny = g_slist_append(ic->deny, name); tmp++; } } @@ -2105,8 +2056,8 @@ static int gaim_ssi_parselist(aim_session_t *sess, aim_frame_t *fr, ...) { case 0x0004: /* Permit/deny setting */ if (curitem->data) { guint8 permdeny; - if ((permdeny = aim_ssi_getpermdeny(sess->ssi.items)) && (permdeny != gc->permdeny)) { - gc->permdeny = permdeny; + if ((permdeny = aim_ssi_getpermdeny(sess->ssi.items)) && (permdeny != ic->permdeny)) { + ic->permdeny = permdeny; tmp++; } } @@ -2124,7 +2075,7 @@ static int gaim_ssi_parselist(aim_session_t *sess, aim_frame_t *fr, ...) { aim_icq_reqofflinemsgs(sess); /* Now that we have a buddy list, we can tell BitlBee that we're online. */ - account_online(gc); + imcb_connected(ic); return 1; } @@ -2146,7 +2097,7 @@ static int gaim_ssi_parseack( aim_session_t *sess, aim_frame_t *fr, ... ) if( count & 1 ) { /* Hmm, the length should be even... */ - do_error_dialog( sess->aux_data, "Received SSI ACK package with non-even length", "Gaim - Error" ); + imcb_error( sess->aux_data, "Received SSI ACK package with non-even length"); return( 0 ); } count >>= 1; @@ -2155,13 +2106,21 @@ static int gaim_ssi_parseack( aim_session_t *sess, aim_frame_t *fr, ... ) for( i = 0; i < count; i ++ ) { st = aimbs_get16( &fr->data ); - if( st == 0x0E ) + if( st == 0x00 ) + { + imcb_add_buddy( sess->aux_data, list, NULL ); + } + else if( st == 0x0E ) { - serv_got_crap( sess->aux_data, "Buddy %s can't be added without authorization, requesting authorization", list ); + imcb_log( sess->aux_data, "Buddy %s can't be added without authorization, requesting authorization", list ); aim_ssi_auth_request( sess, fr->conn, list, "" ); aim_ssi_addbuddies( sess, fr->conn, OSCAR_GROUP, &list, 1, 1 ); } + else + { + imcb_error( sess->aux_data, "Error while adding buddy: 0x%04x", st ); + } list += strlen( list ) + 1; } } @@ -2169,22 +2128,22 @@ static int gaim_ssi_parseack( aim_session_t *sess, aim_frame_t *fr, ... ) return( 1 ); } -static void oscar_set_permit_deny(struct gaim_connection *gc) { - struct oscar_data *od = (struct oscar_data *)gc->proto_data; +static void oscar_set_permit_deny(struct im_connection *ic) { + struct oscar_data *od = (struct oscar_data *)ic->proto_data; if (od->icq) { GSList *list; char buf[MAXMSGLEN]; int at; - switch(gc->permdeny) { + switch(ic->permdeny) { case 1: - aim_bos_changevisibility(od->sess, od->conn, AIM_VISIBILITYCHANGE_DENYADD, gc->username); + aim_bos_changevisibility(od->sess, od->conn, AIM_VISIBILITYCHANGE_DENYADD, ic->acc->user); break; case 2: - aim_bos_changevisibility(od->sess, od->conn, AIM_VISIBILITYCHANGE_PERMITADD, gc->username); + aim_bos_changevisibility(od->sess, od->conn, AIM_VISIBILITYCHANGE_PERMITADD, ic->acc->user); break; case 3: - list = gc->permit; + list = ic->permit; at = 0; while (list) { at += g_snprintf(buf + at, sizeof(buf) - at, "%s&", (char *)list->data); @@ -2193,7 +2152,7 @@ static void oscar_set_permit_deny(struct gaim_connection *gc) { aim_bos_changevisibility(od->sess, od->conn, AIM_VISIBILITYCHANGE_PERMITADD, buf); break; case 4: - list = gc->deny; + list = ic->deny; at = 0; while (list) { at += g_snprintf(buf + at, sizeof(buf) - at, "%s&", (char *)list->data); @@ -2204,15 +2163,14 @@ static void oscar_set_permit_deny(struct gaim_connection *gc) { default: break; } - signoff_blocked(gc); } else { if (od->sess->ssi.received_data) - aim_ssi_setpermdeny(od->sess, od->conn, gc->permdeny, 0xffffffff); + aim_ssi_setpermdeny(od->sess, od->conn, ic->permdeny, 0xffffffff); } } -static void oscar_add_permit(struct gaim_connection *gc, char *who) { - struct oscar_data *od = (struct oscar_data *)gc->proto_data; +static void oscar_add_permit(struct im_connection *ic, char *who) { + struct oscar_data *od = (struct oscar_data *)ic->proto_data; if (od->icq) { aim_ssi_auth_reply(od->sess, od->conn, who, 1, ""); } else { @@ -2221,8 +2179,8 @@ static void oscar_add_permit(struct gaim_connection *gc, char *who) { } } -static void oscar_add_deny(struct gaim_connection *gc, char *who) { - struct oscar_data *od = (struct oscar_data *)gc->proto_data; +static void oscar_add_deny(struct im_connection *ic, char *who) { + struct oscar_data *od = (struct oscar_data *)ic->proto_data; if (od->icq) { aim_ssi_auth_reply(od->sess, od->conn, who, 0, ""); } else { @@ -2231,25 +2189,25 @@ static void oscar_add_deny(struct gaim_connection *gc, char *who) { } } -static void oscar_rem_permit(struct gaim_connection *gc, char *who) { - struct oscar_data *od = (struct oscar_data *)gc->proto_data; +static void oscar_rem_permit(struct im_connection *ic, char *who) { + struct oscar_data *od = (struct oscar_data *)ic->proto_data; if (!od->icq) { if (od->sess->ssi.received_data) aim_ssi_delpord(od->sess, od->conn, &who, 1, AIM_SSI_TYPE_PERMIT); } } -static void oscar_rem_deny(struct gaim_connection *gc, char *who) { - struct oscar_data *od = (struct oscar_data *)gc->proto_data; +static void oscar_rem_deny(struct im_connection *ic, char *who) { + struct oscar_data *od = (struct oscar_data *)ic->proto_data; if (!od->icq) { if (od->sess->ssi.received_data) aim_ssi_delpord(od->sess, od->conn, &who, 1, AIM_SSI_TYPE_DENY); } } -static GList *oscar_away_states(struct gaim_connection *gc) +static GList *oscar_away_states(struct im_connection *ic) { - struct oscar_data *od = gc->proto_data; + struct oscar_data *od = ic->proto_data; GList *m = NULL; if (!od->icq) @@ -2268,7 +2226,7 @@ static GList *oscar_away_states(struct gaim_connection *gc) static int gaim_icqinfo(aim_session_t *sess, aim_frame_t *fr, ...) { - struct gaim_connection *gc = sess->aux_data; + struct im_connection *ic = sess->aux_data; gchar who[16]; GString *str; va_list ap; @@ -2296,7 +2254,8 @@ static int gaim_icqinfo(aim_session_t *sess, aim_frame_t *fr, ...) } } info_string_append(str, "\n", _("Mobile Phone"), info->mobile); - info_string_append(str, "\n", _("Gender"), info->gender==1 ? _("Female") : info->gender==2 ? _("Male") : _("Unknown")); + if (info->gender != 0) + info_string_append(str, "\n", _("Gender"), info->gender==1 ? _("Female") : _("Male")); if (info->birthyear || info->birthmonth || info->birthday) { char date[30]; struct tm tm; @@ -2344,7 +2303,7 @@ static int gaim_icqinfo(aim_session_t *sess, aim_frame_t *fr, ...) g_string_sprintfa(str, "\n"); } - serv_got_crap(gc, "%s\n%s", _("User Info"), str->str); + imcb_log(ic, "%s\n%s", _("User Info"), str->str); g_string_free(str, TRUE); return 1; @@ -2409,7 +2368,7 @@ static char *oscar_encoding_to_utf8(char *encoding, char *text, int textlen) static int gaim_parseaiminfo(aim_session_t *sess, aim_frame_t *fr, ...) { - struct gaim_connection *gc = sess->aux_data; + struct im_connection *ic = sess->aux_data; va_list ap; aim_userinfo_t *userinfo; guint16 infotype; @@ -2438,18 +2397,18 @@ static int gaim_parseaiminfo(aim_session_t *sess, aim_frame_t *fr, ...) idletime.tm_min = userinfo->idletime % 60; idletime.tm_sec = 0; strftime(buff, 256, _("%d days %H hours %M minutes"), &idletime); - serv_got_crap(gc, "%s: %s", _("Idle Time"), buff); + imcb_log(ic, "%s: %s", _("Idle Time"), buff); } if(text) { utf8 = oscar_encoding_to_utf8(extracted_encoding, text, text_length); - serv_got_crap(gc, "%s\n%s", _("User Info"), utf8); + imcb_log(ic, "%s\n%s", _("User Info"), utf8); } else { - serv_got_crap(gc, _("No user info available.")); + imcb_log(ic, _("No user info available.")); } } else if(infotype == AIM_GETINFO_AWAYMESSAGE && userinfo->flags & AIM_FLAG_AWAY) { utf8 = oscar_encoding_to_utf8(extracted_encoding, text, text_length); - serv_got_crap(gc, "%s\n%s", _("Away Message"), utf8); + imcb_log(ic, "%s\n%s", _("Away Message"), utf8); } g_free(utf8); @@ -2459,7 +2418,7 @@ static int gaim_parseaiminfo(aim_session_t *sess, aim_frame_t *fr, ...) int gaim_parsemtn(aim_session_t *sess, aim_frame_t *fr, ...) { - struct gaim_connection * gc = sess->aux_data; + struct im_connection * ic = sess->aux_data; va_list ap; guint16 type1, type2; char * sn; @@ -2472,65 +2431,37 @@ int gaim_parsemtn(aim_session_t *sess, aim_frame_t *fr, ...) if(type2 == 0x0002) { /* User is typing */ - serv_got_typing(gc, sn, 0, 1); + imcb_buddy_typing(ic, sn, OPT_TYPING); } else if (type2 == 0x0001) { /* User has typed something, but is not actively typing (stale) */ - serv_got_typing(gc, sn, 0, 2); + imcb_buddy_typing(ic, sn, OPT_THINKING); } else { /* User has stopped typing */ - serv_got_typing(gc, sn, 0, 0); + imcb_buddy_typing(ic, sn, 0); } return 1; } -static char *oscar_get_status_string( struct gaim_connection *gc, int number ) +int oscar_send_typing(struct im_connection *ic, char * who, int typing) { - struct oscar_data *od = gc->proto_data; - - if( ! number & UC_UNAVAILABLE ) - { - return( NULL ); - } - else if( od->icq ) - { - number >>= 7; - if( number & AIM_ICQ_STATE_DND ) - return( "Do Not Disturb" ); - else if( number & AIM_ICQ_STATE_OUT ) - return( "Not Available" ); - else if( number & AIM_ICQ_STATE_BUSY ) - return( "Occupied" ); - else if( number & AIM_ICQ_STATE_INVISIBLE ) - return( "Invisible" ); - else - return( "Away" ); - } - else - { - return( "Away" ); - } -} - -int oscar_send_typing(struct gaim_connection *gc, char * who, int typing) -{ - struct oscar_data *od = gc->proto_data; - return( aim_im_sendmtn(od->sess, 1, who, typing ? 0x0002 : 0x0000) ); + struct oscar_data *od = ic->proto_data; + return( aim_im_sendmtn(od->sess, 1, who, (typing & OPT_TYPING) ? 0x0002 : 0x0000) ); } -int oscar_chat_send(struct gaim_connection * gc, int id, char *message) +void oscar_chat_msg(struct groupchat *c, char *message, int msgflags) { - struct oscar_data * od = (struct oscar_data*)gc->proto_data; + struct im_connection *ic = c->ic; + struct oscar_data * od = (struct oscar_data*)ic->proto_data; struct chat_connection * ccon; int ret; guint8 len = strlen(message); guint16 flags; char *s; - if(!(ccon = find_oscar_chat(gc, id))) - return -1; + ccon = c->data; for (s = message; *s; s++) if (*s & 128) @@ -2564,27 +2495,25 @@ int oscar_chat_send(struct gaim_connection * gc, int id, char *message) g_free(s); } - return (ret >= 0); +/* return (ret >= 0); */ } -void oscar_chat_invite(struct gaim_connection * gc, int id, char *message, char *who) +void oscar_chat_invite(struct groupchat *c, char *message, char *who) { - struct oscar_data * od = (struct oscar_data *)gc->proto_data; - struct chat_connection *ccon = find_oscar_chat(gc, id); - - if (ccon == NULL) - return; + struct im_connection *ic = c->ic; + struct oscar_data * od = (struct oscar_data *)ic->proto_data; + struct chat_connection *ccon = c->data; aim_chat_invite(od->sess, od->conn, who, message ? message : "", ccon->exchange, ccon->name, 0x0); } -void oscar_chat_kill(struct gaim_connection *gc, struct chat_connection *cc) +void oscar_chat_kill(struct im_connection *ic, struct chat_connection *cc) { - struct oscar_data *od = (struct oscar_data *)gc->proto_data; + struct oscar_data *od = (struct oscar_data *)ic->proto_data; /* Notify the conversation window that we've left the chat */ - serv_got_chat_left(gc, cc->id); + imcb_chat_removed(cc->cnv); /* Destroy the chat_connection */ od->oscar_chats = g_slist_remove(od->oscar_chats, cc); @@ -2596,57 +2525,55 @@ void oscar_chat_kill(struct gaim_connection *gc, struct chat_connection *cc) g_free(cc); } -void oscar_chat_leave(struct gaim_connection * gc, int id) +void oscar_chat_leave(struct groupchat *c) { - struct chat_connection * ccon = find_oscar_chat(gc, id); - - if(ccon == NULL) - return; - - oscar_chat_kill(gc, ccon); + oscar_chat_kill(c->ic, c->data); } -int oscar_chat_join(struct gaim_connection * gc, char * name) +struct groupchat *oscar_chat_join(struct im_connection * ic, char * room, char * nick, char * password ) { - struct oscar_data * od = (struct oscar_data *)gc->proto_data; - + struct oscar_data * od = (struct oscar_data *)ic->proto_data; aim_conn_t * cur; if((cur = aim_getconn_type(od->sess, AIM_CONN_TYPE_CHATNAV))) { - - return (aim_chatnav_createroom(od->sess, cur, name, 4) == 0); - + int st; + + st = aim_chatnav_createroom(od->sess, cur, room, 4); + + return NULL; } else { struct create_room * cr = g_new0(struct create_room, 1); + cr->exchange = 4; - cr->name = g_strdup(name); + cr->name = g_strdup(room); od->create_rooms = g_slist_append(od->create_rooms, cr); aim_reqservice(od->sess, od->conn, AIM_CONN_TYPE_CHATNAV); - return 1; + + return NULL; } } -int oscar_chat_open(struct gaim_connection * gc, char *who) +struct groupchat *oscar_chat_with(struct im_connection * ic, char *who) { - struct oscar_data * od = (struct oscar_data *)gc->proto_data; - int ret; + struct oscar_data * od = (struct oscar_data *)ic->proto_data; + struct groupchat *ret; static int chat_id = 0; char * chatname; - chatname = g_strdup_printf("%s%d", gc->username, chat_id++); + chatname = g_strdup_printf("%s%d", ic->acc->user, chat_id++); - ret = oscar_chat_join(gc, chatname); + ret = oscar_chat_join(ic, chatname, NULL, NULL); aim_chat_invite(od->sess, od->conn, who, "", 4, chatname, 0x0); g_free(chatname); - return ret; + return NULL; } void oscar_accept_chat(gpointer w, struct aim_chat_invitation * inv) { - oscar_chat_join(inv->gc, inv->name); + oscar_chat_join(inv->ic, inv->name, NULL, NULL); g_free(inv->name); g_free(inv); } @@ -2657,31 +2584,31 @@ void oscar_reject_chat(gpointer w, struct aim_chat_invitation * inv) g_free(inv); } -void oscar_init() +void oscar_initmodule() { struct prpl *ret = g_new0(struct prpl, 1); ret->name = "oscar"; ret->away_states = oscar_away_states; + ret->init = oscar_init; ret->login = oscar_login; - ret->acc_init = oscar_acc_init; - ret->close = oscar_close; - ret->send_im = oscar_send_im; + ret->keepalive = oscar_keepalive; + ret->logout = oscar_logout; + ret->buddy_msg = oscar_buddy_msg; ret->get_info = oscar_get_info; ret->set_away = oscar_set_away; ret->get_away = oscar_get_away; ret->add_buddy = oscar_add_buddy; ret->remove_buddy = oscar_remove_buddy; - ret->chat_send = oscar_chat_send; + ret->chat_msg = oscar_chat_msg; ret->chat_invite = oscar_chat_invite; ret->chat_leave = oscar_chat_leave; - ret->chat_open = oscar_chat_open; + ret->chat_with = oscar_chat_with; + ret->chat_join = oscar_chat_join; ret->add_permit = oscar_add_permit; ret->add_deny = oscar_add_deny; ret->rem_permit = oscar_rem_permit; ret->rem_deny = oscar_rem_deny; ret->set_permit_deny = oscar_set_permit_deny; - ret->keepalive = oscar_keepalive; - ret->get_status_string = oscar_get_status_string; ret->send_typing = oscar_send_typing; ret->handle_cmp = aim_sncmp; diff --git a/protocols/oscar/rxqueue.c b/protocols/oscar/rxqueue.c index 6e8dd29c..34f389af 100644 --- a/protocols/oscar/rxqueue.c +++ b/protocols/oscar/rxqueue.c @@ -391,7 +391,7 @@ int aim_get_command(aim_session_t *sess, aim_conn_t *conn) aim_bstream_rewind(&flaphdr); start = aimbs_get8(&flaphdr); - do_error_dialog(sess->aux_data, "FLAP framing disrupted", "Gaim"); + imcb_error(sess->aux_data, "FLAP framing disrupted"); aim_conn_close(conn); return -1; } diff --git a/protocols/oscar/search.c b/protocols/oscar/search.c index 9685a3d1..3570e4df 100644 --- a/protocols/oscar/search.c +++ b/protocols/oscar/search.c @@ -38,7 +38,7 @@ static int error(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_mo /* XXX the modules interface should have already retrieved this for us */ if (!(snac2 = aim_remsnac(sess, snac->id))) { - do_error_dialog(sess->aux_data, "couldn't get snac", "Gaim"); + imcb_error(sess->aux_data, "couldn't get snac"); return 0; } diff --git a/protocols/oscar/service.c b/protocols/oscar/service.c index d55e0987..3a180780 100644 --- a/protocols/oscar/service.c +++ b/protocols/oscar/service.c @@ -566,7 +566,7 @@ static int migrate(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_ group = aimbs_get16(bs); - do_error_dialog(sess->aux_data, "bifurcated migration unsupported", "Gaim"); + imcb_error(sess->aux_data, "bifurcated migration unsupported"); } tl = aim_readtlvchain(bs); @@ -731,11 +731,11 @@ int aim_setextstatus(aim_session_t *sess, aim_conn_t *conn, guint32 status) aim_tlvlist_t *tl = NULL; guint32 data; int tlvlen; - struct gaim_connection *gc = sess ? sess->aux_data : NULL; + struct im_connection *ic = sess ? sess->aux_data : NULL; data = AIM_ICQ_STATE_HIDEIP | status; /* yay for error checking ;^) */ - if (gc && set_getbool(&gc->acc->set, "web_aware")) + if (ic && set_getbool(&ic->acc->set, "web_aware")) data |= AIM_ICQ_STATE_WEBAWARE; tlvlen = aim_addtlvtochain32(&tl, 0x0006, data); @@ -893,7 +893,7 @@ int aim_sendmemblock(aim_session_t *sess, aim_conn_t *conn, guint32 offset, guin aimbs_put32(&fr->data, 0xecf8427e); */ } else - do_error_dialog(sess->aux_data, "WARNING: unknown hash request", "Gaim"); + imcb_error(sess->aux_data, "WARNING: unknown hash request"); } diff --git a/protocols/oscar/txqueue.c b/protocols/oscar/txqueue.c index 6b4854c5..4416025a 100644 --- a/protocols/oscar/txqueue.c +++ b/protocols/oscar/txqueue.c @@ -29,7 +29,7 @@ aim_frame_t *aim_tx_new(aim_session_t *sess, aim_conn_t *conn, guint8 framing, g aim_frame_t *fr; if (!conn) { - do_error_dialog(sess->aux_data, "no connection specified", "Gaim"); + imcb_error(sess->aux_data, "no connection specified"); return NULL; } @@ -45,7 +45,7 @@ aim_frame_t *aim_tx_new(aim_session_t *sess, aim_conn_t *conn, guint8 framing, g fr->hdr.flap.type = chan; } else - do_error_dialog(sess->aux_data, "unknown framing", "Gaim"); + imcb_error(sess->aux_data, "unknown framing"); if (datalen > 0) { guint8 *data; @@ -79,7 +79,7 @@ static int aim_tx_enqueue__queuebased(aim_session_t *sess, aim_frame_t *fr) { if (!fr->conn) { - do_error_dialog(sess->aux_data, "WARNING: enqueueing packet with no connection", "Gaim"); + imcb_error(sess->aux_data, "WARNING: enqueueing packet with no connection"); fr->conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS); } @@ -119,7 +119,7 @@ static int aim_tx_enqueue__immediate(aim_session_t *sess, aim_frame_t *fr) { if (!fr->conn) { - do_error_dialog(sess->aux_data, "packet has no connection", "Gaim"); + imcb_error(sess->aux_data, "packet has no connection"); aim_frame_destroy(fr); return 0; } diff --git a/protocols/yahoo/libyahoo2.c b/protocols/yahoo/libyahoo2.c index 69b63baa..5beae687 100644 --- a/protocols/yahoo/libyahoo2.c +++ b/protocols/yahoo/libyahoo2.c @@ -104,6 +104,8 @@ void yahoo_register_callbacks(struct yahoo_callbacks * tyc) #define YAHOO_CALLBACK(x) x #endif +static int yahoo_send_data(int fd, void *data, int len); + int yahoo_log_message(char * fmt, ...) { char out[1024]; @@ -203,7 +205,12 @@ enum yahoo_service { /* these are easier to see in hex */ YAHOO_SERVICE_CHATEXIT = 0x9b, YAHOO_SERVICE_CHATLOGOUT = 0xa0, YAHOO_SERVICE_CHATPING, - YAHOO_SERVICE_COMMENT = 0xa8 + YAHOO_SERVICE_COMMENT = 0xa8, + YAHOO_SERVICE_STEALTH = 0xb9, + YAHOO_SERVICE_PICTURE_CHECKSUM = 0xbd, + YAHOO_SERVICE_PICTURE = 0xbe, + YAHOO_SERVICE_PICTURE_UPDATE = 0xc1, + YAHOO_SERVICE_PICTURE_UPLOAD = 0xc2 }; struct yahoo_pair { @@ -740,6 +747,9 @@ static void yahoo_send_packet(struct yahoo_input_data *yid, struct yahoo_packet yahoo_packet_dump(data, len); + if( yid->type == YAHOO_CONNECTION_FT ) + yahoo_send_data(yid->fd, data, len); + else yahoo_add_to_send_queue(yid, data, len); FREE(data); } @@ -925,6 +935,7 @@ static void yahoo_process_notify(struct yahoo_input_data *yid, struct yahoo_pack struct yahoo_data *yd = yid->yd; char *msg = NULL; char *from = NULL; + char *to = NULL; int stat = 0; int accept = 0; char *ind = NULL; @@ -933,6 +944,8 @@ static void yahoo_process_notify(struct yahoo_input_data *yid, struct yahoo_pack struct yahoo_pair *pair = l->data; if (pair->key == 4) from = pair->value; + if (pair->key == 5) + to = pair->value; if (pair->key == 49) msg = pair->value; if (pair->key == 13) @@ -950,19 +963,19 @@ static void yahoo_process_notify(struct yahoo_input_data *yid, struct yahoo_pack return; if (!strncasecmp(msg, "TYPING", strlen("TYPING"))) - YAHOO_CALLBACK(ext_yahoo_typing_notify)(yd->client_id, from, stat); + YAHOO_CALLBACK(ext_yahoo_typing_notify)(yd->client_id, to, from, stat); else if (!strncasecmp(msg, "GAME", strlen("GAME"))) - YAHOO_CALLBACK(ext_yahoo_game_notify)(yd->client_id, from, stat); + YAHOO_CALLBACK(ext_yahoo_game_notify)(yd->client_id, to, from, stat); else if (!strncasecmp(msg, "WEBCAMINVITE", strlen("WEBCAMINVITE"))) { if (!strcmp(ind, " ")) { - YAHOO_CALLBACK(ext_yahoo_webcam_invite)(yd->client_id, from); + YAHOO_CALLBACK(ext_yahoo_webcam_invite)(yd->client_id, to, from); } else { accept = atoi(ind); /* accept the invitation (-1 = deny 1 = accept) */ if (accept < 0) accept = 0; - YAHOO_CALLBACK(ext_yahoo_webcam_invite_reply)(yd->client_id, from, accept); + YAHOO_CALLBACK(ext_yahoo_webcam_invite_reply)(yd->client_id, to, from, accept); } } else @@ -1021,7 +1034,7 @@ static void yahoo_process_filetransfer(struct yahoo_input_data *yid, struct yaho *tmp = '\0'; } if(url && from) - YAHOO_CALLBACK(ext_yahoo_got_file)(yd->client_id, from, url, expires, msg, filename, filesize); + YAHOO_CALLBACK(ext_yahoo_got_file)(yd->client_id, to, from, url, expires, msg, filename, filesize); } @@ -1095,31 +1108,31 @@ static void yahoo_process_conference(struct yahoo_input_data *yid, struct yahoo_ if(pkt->status == 2) ; else if(members) - YAHOO_CALLBACK(ext_yahoo_got_conf_invite)(yd->client_id, host, room, msg, members); + YAHOO_CALLBACK(ext_yahoo_got_conf_invite)(yd->client_id, id, host, room, msg, members); else if(msg) - YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, msg, 0); + YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, msg, 0, E_CONFNOTAVAIL); break; case YAHOO_SERVICE_CONFADDINVITE: if(pkt->status == 2) ; else - YAHOO_CALLBACK(ext_yahoo_got_conf_invite)(yd->client_id, host, room, msg, members); + YAHOO_CALLBACK(ext_yahoo_got_conf_invite)(yd->client_id, id, host, room, msg, members); break; case YAHOO_SERVICE_CONFDECLINE: if(who) - YAHOO_CALLBACK(ext_yahoo_conf_userdecline)(yd->client_id, who, room, msg); + YAHOO_CALLBACK(ext_yahoo_conf_userdecline)(yd->client_id, id, who, room, msg); break; case YAHOO_SERVICE_CONFLOGON: if(who) - YAHOO_CALLBACK(ext_yahoo_conf_userjoin)(yd->client_id, who, room); + YAHOO_CALLBACK(ext_yahoo_conf_userjoin)(yd->client_id, id, who, room); break; case YAHOO_SERVICE_CONFLOGOFF: if(who) - YAHOO_CALLBACK(ext_yahoo_conf_userleave)(yd->client_id, who, room); + YAHOO_CALLBACK(ext_yahoo_conf_userleave)(yd->client_id, id, who, room); break; case YAHOO_SERVICE_CONFMSG: if(who) - YAHOO_CALLBACK(ext_yahoo_conf_message)(yd->client_id, who, room, msg, utf8); + YAHOO_CALLBACK(ext_yahoo_conf_message)(yd->client_id, id, who, room, msg, utf8); break; } } @@ -1127,6 +1140,7 @@ static void yahoo_process_conference(struct yahoo_input_data *yid, struct yahoo_ static void yahoo_process_chat(struct yahoo_input_data *yid, struct yahoo_packet *pkt) { char *msg = NULL; + char *id = NULL; char *who = NULL; char *room = NULL; char *topic = NULL; @@ -1143,6 +1157,11 @@ static void yahoo_process_chat(struct yahoo_input_data *yid, struct yahoo_packet for (l = pkt->hash; l; l = l->next) { struct yahoo_pair *pair = l->data; + if (pair->key == 1) { + /* My identity */ + id = pair->value; + } + if (pair->key == 104) { /* Room name */ room = pair->value; @@ -1217,12 +1236,12 @@ static void yahoo_process_chat(struct yahoo_input_data *yid, struct yahoo_packet if(!room) { if (pkt->service == YAHOO_SERVICE_CHATLOGOUT) { /* yahoo originated chat logout */ - YAHOO_CALLBACK(ext_yahoo_chat_yahoologout)(yid->yd->client_id); + YAHOO_CALLBACK(ext_yahoo_chat_yahoologout)(yid->yd->client_id, id); return ; } if (pkt->service == YAHOO_SERVICE_COMMENT && chaterr) { - YAHOO_CALLBACK(ext_yahoo_chat_yahooerror)(yid->yd->client_id); - return ; + YAHOO_CALLBACK(ext_yahoo_chat_yahooerror)(yid->yd->client_id, id); + return; } WARNING(("We didn't get a room name, ignoring packet")); @@ -1235,7 +1254,7 @@ static void yahoo_process_chat(struct yahoo_input_data *yid, struct yahoo_packet WARNING(("Count of members doesn't match No. of members we got")); } if(firstjoin && members) { - YAHOO_CALLBACK(ext_yahoo_chat_join)(yid->yd->client_id, room, topic, members, yid->fd); + YAHOO_CALLBACK(ext_yahoo_chat_join)(yid->yd->client_id, id, room, topic, members, yid->fd); } else if(who) { if(y_list_length(members) != 1) { WARNING(("Got more than 1 member on a normal join")); @@ -1244,7 +1263,7 @@ static void yahoo_process_chat(struct yahoo_input_data *yid, struct yahoo_packet while(members) { YList *n = members->next; currentmember = members->data; - YAHOO_CALLBACK(ext_yahoo_chat_userjoin)(yid->yd->client_id, room, currentmember); + YAHOO_CALLBACK(ext_yahoo_chat_userjoin)(yid->yd->client_id, id, room, currentmember); y_list_free_1(members); members=n; } @@ -1252,12 +1271,12 @@ static void yahoo_process_chat(struct yahoo_input_data *yid, struct yahoo_packet break; case YAHOO_SERVICE_CHATEXIT: if(who) { - YAHOO_CALLBACK(ext_yahoo_chat_userleave)(yid->yd->client_id, room, who); + YAHOO_CALLBACK(ext_yahoo_chat_userleave)(yid->yd->client_id, id, room, who); } break; case YAHOO_SERVICE_COMMENT: if(who) { - YAHOO_CALLBACK(ext_yahoo_chat_message)(yid->yd->client_id, who, room, msg, msgtype, utf8); + YAHOO_CALLBACK(ext_yahoo_chat_message)(yid->yd->client_id, id, who, room, msg, msgtype, utf8); } break; } @@ -1316,9 +1335,9 @@ static void yahoo_process_message(struct yahoo_input_data *yid, struct yahoo_pac if (pkt->service == YAHOO_SERVICE_SYSMESSAGE) { YAHOO_CALLBACK(ext_yahoo_system_message)(yd->client_id, message->msg); } else if (pkt->status <= 2 || pkt->status == 5) { - YAHOO_CALLBACK(ext_yahoo_got_im)(yd->client_id, message->from, message->msg, message->tm, pkt->status, message->utf8); + YAHOO_CALLBACK(ext_yahoo_got_im)(yd->client_id, message->to, message->from, message->msg, message->tm, pkt->status, message->utf8); } else if (pkt->status == 0xffffffff) { - YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, message->msg, 0); + YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, message->msg, 0, E_SYSTEM); } free(message); } @@ -1331,13 +1350,32 @@ static void yahoo_process_status(struct yahoo_input_data *yid, struct yahoo_pack { YList *l; struct yahoo_data *yd = yid->yd; - char *name = NULL; - int state = 0; - int away = 0; - int idle = 0; - char *msg = NULL; + + struct user + { + char *name; /* 7 name */ + int state; /* 10 state */ + int flags; /* 13 flags, bit 0 = pager, bit 1 = chat, bit 2 = game */ + int mobile; /* 60 mobile */ + char *msg; /* 19 custom status message */ + int away; /* 47 away (or invisible)*/ + int buddy_session; /* 11 state */ + int f17; /* 17 in chat? then what about flags? */ + int idle; /* 137 seconds idle */ + int f138; /* 138 state */ + char *f184; /* 184 state */ + int f192; /* 192 state */ + int f10001; /* 10001 state */ + int f10002; /* 10002 state */ + int f198; /* 198 state */ + char *f197; /* 197 state */ + char *f205; /* 205 state */ + int f213; /* 213 state */ + } *u; + + YList *users = 0; - if(pkt->service == YAHOO_SERVICE_LOGOFF && pkt->status == -1) { + if (pkt->service == YAHOO_SERVICE_LOGOFF && pkt->status == -1) { YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_DUPL, NULL); return; } @@ -1361,51 +1399,87 @@ static void yahoo_process_status(struct yahoo_input_data *yid, struct yahoo_pack NOTICE(("key %d:%s", pair->key, pair->value)); break; case 7: /* the current buddy */ - name = pair->value; + u = y_new0(struct user, 1); + u->name = pair->value; + users = y_list_prepend(users, u); break; case 10: /* state */ - state = strtol(pair->value, NULL, 10); + ((struct user*)users->data)->state = strtol(pair->value, NULL, 10); break; case 19: /* custom status message */ - msg = pair->value; + ((struct user*)users->data)->msg = pair->value; break; case 47: /* is it an away message or not */ - away = atoi(pair->value); + ((struct user*)users->data)->away = atoi(pair->value); break; case 137: /* seconds idle */ - idle = atoi(pair->value); + ((struct user*)users->data)->idle = atoi(pair->value); break; - case 11: /* what is this? */ - NOTICE(("key %d:%s", pair->key, pair->value)); + case 11: /* this is the buddy's session id */ + ((struct user*)users->data)->buddy_session = atoi(pair->value); break; case 17: /* in chat? */ + ((struct user*)users->data)->f17 = atoi(pair->value); break; - case 13: /* in pager? */ - if (pkt->service == YAHOO_SERVICE_LOGOFF || strtol(pair->value, NULL, 10) == 0) { - YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, name, YAHOO_STATUS_OFFLINE, NULL, 1); - break; - } - if (state == YAHOO_STATUS_AVAILABLE) { - YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, name, state, NULL, 0); - } else if (state == YAHOO_STATUS_CUSTOM) { - YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, name, state, msg, away); - } else { - YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, name, state, NULL, idle); - } - + case 13: /* bitmask, bit 0 = pager, bit 1 = chat, bit 2 = game */ + ((struct user*)users->data)->flags = atoi(pair->value); break; - case 60: + case 60: /* SMS -> 1 MOBILE USER */ /* sometimes going offline makes this 2, but invisible never sends it */ - NOTICE(("key %d:%s", pair->key, pair->value)); - break; + ((struct user*)users->data)->mobile = atoi(pair->value); + break; + case 138: + ((struct user*)users->data)->f138 = atoi(pair->value); + break; + case 184: + ((struct user*)users->data)->f184 = pair->value; + break; + case 192: + ((struct user*)users->data)->f192 = atoi(pair->value); + break; + case 10001: + ((struct user*)users->data)->f10001 = atoi(pair->value); + break; + case 10002: + ((struct user*)users->data)->f10002 = atoi(pair->value); + break; + case 198: + ((struct user*)users->data)->f198 = atoi(pair->value); + break; + case 197: + ((struct user*)users->data)->f197 = pair->value; + break; + case 205: + ((struct user*)users->data)->f205 = pair->value; + break; + case 213: + ((struct user*)users->data)->f213 = atoi(pair->value); + break; case 16: /* Custom error message */ - YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, pair->value, 0); + YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, pair->value, 0, E_CUSTOM); break; default: WARNING(("unknown status key %d:%s", pair->key, pair->value)); break; } } + + while (users) { + YList *t = users; + struct user *u = users->data; + + if (u->name != NULL) { + if (pkt->service == YAHOO_SERVICE_LOGOFF || u->flags == 0) { + YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, u->name, YAHOO_STATUS_OFFLINE, NULL, 1, 0, 0); + } else { + YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, u->name, u->state, u->msg, u->away, u->idle, u->mobile); + } + } + + users = y_list_remove_link(users, users); + y_list_free_1(t); + FREE(u); + } } static void yahoo_process_list(struct yahoo_input_data *yid, struct yahoo_packet *pkt) @@ -1511,6 +1585,113 @@ static void yahoo_process_verify(struct yahoo_input_data *yid, struct yahoo_pack } +static void yahoo_process_picture_checksum( struct yahoo_input_data *yid, struct yahoo_packet *pkt) +{ + struct yahoo_data *yd = yid->yd; + char *from = NULL; + char *to = NULL; + int checksum = 0; + YList *l; + + for(l = pkt->hash; l; l = l->next) + { + struct yahoo_pair *pair = l->data; + + switch(pair->key) + { + case 1: + case 4: + from = pair->value; + case 5: + to = pair->value; + break; + case 212: + break; + case 192: + checksum = atoi( pair->value ); + break; + } + } + + YAHOO_CALLBACK(ext_yahoo_got_buddyicon_checksum)(yd->client_id,to,from,checksum); +} + +static void yahoo_process_picture(struct yahoo_input_data *yid, struct yahoo_packet *pkt) +{ + struct yahoo_data *yd = yid->yd; + char *url = NULL; + char *from = NULL; + char *to = NULL; + int status = 0; + int checksum = 0; + YList *l; + + for(l = pkt->hash; l; l = l->next) + { + struct yahoo_pair *pair = l->data; + + switch(pair->key) + { + case 1: + case 4: /* sender */ + from = pair->value; + break; + case 5: /* we */ + to = pair->value; + break; + case 13: /* request / sending */ + status = atoi( pair->value ); + break; + case 20: /* url */ + url = pair->value; + break; + case 192: /*checksum */ + checksum = atoi( pair->value ); + break; + } + } + + switch( status ) + { + case 1: /* this is a request, ignore for now */ + YAHOO_CALLBACK(ext_yahoo_got_buddyicon_request)(yd->client_id, to, from); + break; + case 2: /* this is cool - we get a picture :) */ + YAHOO_CALLBACK(ext_yahoo_got_buddyicon)(yd->client_id,to, from, url, checksum); + break; + } +} + +static void yahoo_process_picture_upload(struct yahoo_input_data *yid, struct yahoo_packet *pkt) +{ + struct yahoo_data *yd = yid->yd; + YList *l; + char *url = NULL; + + if ( pkt->status != 1 ) + return; /* something went wrong */ + + for(l = pkt->hash; l; l = l->next) + { + struct yahoo_pair *pair = l->data; + + switch(pair->key) + { + case 5: /* we */ + break; + case 20: /* url */ + url = pair->value; + break; + case 27: /* local filename */ + break; + case 38: /* time */ + break; + } + } + + YAHOO_CALLBACK(ext_yahoo_buddyicon_uploaded)(yd->client_id, url); +} + static void yahoo_process_auth_pre_0x0b(struct yahoo_input_data *yid, const char *seed, const char *sn) { @@ -2153,6 +2334,8 @@ static void yahoo_process_contact(struct yahoo_input_data *yid, struct yahoo_pac int state = YAHOO_STATUS_AVAILABLE; int online = FALSE; int away = 0; + int idle = 0; + int mobile = 0; YList *l; @@ -2174,12 +2357,17 @@ static void yahoo_process_contact(struct yahoo_input_data *yid, struct yahoo_pac online = strtol(pair->value, NULL, 10); else if (pair->key == 47) away = strtol(pair->value, NULL, 10); + else if (pair->key == 137) + idle = strtol(pair->value, NULL, 10); + else if (pair->key == 60) + mobile = strtol(pair->value, NULL, 10); + } if (id) YAHOO_CALLBACK(ext_yahoo_contact_added)(yd->client_id, id, who, msg); else if (name) - YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, name, state, msg, away); + YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, name, state, msg, away, idle, mobile); else if(pkt->status == 0x07) YAHOO_CALLBACK(ext_yahoo_rejected)(yd->client_id, who, msg); } @@ -2214,12 +2402,19 @@ static void yahoo_process_buddyadd(struct yahoo_input_data *yid, struct yahoo_pa if(!where) where = "Unknown"; - bud = y_new0(struct yahoo_buddy, 1); - bud->id = strdup(who); - bud->group = strdup(where); - bud->real_name = NULL; - - yd->buddies = y_list_append(yd->buddies, bud); + /* status: 0 == Successful, 1 == Error (does not exist), 2 == Already in list */ + if( status == 0 ) { + bud = y_new0(struct yahoo_buddy, 1); + bud->id = strdup(who); + bud->group = strdup(where); + bud->real_name = NULL; + + yd->buddies = y_list_append(yd->buddies, bud); + + /* Possibly called already, but at least the call above doesn't + seem to happen every time (not anytime I tried). */ + YAHOO_CALLBACK(ext_yahoo_contact_added)(yd->client_id, me, who, NULL); + } /* YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, who, status, NULL, (status==YAHOO_STATUS_AVAILABLE?0:1)); */ } @@ -2307,7 +2502,7 @@ static void yahoo_process_ignore(struct yahoo_input_data *yid, struct yahoo_pack */ /* if(status) - YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, status, who, 0); + YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, who, 0, status); */ } @@ -2331,7 +2526,7 @@ static void yahoo_process_voicechat(struct yahoo_input_data *yid, struct yahoo_p room=pair->value; } - NOTICE(("got voice chat invite from %s in %s", who, room)); + NOTICE(("got voice chat invite from %s in %s to identity %s", who, room, me)); /* * send: s:0 1:me 5:who 57:room 13:1 * ???? s:4 5:who 10:99 19:-1615114531 @@ -2343,6 +2538,21 @@ static void yahoo_process_voicechat(struct yahoo_input_data *yid, struct yahoo_p */ } +static void yahoo_process_ping(struct yahoo_input_data *yid, struct yahoo_packet *pkt) +{ + char *errormsg = NULL; + + YList *l; + for (l = pkt->hash; l; l = l->next) { + struct yahoo_pair *pair = l->data; + if (pair->key == 16) + errormsg = pair->value; + } + + NOTICE(("got ping packet")); + YAHOO_CALLBACK(ext_yahoo_got_ping)(yid->yd->client_id, errormsg); +} + static void _yahoo_webcam_get_server_connected(int fd, int error, void *d) { struct yahoo_input_data *yid = d; @@ -2518,6 +2728,9 @@ static void yahoo_packet_process(struct yahoo_input_data *yid, struct yahoo_pack case YAHOO_SERVICE_WEBCAM: yahoo_process_webcam_key(yid, pkt); break; + case YAHOO_SERVICE_PING: + yahoo_process_ping(yid, pkt); + break; case YAHOO_SERVICE_IDLE: case YAHOO_SERVICE_MAILSTAT: case YAHOO_SERVICE_CHATINVITE: @@ -2525,7 +2738,6 @@ static void yahoo_packet_process(struct yahoo_input_data *yid, struct yahoo_pack case YAHOO_SERVICE_NEWPERSONALMAIL: case YAHOO_SERVICE_ADDIDENT: case YAHOO_SERVICE_ADDIGNORE: - case YAHOO_SERVICE_PING: case YAHOO_SERVICE_GOTGROUPRENAME: case YAHOO_SERVICE_GROUPRENAME: case YAHOO_SERVICE_PASSTHROUGH2: @@ -2537,6 +2749,15 @@ static void yahoo_packet_process(struct yahoo_input_data *yid, struct yahoo_pack WARNING(("unhandled service 0x%02x", pkt->service)); yahoo_dump_unhandled(pkt); break; + case YAHOO_SERVICE_PICTURE: + yahoo_process_picture(yid, pkt); + break; + case YAHOO_SERVICE_PICTURE_CHECKSUM: + yahoo_process_picture_checksum(yid, pkt); + break; + case YAHOO_SERVICE_PICTURE_UPLOAD: + yahoo_process_picture_upload(yid, pkt); + break; default: WARNING(("unknown service 0x%02x", pkt->service)); yahoo_dump_unhandled(pkt); @@ -3346,7 +3567,7 @@ int yahoo_read_ready(int id, int fd, void *data) DEBUG_MSG(("len == %d (<= 0)", len)); if(yid->type == YAHOO_CONNECTION_PAGER) { - YAHOO_CALLBACK(ext_yahoo_login_response)(yid->yd->client_id, YAHOO_LOGIN_SOCK, NULL); + YAHOO_CALLBACK(ext_yahoo_error)(yid->yd->client_id, "Connection closed by server", 1, E_CONNECTION); } yahoo_process_connection[yid->type](yid, 1); @@ -3494,11 +3715,12 @@ int yahoo_get_fd(int id) return yid->fd; } -void yahoo_send_im(int id, const char *from, const char *who, const char *what, int utf8) +void yahoo_send_im(int id, const char *from, const char *who, const char *what, int utf8, int picture) { struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER); struct yahoo_packet *pkt = NULL; struct yahoo_data *yd; + char pic_str[10]; if(!yid) return; @@ -3507,6 +3729,8 @@ void yahoo_send_im(int id, const char *from, const char *who, const char *what, pkt = yahoo_packet_new(YAHOO_SERVICE_MESSAGE, YAHOO_STATUS_OFFLINE, yd->session_id); + snprintf(pic_str, sizeof(pic_str), "%d", picture); + if(from && strcmp(from, yd->user)) yahoo_packet_hash(pkt, 0, yd->user); yahoo_packet_hash(pkt, 1, from?from:yd->user); @@ -3518,6 +3742,7 @@ void yahoo_send_im(int id, const char *from, const char *who, const char *what, yahoo_packet_hash(pkt, 63, ";0"); /* imvironment name; or ;0 */ yahoo_packet_hash(pkt, 64, "0"); + yahoo_packet_hash(pkt, 206, pic_str); yahoo_send_packet(yid, pkt, 0); @@ -3570,12 +3795,24 @@ void yahoo_set_away(int id, enum yahoo_status state, const char *msg, int away) service = YAHOO_SERVICE_ISBACK; else service = YAHOO_SERVICE_ISAWAY; - pkt = yahoo_packet_new(service, yd->current_status, yd->session_id); - snprintf(s, sizeof(s), "%d", yd->current_status); - yahoo_packet_hash(pkt, 10, s); - if (yd->current_status == YAHOO_STATUS_CUSTOM) { - yahoo_packet_hash(pkt, 19, msg); - yahoo_packet_hash(pkt, 47, away?"1":"0"); + + if ((away == 2) && (yd->current_status == YAHOO_STATUS_AVAILABLE)) { + pkt = yahoo_packet_new(YAHOO_SERVICE_ISAWAY, YAHOO_STATUS_BRB, yd->session_id); + yahoo_packet_hash(pkt, 10, "999"); + yahoo_packet_hash(pkt, 47, "2"); + }else { + pkt = yahoo_packet_new(service, YAHOO_STATUS_AVAILABLE, yd->session_id); + snprintf(s, sizeof(s), "%d", yd->current_status); + yahoo_packet_hash(pkt, 10, s); + if (yd->current_status == YAHOO_STATUS_CUSTOM) { + yahoo_packet_hash(pkt, 19, msg); + yahoo_packet_hash(pkt, 47, (away == 2)? "2": (away) ?"1":"0"); + } else { + yahoo_packet_hash(pkt, 47, (away == 2)? "2": (away) ?"1":"0"); + } + + + } yahoo_send_packet(yid, pkt, 0); @@ -3816,7 +4053,7 @@ void yahoo_chat_keepalive (int id) yahoo_packet_free (pkt); } -void yahoo_add_buddy(int id, const char *who, const char *group) +void yahoo_add_buddy(int id, const char *who, const char *group, const char *msg) { struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER); struct yahoo_data *yd; @@ -3833,6 +4070,8 @@ void yahoo_add_buddy(int id, const char *who, const char *group) yahoo_packet_hash(pkt, 1, yd->user); yahoo_packet_hash(pkt, 7, who); yahoo_packet_hash(pkt, 65, group); + if (msg != NULL) /* add message/request "it's me add me" */ + yahoo_packet_hash(pkt, 14, msg); yahoo_send_packet(yid, pkt, 0); yahoo_packet_free(pkt); } @@ -3898,6 +4137,28 @@ void yahoo_ignore_buddy(int id, const char *who, int unignore) yahoo_packet_free(pkt); } +void yahoo_stealth_buddy(int id, const char *who, int unstealth) +{ + struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER); + struct yahoo_data *yd; + struct yahoo_packet *pkt; + + if(!yid) + return; + yd = yid->yd; + + if (!yd->logged_in) + return; + + pkt = yahoo_packet_new(YAHOO_SERVICE_STEALTH, YAHOO_STATUS_AVAILABLE, yd->session_id); + yahoo_packet_hash(pkt, 1, yd->user); + yahoo_packet_hash(pkt, 7, who); + yahoo_packet_hash(pkt, 31, unstealth?"2":"1"); + yahoo_packet_hash(pkt, 13, "2"); + yahoo_send_packet(yid, pkt, 0); + yahoo_packet_free(pkt); +} + void yahoo_change_buddy_group(int id, const char *who, const char *old_group, const char *new_group) { struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER); @@ -4206,6 +4467,100 @@ void yahoo_chat_logoff(int id, const char *from) yahoo_packet_free(pkt); } +void yahoo_buddyicon_request(int id, const char *who) +{ + struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER); + struct yahoo_data *yd; + struct yahoo_packet *pkt; + + if( !yid ) + return; + + yd = yid->yd; + + pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE, YAHOO_STATUS_AVAILABLE, 0); + yahoo_packet_hash(pkt, 4, yd->user); + yahoo_packet_hash(pkt, 5, who); + yahoo_packet_hash(pkt, 13, "1"); + yahoo_send_packet(yid, pkt, 0); + + yahoo_packet_free(pkt); +} + +void yahoo_send_picture_info(int id, const char *who, const char *url, int checksum) +{ + struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER); + struct yahoo_data *yd; + struct yahoo_packet *pkt; + char checksum_str[10]; + + if( !yid ) + return; + + yd = yid->yd; + + snprintf(checksum_str, sizeof(checksum_str), "%d", checksum); + + pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE, YAHOO_STATUS_AVAILABLE, 0); + yahoo_packet_hash(pkt, 1, yd->user); + yahoo_packet_hash(pkt, 4, yd->user); + yahoo_packet_hash(pkt, 5, who); + yahoo_packet_hash(pkt, 13, "2"); + yahoo_packet_hash(pkt, 20, url); + yahoo_packet_hash(pkt, 192, checksum_str); + yahoo_send_packet(yid, pkt, 0); + + yahoo_packet_free(pkt); +} + +void yahoo_send_picture_update(int id, const char *who, int type) +{ + struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER); + struct yahoo_data *yd; + struct yahoo_packet *pkt; + char type_str[10]; + + if( !yid ) + return; + + yd = yid->yd; + + snprintf(type_str, sizeof(type_str), "%d", type); + + pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE_UPDATE, YAHOO_STATUS_AVAILABLE, 0); + yahoo_packet_hash(pkt, 1, yd->user); + yahoo_packet_hash(pkt, 5, who); + yahoo_packet_hash(pkt, 206, type_str); + yahoo_send_packet(yid, pkt, 0); + + yahoo_packet_free(pkt); +} + +void yahoo_send_picture_checksum(int id, const char *who, int checksum) +{ + struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER); + struct yahoo_data *yd; + struct yahoo_packet *pkt; + char checksum_str[10]; + + if( !yid ) + return; + + yd = yid->yd; + + snprintf(checksum_str, sizeof(checksum_str), "%d", checksum); + + pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE_CHECKSUM, YAHOO_STATUS_AVAILABLE, 0); + yahoo_packet_hash(pkt, 1, yd->user); + if( who != 0 ) + yahoo_packet_hash(pkt, 5, who); + yahoo_packet_hash(pkt, 192, checksum_str); + yahoo_packet_hash(pkt, 212, "1"); + yahoo_send_packet(yid, pkt, 0); + + yahoo_packet_free(pkt); +} + void yahoo_webcam_close_feed(int id, const char *who) { struct yahoo_input_data *yid = find_input_by_id_and_webcam_user(id, who); @@ -4409,6 +4764,99 @@ struct send_file_data { void *user_data; }; +static void _yahoo_send_picture_connected(int id, int fd, int error, void *data) +{ + struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_FT); + struct send_file_data *sfd = data; + struct yahoo_packet *pkt = sfd->pkt; + unsigned char buff[1024]; + + if(fd <= 0) { + sfd->callback(id, fd, error, sfd->user_data); + FREE(sfd); + yahoo_packet_free(pkt); + inputs = y_list_remove(inputs, yid); + FREE(yid); + return; + } + + yid->fd = fd; + yahoo_send_packet(yid, pkt, 8); + yahoo_packet_free(pkt); + + snprintf((char *)buff, sizeof(buff), "29"); + buff[2] = 0xc0; + buff[3] = 0x80; + + write(yid->fd, buff, 4); + + /* YAHOO_CALLBACK(ext_yahoo_add_handler)(nyd->fd, YAHOO_INPUT_READ); */ + + sfd->callback(id, fd, error, sfd->user_data); + FREE(sfd); + inputs = y_list_remove(inputs, yid); + /* + while(yahoo_tcp_readline(buff, sizeof(buff), nyd->fd) > 0) { + if(!strcmp(buff, "")) + break; +} + + */ + yahoo_input_close(yid); +} + +void yahoo_send_picture(int id, const char *name, unsigned long size, + yahoo_get_fd_callback callback, void *data) +{ + struct yahoo_data *yd = find_conn_by_id(id); + struct yahoo_input_data *yid; + struct yahoo_server_settings *yss; + struct yahoo_packet *pkt = NULL; + char size_str[10]; + char expire_str[10]; + long content_length=0; + unsigned char buff[1024]; + char url[255]; + struct send_file_data *sfd; + + if(!yd) + return; + + yss = yd->server_settings; + + yid = y_new0(struct yahoo_input_data, 1); + yid->yd = yd; + yid->type = YAHOO_CONNECTION_FT; + + pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE_UPLOAD, YAHOO_STATUS_AVAILABLE, yd->session_id); + + snprintf(size_str, sizeof(size_str), "%ld", size); + snprintf(expire_str, sizeof(expire_str), "%ld", (long)604800); + + yahoo_packet_hash(pkt, 0, yd->user); + yahoo_packet_hash(pkt, 1, yd->user); + yahoo_packet_hash(pkt, 14, ""); + yahoo_packet_hash(pkt, 27, name); + yahoo_packet_hash(pkt, 28, size_str); + yahoo_packet_hash(pkt, 38, expire_str); + + + content_length = YAHOO_PACKET_HDRLEN + yahoo_packet_length(pkt); + + snprintf(url, sizeof(url), "http://%s:%d/notifyft", + yss->filetransfer_host, yss->filetransfer_port); + snprintf((char *)buff, sizeof(buff), "Y=%s; T=%s", + yd->cookie_y, yd->cookie_t); + inputs = y_list_prepend(inputs, yid); + + sfd = y_new0(struct send_file_data, 1); + sfd->pkt = pkt; + sfd->callback = callback; + sfd->user_data = data; + yahoo_http_post(yid->yd->client_id, url, (char *)buff, content_length+4+size, + _yahoo_send_picture_connected, sfd); +} + static void _yahoo_send_file_connected(int id, int fd, int error, void *data) { struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_FT); diff --git a/protocols/yahoo/yahoo.c b/protocols/yahoo/yahoo.c index 6f286196..69fc29bb 100644 --- a/protocols/yahoo/yahoo.c +++ b/protocols/yahoo/yahoo.c @@ -57,20 +57,20 @@ struct byahoo_input_data struct byahoo_conf_invitation { char *name; - struct conversation *c; + struct groupchat *c; int yid; YList *members; - struct gaim_connection *gc; + struct im_connection *ic; }; static GSList *byahoo_inputs = NULL; static int byahoo_chat_id = 0; -static char *byahoo_strip( char *in ) +static char *byahoo_strip( const char *in ) { int len; - /* This should get rid of HTML tags at the beginning of the string. */ + /* This should get rid of the markup noise at the beginning of the string. */ while( *in ) { if( g_strncasecmp( in, "<font", 5 ) == 0 || @@ -85,7 +85,7 @@ static char *byahoo_strip( char *in ) } else if( strncmp( in, "\e[", 2 ) == 0 ) { - char *s; + const char *s; for( s = in + 2; *s && *s != 'm'; s ++ ); @@ -100,17 +100,23 @@ static char *byahoo_strip( char *in ) } } - /* This is supposed to get rid of the closing HTML tags at the end of the line. */ + /* This is supposed to get rid of the noise at the end of the line. */ len = strlen( in ); - while( len > 0 && in[len-1] == '>' ) + while( len > 0 && ( in[len-1] == '>' || in[len-1] == 'm' ) ) { int blen = len; + const char *search; - len --; - while( len > 0 && ( in[len] != '<' || in[len+1] != '/' ) ) + if( in[len-1] == '>' ) + search = "</"; + else + search = "\e["; + + len -= 3; + while( len > 0 && strncmp( in + len, search, 2 ) != 0 ) len --; - if( len == 0 && ( in[len] != '<' || in[len+1] != '/' ) ) + if( len <= 0 && strncmp( in, search, 2 ) != 0 ) { len = blen; break; @@ -122,24 +128,24 @@ static char *byahoo_strip( char *in ) static void byahoo_login( account_t *acc ) { - struct gaim_connection *gc = new_gaim_conn( acc ); - struct byahoo_data *yd = gc->proto_data = g_new0( struct byahoo_data, 1 ); + struct im_connection *ic = imcb_new( acc ); + struct byahoo_data *yd = ic->proto_data = g_new0( struct byahoo_data, 1 ); yd->logged_in = FALSE; yd->current_status = YAHOO_STATUS_AVAILABLE; - set_login_progress( gc, 1, "Connecting" ); + imcb_log( ic, "Connecting" ); yd->y2_id = yahoo_init( acc->user, acc->pass ); yahoo_login( yd->y2_id, yd->current_status ); } -static void byahoo_close( struct gaim_connection *gc ) +static void byahoo_logout( struct im_connection *ic ) { - struct byahoo_data *yd = (struct byahoo_data *) gc->proto_data; + struct byahoo_data *yd = (struct byahoo_data *) ic->proto_data; GSList *l; - while( gc->conversations ) - serv_got_chat_left( gc, gc->conversations->id ); + while( ic->conversations ) + imcb_chat_removed( ic->conversations ); for( l = yd->buddygroups; l; l = l->next ) { @@ -159,42 +165,42 @@ static void byahoo_close( struct gaim_connection *gc ) g_free( yd ); } -static void byahoo_get_info(struct gaim_connection *gc, char *who) +static void byahoo_get_info(struct im_connection *ic, char *who) { /* Just make an URL and let the user fetch the info */ - serv_got_crap(gc, "%s\n%s: %s%s", _("User Info"), + imcb_log(ic, "%s\n%s: %s%s", _("User Info"), _("For now, fetch yourself"), yahoo_get_profile_url(), who); } -static int byahoo_send_im( struct gaim_connection *gc, char *who, char *what, int len, int flags ) +static int byahoo_buddy_msg( struct im_connection *ic, char *who, char *what, int flags ) { - struct byahoo_data *yd = gc->proto_data; + struct byahoo_data *yd = ic->proto_data; - yahoo_send_im( yd->y2_id, NULL, who, what, 1 ); + yahoo_send_im( yd->y2_id, NULL, who, what, 1, 0 ); return 1; } -static int byahoo_send_typing( struct gaim_connection *gc, char *who, int typing ) +static int byahoo_send_typing( struct im_connection *ic, char *who, int typing ) { - struct byahoo_data *yd = gc->proto_data; + struct byahoo_data *yd = ic->proto_data; - yahoo_send_typing( yd->y2_id, NULL, who, typing ); + yahoo_send_typing( yd->y2_id, NULL, who, ( typing & OPT_TYPING ) != 0 ); return 1; } -static void byahoo_set_away( struct gaim_connection *gc, char *state, char *msg ) +static void byahoo_set_away( struct im_connection *ic, char *state, char *msg ) { - struct byahoo_data *yd = (struct byahoo_data *) gc->proto_data; + struct byahoo_data *yd = (struct byahoo_data *) ic->proto_data; - gc->away = NULL; + ic->away = NULL; if( state && msg && g_strcasecmp( state, msg ) != 0 ) { yd->current_status = YAHOO_STATUS_CUSTOM; - gc->away = ""; + ic->away = ""; } else if( state ) { @@ -203,11 +209,11 @@ static void byahoo_set_away( struct gaim_connection *gc, char *state, char *msg away state. */ msg = NULL; - gc->away = ""; + ic->away = ""; if( g_strcasecmp( state, "Available" ) == 0 ) { yd->current_status = YAHOO_STATUS_AVAILABLE; - gc->away = NULL; + ic->away = NULL; } else if( g_strcasecmp( state, "Be Right Back" ) == 0 ) yd->current_status = YAHOO_STATUS_BRB; @@ -233,16 +239,16 @@ static void byahoo_set_away( struct gaim_connection *gc, char *state, char *msg { yd->current_status = YAHOO_STATUS_AVAILABLE; - gc->away = NULL; + ic->away = NULL; } } else yd->current_status = YAHOO_STATUS_AVAILABLE; - yahoo_set_away( yd->y2_id, yd->current_status, msg, gc->away != NULL ); + yahoo_set_away( yd->y2_id, yd->current_status, msg, ic->away != NULL ? 2 : 0 ); } -static GList *byahoo_away_states( struct gaim_connection *gc ) +static GList *byahoo_away_states( struct im_connection *ic ) { GList *m = NULL; @@ -262,23 +268,23 @@ static GList *byahoo_away_states( struct gaim_connection *gc ) return m; } -static void byahoo_keepalive( struct gaim_connection *gc ) +static void byahoo_keepalive( struct im_connection *ic ) { - struct byahoo_data *yd = gc->proto_data; + struct byahoo_data *yd = ic->proto_data; yahoo_keepalive( yd->y2_id ); } -static void byahoo_add_buddy( struct gaim_connection *gc, char *who ) +static void byahoo_add_buddy( struct im_connection *ic, char *who, char *group ) { - struct byahoo_data *yd = (struct byahoo_data *) gc->proto_data; + struct byahoo_data *yd = (struct byahoo_data *) ic->proto_data; - yahoo_add_buddy( yd->y2_id, who, BYAHOO_DEFAULT_GROUP ); + yahoo_add_buddy( yd->y2_id, who, group ? group : BYAHOO_DEFAULT_GROUP, NULL ); } -static void byahoo_remove_buddy( struct gaim_connection *gc, char *who, char *group ) +static void byahoo_remove_buddy( struct im_connection *ic, char *who, char *group ) { - struct byahoo_data *yd = (struct byahoo_data *) gc->proto_data; + struct byahoo_data *yd = (struct byahoo_data *) ic->proto_data; GSList *bgl; yahoo_remove_buddy( yd->y2_id, who, BYAHOO_DEFAULT_GROUP ); @@ -292,90 +298,39 @@ static void byahoo_remove_buddy( struct gaim_connection *gc, char *who, char *gr } } -static char *byahoo_get_status_string( struct gaim_connection *gc, int stat ) +static void byahoo_chat_msg( struct groupchat *c, char *message, int flags ) { - enum yahoo_status a = stat >> 1; + struct byahoo_data *yd = (struct byahoo_data *) c->ic->proto_data; - switch (a) - { - case YAHOO_STATUS_BRB: - return "Be Right Back"; - case YAHOO_STATUS_BUSY: - return "Busy"; - case YAHOO_STATUS_NOTATHOME: - return "Not At Home"; - case YAHOO_STATUS_NOTATDESK: - return "Not At Desk"; - case YAHOO_STATUS_NOTINOFFICE: - return "Not In Office"; - case YAHOO_STATUS_ONPHONE: - return "On Phone"; - case YAHOO_STATUS_ONVACATION: - return "On Vacation"; - case YAHOO_STATUS_OUTTOLUNCH: - return "Out To Lunch"; - case YAHOO_STATUS_STEPPEDOUT: - return "Stepped Out"; - case YAHOO_STATUS_INVISIBLE: - return "Invisible"; - case YAHOO_STATUS_CUSTOM: - return "Away"; - case YAHOO_STATUS_IDLE: - return "Idle"; - case YAHOO_STATUS_OFFLINE: - return "Offline"; - case YAHOO_STATUS_NOTIFY: - return "Notify"; - default: - return "Away"; - } -} - -static int byahoo_chat_send( struct gaim_connection *gc, int id, char *message ) -{ - struct byahoo_data *yd = (struct byahoo_data *) gc->proto_data; - struct conversation *c; - - for( c = gc->conversations; c && c->id != id; c = c->next ); - yahoo_conference_message( yd->y2_id, NULL, c->data, c->title, message, 1 ); - - return( 0 ); } -static void byahoo_chat_invite( struct gaim_connection *gc, int id, char *msg, char *who ) +static void byahoo_chat_invite( struct groupchat *c, char *msg, char *who ) { - struct byahoo_data *yd = (struct byahoo_data *) gc->proto_data; - struct conversation *c; - - for( c = gc->conversations; c && c->id != id; c = c->next ); + struct byahoo_data *yd = (struct byahoo_data *) c->ic->proto_data; yahoo_conference_invite( yd->y2_id, NULL, c->data, c->title, msg ); } -static void byahoo_chat_leave( struct gaim_connection *gc, int id ) +static void byahoo_chat_leave( struct groupchat *c ) { - struct byahoo_data *yd = (struct byahoo_data *) gc->proto_data; - struct conversation *c; - - for( c = gc->conversations; c && c->id != id; c = c->next ); + struct byahoo_data *yd = (struct byahoo_data *) c->ic->proto_data; yahoo_conference_logoff( yd->y2_id, NULL, c->data, c->title ); - serv_got_chat_left( gc, c->id ); + imcb_chat_removed( c ); } -static int byahoo_chat_open( struct gaim_connection *gc, char *who ) +static struct groupchat *byahoo_chat_with( struct im_connection *ic, char *who ) { - struct byahoo_data *yd = (struct byahoo_data *) gc->proto_data; - struct conversation *c; + struct byahoo_data *yd = (struct byahoo_data *) ic->proto_data; + struct groupchat *c; char *roomname; YList *members; - roomname = g_new0( char, strlen( gc->username ) + 16 ); - g_snprintf( roomname, strlen( gc->username ) + 16, "%s-Bee-%d", gc->username, byahoo_chat_id ); + roomname = g_strdup_printf( "%s-Bee-%d", ic->acc->user, byahoo_chat_id ); - c = serv_got_joined_chat( gc, ++byahoo_chat_id, roomname ); - add_chat_buddy( c, gc->username ); + c = imcb_chat_new( ic, roomname ); + imcb_chat_add_buddy( c, ic->acc->user ); /* FIXME: Free this thing when the chat's destroyed. We can't *always* do this because it's not always created here. */ @@ -386,49 +341,49 @@ static int byahoo_chat_open( struct gaim_connection *gc, char *who ) g_free( roomname ); - return( 1 ); + return c; } -void byahoo_init( ) +void byahoo_initmodule( ) { struct prpl *ret = g_new0(struct prpl, 1); ret->name = "yahoo"; ret->login = byahoo_login; - ret->close = byahoo_close; - ret->send_im = byahoo_send_im; + ret->keepalive = byahoo_keepalive; + ret->logout = byahoo_logout; + + ret->buddy_msg = byahoo_buddy_msg; ret->get_info = byahoo_get_info; ret->away_states = byahoo_away_states; ret->set_away = byahoo_set_away; - ret->keepalive = byahoo_keepalive; ret->add_buddy = byahoo_add_buddy; ret->remove_buddy = byahoo_remove_buddy; - ret->get_status_string = byahoo_get_status_string; ret->send_typing = byahoo_send_typing; - ret->chat_send = byahoo_chat_send; + ret->chat_msg = byahoo_chat_msg; ret->chat_invite = byahoo_chat_invite; ret->chat_leave = byahoo_chat_leave; - ret->chat_open = byahoo_chat_open; + ret->chat_with = byahoo_chat_with; ret->handle_cmp = g_strcasecmp; register_protocol(ret); } -static struct gaim_connection *byahoo_get_gc_by_id( int id ) +static struct im_connection *byahoo_get_ic_by_id( int id ) { GSList *l; - struct gaim_connection *gc; + struct im_connection *ic; struct byahoo_data *yd; for( l = get_connections(); l; l = l->next ) { - gc = l->data; - yd = gc->proto_data; + ic = l->data; + yd = ic->proto_data; - if( strcmp( gc->acc->prpl->name, "yahoo" ) == 0 && yd->y2_id == id ) - return( gc ); + if( strcmp( ic->acc->prpl->name, "yahoo" ) == 0 && yd->y2_id == id ) + return( ic ); } return( NULL ); @@ -449,7 +404,7 @@ void byahoo_connect_callback( gpointer data, gint source, b_input_condition cond { struct byahoo_connect_callback_data *d = data; - if( !byahoo_get_gc_by_id( d->id ) ) + if( !byahoo_get_ic_by_id( d->id ) ) { g_free( d ); return; @@ -471,7 +426,7 @@ gboolean byahoo_read_ready_callback( gpointer data, gint source, b_input_conditi { struct byahoo_read_ready_data *d = data; - if( !byahoo_get_gc_by_id( d->id ) ) + if( !byahoo_get_ic_by_id( d->id ) ) /* WTF doesn't libyahoo clean this up? */ return FALSE; @@ -492,7 +447,7 @@ gboolean byahoo_write_ready_callback( gpointer data, gint source, b_input_condit { struct byahoo_write_ready_data *d = data; - if( !byahoo_get_gc_by_id( d->id ) ) + if( !byahoo_get_ic_by_id( d->id ) ) /* WTF doesn't libyahoo clean this up? */ return FALSE; @@ -501,12 +456,12 @@ gboolean byahoo_write_ready_callback( gpointer data, gint source, b_input_condit return FALSE; } -void ext_yahoo_login_response( int id, int succ, char *url ) +void ext_yahoo_login_response( int id, int succ, const char *url ) { - struct gaim_connection *gc = byahoo_get_gc_by_id( id ); + struct im_connection *ic = byahoo_get_ic_by_id( id ); struct byahoo_data *yd = NULL; - if( gc == NULL ) + if( ic == NULL ) { /* libyahoo2 seems to call this one twice when something went wrong sometimes. Don't know why. Because we clean @@ -516,18 +471,18 @@ void ext_yahoo_login_response( int id, int succ, char *url ) return; } - yd = (struct byahoo_data *) gc->proto_data; + yd = (struct byahoo_data *) ic->proto_data; if( succ == YAHOO_LOGIN_OK ) { - account_online( gc ); + imcb_connected( ic ); yd->logged_in = TRUE; } else { char *errstr; - char *s; + int allow_reconnect = TRUE; yd->logged_in = FALSE; @@ -540,7 +495,7 @@ void ext_yahoo_login_response( int id, int succ, char *url ) else if( succ == YAHOO_LOGIN_DUPL ) { errstr = "Logged in on a different machine or device"; - gc->wants_to_die = TRUE; + allow_reconnect = FALSE; } else if( succ == YAHOO_LOGIN_SOCK ) errstr = "Socket problem"; @@ -548,31 +503,18 @@ void ext_yahoo_login_response( int id, int succ, char *url ) errstr = "Unknown error"; if( url && *url ) - { - s = g_malloc( strlen( "Error %d (%s). See %s for more information." ) + strlen( url ) + strlen( errstr ) + 16 ); - sprintf( s, "Error %d (%s). See %s for more information.", succ, errstr, url ); - } + imcb_error( ic, "Error %d (%s). See %s for more information.", succ, errstr, url ); else - { - s = g_malloc( strlen( "Error %d (%s)" ) + strlen( errstr ) + 16 ); - sprintf( s, "Error %d (%s)", succ, errstr ); - } - - if( yd->logged_in ) - hide_login_progress_error( gc, s ); - else - hide_login_progress( gc, s ); - - g_free( s ); + imcb_error( ic, "Error %d (%s)", succ, errstr ); - signoff( gc ); + imc_logout( ic, allow_reconnect ); } } void ext_yahoo_got_buddies( int id, YList *buds ) { - struct gaim_connection *gc = byahoo_get_gc_by_id( id ); - struct byahoo_data *yd = gc->proto_data; + struct im_connection *ic = byahoo_get_ic_by_id( id ); + struct byahoo_data *yd = ic->proto_data; YList *bl = buds; while( bl ) @@ -589,7 +531,9 @@ void ext_yahoo_got_buddies( int id, YList *buds ) yd->buddygroups = g_slist_append( yd->buddygroups, bg ); } - add_buddy( gc, b->group, b->id, b->real_name ); + imcb_add_buddy( ic, b->id, b->group ); + imcb_rename_buddy( ic, b->id, b->real_name ); + bl = bl->next; } } @@ -606,71 +550,120 @@ void ext_yahoo_got_cookies( int id ) { } -void ext_yahoo_status_changed( int id, char *who, int stat, char *msg, int away ) +void ext_yahoo_status_changed( int id, const char *who, int stat, const char *msg, int away, int idle, int mobile ) { - struct gaim_connection *gc = byahoo_get_gc_by_id( id ); + struct im_connection *ic = byahoo_get_ic_by_id( id ); + char *state_string = NULL; + int flags = OPT_LOGGED_IN; + + if( away ) + flags |= OPT_AWAY; + + switch (stat) + { + case YAHOO_STATUS_BRB: + state_string = "Be Right Back"; + break; + case YAHOO_STATUS_BUSY: + state_string = "Busy"; + break; + case YAHOO_STATUS_NOTATHOME: + state_string = "Not At Home"; + break; + case YAHOO_STATUS_NOTATDESK: + state_string = "Not At Desk"; + break; + case YAHOO_STATUS_NOTINOFFICE: + state_string = "Not In Office"; + break; + case YAHOO_STATUS_ONPHONE: + state_string = "On Phone"; + break; + case YAHOO_STATUS_ONVACATION: + state_string = "On Vacation"; + break; + case YAHOO_STATUS_OUTTOLUNCH: + state_string = "Out To Lunch"; + break; + case YAHOO_STATUS_STEPPEDOUT: + state_string = "Stepped Out"; + break; + case YAHOO_STATUS_INVISIBLE: + state_string = "Invisible"; + break; + case YAHOO_STATUS_CUSTOM: + state_string = "Away"; + break; + case YAHOO_STATUS_IDLE: + state_string = "Idle"; + break; + case YAHOO_STATUS_OFFLINE: + state_string = "Offline"; + flags = 0; + break; + case YAHOO_STATUS_NOTIFY: + state_string = "Notify"; + break; + } - serv_got_update( gc, who, stat != YAHOO_STATUS_OFFLINE, 0, 0, - ( stat == YAHOO_STATUS_IDLE ) ? away : 0, - ( stat != YAHOO_STATUS_AVAILABLE ) | ( stat << 1 ), 0 ); + imcb_buddy_status( ic, who, flags, state_string, msg ); + + /* Not implemented yet... + if( stat == YAHOO_STATUS_IDLE ) + imcb_buddy_times( ic, who, 0, away ); + */ } -void ext_yahoo_got_im( int id, char *who, char *msg, long tm, int stat, int utf8 ) +void ext_yahoo_got_im( int id, const char *me, const char *who, const char *msg, long tm, int stat, int utf8 ) { - struct gaim_connection *gc = byahoo_get_gc_by_id( id ); + struct im_connection *ic = byahoo_get_ic_by_id( id ); char *m = byahoo_strip( msg ); - serv_got_im( gc, who, m, 0, 0, strlen( m ) ); + imcb_buddy_msg( ic, (char*) who, (char*) m, 0, 0 ); g_free( m ); } -void ext_yahoo_got_file( int id, char *who, char *url, long expires, char *msg, char *fname, unsigned long fesize ) +void ext_yahoo_got_file( int id, + const char *ignored, + const char *who, const char *url, long expires, const char *msg, const char *fname, unsigned long fesize ) { - struct gaim_connection *gc = byahoo_get_gc_by_id( id ); + struct im_connection *ic = byahoo_get_ic_by_id( id ); - serv_got_crap( gc, "Got a file transfer (file = %s) from %s. Ignoring for now due to lack of support.", fname, who ); + imcb_log( ic, "Got a file transfer (file = %s) from %s. Ignoring for now due to lack of support.", fname, who ); } -void ext_yahoo_typing_notify( int id, char *who, int stat ) +void ext_yahoo_typing_notify( int id, const char *ignored, const char *who, int stat ) { - struct gaim_connection *gc = byahoo_get_gc_by_id( id ); - if (stat == 1) { - /* User is typing */ - serv_got_typing( gc, who, 1, 1 ); - } - else { - /* User stopped typing */ - serv_got_typing( gc, who, 1, 0 ); - } + struct im_connection *ic = byahoo_get_ic_by_id( id ); + + if( stat == 1 ) + imcb_buddy_typing( ic, (char*) who, OPT_TYPING ); + else + imcb_buddy_typing( ic, (char*) who, 0 ); } -void ext_yahoo_system_message( int id, char *msg ) +void ext_yahoo_system_message( int id, const char *msg ) { - struct gaim_connection *gc = byahoo_get_gc_by_id( id ); + struct im_connection *ic = byahoo_get_ic_by_id( id ); - serv_got_crap( gc, "Yahoo! system message: %s", msg ); + imcb_log( ic, "Yahoo! system message: %s", msg ); } -void ext_yahoo_webcam_invite( int id, char *from ) +void ext_yahoo_webcam_invite( int id, const char *ignored, const char *from ) { - struct gaim_connection *gc = byahoo_get_gc_by_id( id ); + struct im_connection *ic = byahoo_get_ic_by_id( id ); - serv_got_crap( gc, "Got a webcam invitation from %s. IRC+webcams is a no-no though...", from ); + imcb_log( ic, "Got a webcam invitation from %s. IRC+webcams is a no-no though...", from ); } -void ext_yahoo_error( int id, char *err, int fatal ) +void ext_yahoo_error( int id, const char *err, int fatal, int num ) { - struct gaim_connection *gc = byahoo_get_gc_by_id( id ); + struct im_connection *ic = byahoo_get_ic_by_id( id ); + + imcb_error( ic, "%s", err ); if( fatal ) - { - hide_login_progress_error( gc, err ); - signoff( gc ); - } - else - { - do_error_dialog( gc, err, "Yahoo! error" ); - } + imc_logout( ic, TRUE ); } /* TODO: Clear up the mess of inp and d structures */ @@ -732,7 +725,7 @@ void ext_yahoo_remove_handler( int id, int tag ) b_event_remove( tag ); } -int ext_yahoo_connect_async( int id, char *host, int port, yahoo_connect_callback callback, void *data ) +int ext_yahoo_connect_async( int id, const char *host, int port, yahoo_connect_callback callback, void *data ) { struct byahoo_connect_callback_data *d; int fd; @@ -753,7 +746,7 @@ int ext_yahoo_connect_async( int id, char *host, int port, yahoo_connect_callbac /* Because we don't want asynchronous connects in BitlBee, and because libyahoo doesn't seem to use this one anyway, this one is now defunct. */ -int ext_yahoo_connect(char *host, int port) +int ext_yahoo_connect(const char *host, int port) { #if 0 struct sockaddr_in serv_addr; @@ -796,7 +789,7 @@ int ext_yahoo_connect(char *host, int port) static void byahoo_accept_conf( gpointer w, struct byahoo_conf_invitation *inv ) { yahoo_conference_logon( inv->yid, NULL, inv->members, inv->name ); - add_chat_buddy( inv->c, inv->gc->username ); + imcb_chat_add_buddy( inv->c, inv->ic->acc->user ); g_free( inv->name ); g_free( inv ); } @@ -804,14 +797,15 @@ static void byahoo_accept_conf( gpointer w, struct byahoo_conf_invitation *inv ) static void byahoo_reject_conf( gpointer w, struct byahoo_conf_invitation *inv ) { yahoo_conference_decline( inv->yid, NULL, inv->members, inv->name, "User rejected groupchat" ); - serv_got_chat_left( inv->gc, inv->c->id ); + imcb_chat_removed( inv->c ); g_free( inv->name ); g_free( inv ); } -void ext_yahoo_got_conf_invite( int id, char *who, char *room, char *msg, YList *members ) +void ext_yahoo_got_conf_invite( int id, const char *ignored, + const char *who, const char *room, const char *msg, YList *members ) { - struct gaim_connection *gc = byahoo_get_gc_by_id( id ); + struct im_connection *ic = byahoo_get_ic_by_id( id ); struct byahoo_conf_invitation *inv; char txt[1024]; YList *m; @@ -819,117 +813,126 @@ void ext_yahoo_got_conf_invite( int id, char *who, char *room, char *msg, YList inv = g_malloc( sizeof( struct byahoo_conf_invitation ) ); memset( inv, 0, sizeof( struct byahoo_conf_invitation ) ); inv->name = g_strdup( room ); - inv->c = serv_got_joined_chat( gc, ++byahoo_chat_id, room ); + inv->c = imcb_chat_new( ic, (char*) room ); inv->c->data = members; inv->yid = id; inv->members = members; - inv->gc = gc; + inv->ic = ic; for( m = members; m; m = m->next ) - if( g_strcasecmp( m->data, gc->username ) != 0 ) - add_chat_buddy( inv->c, m->data ); + if( g_strcasecmp( m->data, ic->acc->user ) != 0 ) + imcb_chat_add_buddy( inv->c, m->data ); g_snprintf( txt, 1024, "Got an invitation to chatroom %s from %s: %s", room, who, msg ); - do_ask_dialog( gc, txt, inv, byahoo_accept_conf, byahoo_reject_conf ); + imcb_ask( ic, txt, inv, byahoo_accept_conf, byahoo_reject_conf ); } -void ext_yahoo_conf_userdecline( int id, char *who, char *room, char *msg ) +void ext_yahoo_conf_userdecline( int id, const char *ignored, const char *who, const char *room, const char *msg ) { - struct gaim_connection *gc = byahoo_get_gc_by_id( id ); + struct im_connection *ic = byahoo_get_ic_by_id( id ); - serv_got_crap( gc, "Invite to chatroom %s rejected by %s: %s", room, who, msg ); + imcb_log( ic, "Invite to chatroom %s rejected by %s: %s", room, who, msg ); } -void ext_yahoo_conf_userjoin( int id, char *who, char *room ) +void ext_yahoo_conf_userjoin( int id, const char *ignored, const char *who, const char *room ) { - struct gaim_connection *gc = byahoo_get_gc_by_id( id ); - struct conversation *c; + struct im_connection *ic = byahoo_get_ic_by_id( id ); + struct groupchat *c; - for( c = gc->conversations; c && strcmp( c->title, room ) != 0; c = c->next ); + for( c = ic->conversations; c && strcmp( c->title, room ) != 0; c = c->next ); if( c ) - add_chat_buddy( c, who ); + imcb_chat_add_buddy( c, (char*) who ); } -void ext_yahoo_conf_userleave( int id, char *who, char *room ) +void ext_yahoo_conf_userleave( int id, const char *ignored, const char *who, const char *room ) + { - struct gaim_connection *gc = byahoo_get_gc_by_id( id ); - struct conversation *c; + struct im_connection *ic = byahoo_get_ic_by_id( id ); + struct groupchat *c; - for( c = gc->conversations; c && strcmp( c->title, room ) != 0; c = c->next ); + for( c = ic->conversations; c && strcmp( c->title, room ) != 0; c = c->next ); if( c ) - remove_chat_buddy( c, who, "" ); + imcb_chat_remove_buddy( c, (char*) who, "" ); } -void ext_yahoo_conf_message( int id, char *who, char *room, char *msg, int utf8 ) +void ext_yahoo_conf_message( int id, const char *ignored, const char *who, const char *room, const char *msg, int utf8 ) { - struct gaim_connection *gc = byahoo_get_gc_by_id( id ); + struct im_connection *ic = byahoo_get_ic_by_id( id ); char *m = byahoo_strip( msg ); - struct conversation *c; + struct groupchat *c; - for( c = gc->conversations; c && strcmp( c->title, room ) != 0; c = c->next ); + for( c = ic->conversations; c && strcmp( c->title, room ) != 0; c = c->next ); - serv_got_chat_in( gc, c ? c->id : 0, who, 0, m, 0 ); + if( c ) + imcb_chat_msg( c, (char*) who, (char*) m, 0, 0 ); g_free( m ); } -void ext_yahoo_chat_cat_xml( int id, char *xml ) +void ext_yahoo_chat_cat_xml( int id, const char *xml ) { } -void ext_yahoo_chat_join( int id, char *room, char *topic, YList *members, int fd ) +void ext_yahoo_chat_join( int id, const char *who, const char *room, const char *topic, YList *members, int fd ) { } -void ext_yahoo_chat_userjoin( int id, char *room, struct yahoo_chat_member *who ) +void ext_yahoo_chat_userjoin( int id, const char *me, const char *room, struct yahoo_chat_member *who ) { + free(who->id); + free(who->alias); + free(who->location); + free(who); } -void ext_yahoo_chat_userleave( int id, char *room, char *who ) +void ext_yahoo_chat_userleave( int id, const char *me, const char *room, const char *who ) { } -void ext_yahoo_chat_message( int id, char *who, char *room, char *msg, int msgtype, int utf8 ) +void ext_yahoo_chat_message( int id, const char *me, const char *who, const char *room, const char *msg, int msgtype, int utf8 ) { } -void ext_yahoo_chat_yahoologout( int id ) +void ext_yahoo_chat_yahoologout( int id, const char *me ) { } -void ext_yahoo_chat_yahooerror( int id ) +void ext_yahoo_chat_yahooerror( int id, const char *me ) { } -void ext_yahoo_contact_added( int id, char *myid, char *who, char *msg ) +void ext_yahoo_contact_added( int id, const char *myid, const char *who, const char *msg ) { + /* Groups schmoups. If I want to handle groups properly I can get the + buddy data from some internal libyahoo2 structure. */ + imcb_add_buddy( byahoo_get_ic_by_id( id ), (char*) who, NULL ); } -void ext_yahoo_rejected( int id, char *who, char *msg ) +void ext_yahoo_rejected( int id, const char *who, const char *msg ) { } -void ext_yahoo_game_notify( int id, char *who, int stat ) +void ext_yahoo_game_notify( int id, const char *me, const char *who, int stat ) { } -void ext_yahoo_mail_notify( int id, char *from, char *subj, int cnt ) +void ext_yahoo_mail_notify( int id, const char *from, const char *subj, int cnt ) { - struct gaim_connection *gc = byahoo_get_gc_by_id( id ); + struct im_connection *ic = byahoo_get_ic_by_id( id ); if( from && subj ) - serv_got_crap( gc, "Received e-mail message from %s with subject `%s'", from, subj ); + imcb_log( ic, "Received e-mail message from %s with subject `%s'", from, subj ); else if( cnt > 0 ) - serv_got_crap( gc, "Received %d new e-mails", cnt ); + imcb_log( ic, "Received %d new e-mails", cnt ); } -void ext_yahoo_webcam_invite_reply( int id, char *from, int accept ) +void ext_yahoo_webcam_invite_reply( int id, const char *me, const char *from, int accept ) { } -void ext_yahoo_webcam_closed( int id, char *who, int reason ) +void ext_yahoo_webcam_closed( int id, const char *who, int reason ) { } @@ -937,7 +940,7 @@ void ext_yahoo_got_search_result( int id, int found, int start, int total, YList { } -void ext_yahoo_webcam_viewer( int id, char *who, int connect ) +void ext_yahoo_webcam_viewer( int id, const char *who, int connect ) { } @@ -945,7 +948,7 @@ void ext_yahoo_webcam_data_request( int id, int send ) { } -int ext_yahoo_log( char *fmt, ... ) +int ext_yahoo_log( const char *fmt, ... ) { return( 0 ); } @@ -953,3 +956,13 @@ int ext_yahoo_log( char *fmt, ... ) void ext_yahoo_got_webcam_image( int id, const char * who, const unsigned char *image, unsigned int image_size, unsigned int real_size, unsigned int timestamp ) { } + +void ext_yahoo_got_ping( int id, const char *msg) +{ +} + +void ext_yahoo_got_buddyicon (int id, const char *me, const char *who, const char *url, int checksum) {} +void ext_yahoo_got_buddyicon_checksum (int id, const char *me,const char *who, int checksum) {} + +void ext_yahoo_got_buddyicon_request(int id, const char *me, const char *who){} +void ext_yahoo_buddyicon_uploaded(int id, const char *url){} diff --git a/protocols/yahoo/yahoo2.h b/protocols/yahoo/yahoo2.h index 5ac5e4f9..e54e09fb 100644 --- a/protocols/yahoo/yahoo2.h +++ b/protocols/yahoo/yahoo2.h @@ -119,7 +119,7 @@ void yahoo_chat_keepalive(int id); /* from is the identity you're sending from. if NULL, the default is used */ /* utf8 is whether msg is a utf8 string or not. */ -void yahoo_send_im(int id, const char *from, const char *who, const char *msg, int utf8); +void yahoo_send_im(int id, const char *from, const char *who, const char *msg, int utf8, int picture); /* if type is true, send typing notice, else send stopped typing notice */ void yahoo_send_typing(int id, const char *from, const char *who, int typ); @@ -127,9 +127,10 @@ void yahoo_send_typing(int id, const char *from, const char *who, int typ); /* away says whether the custom message is an away message or a sig */ void yahoo_set_away(int id, enum yahoo_status state, const char *msg, int away); -void yahoo_add_buddy(int id, const char *who, const char *group); +void yahoo_add_buddy(int id, const char *who, const char *group, const char *msg); void yahoo_remove_buddy(int id, const char *who, const char *group); void yahoo_reject_buddy(int id, const char *who, const char *msg); +void yahoo_stealth_buddy(int id, const char *who, int unstealth); /* if unignore is true, unignore, else ignore */ void yahoo_ignore_buddy(int id, const char *who, int unignore); void yahoo_change_buddy_group(int id, const char *who, const char *old_group, const char *new_group); @@ -213,6 +214,8 @@ const char * yahoo_get_cookie(int id, const char *which); /* You'll have to do urlencoding yourself, but see yahoo_httplib.h first */ const char * yahoo_get_profile_url( void ); +void yahoo_buddyicon_request(int id, const char *who); + #include "yahoo_httplib.h" #ifdef __cplusplus diff --git a/protocols/yahoo/yahoo2_callbacks.h b/protocols/yahoo/yahoo2_callbacks.h index 1ab8a9d7..b7f4e99b 100644 --- a/protocols/yahoo/yahoo2_callbacks.h +++ b/protocols/yahoo/yahoo2_callbacks.h @@ -30,7 +30,6 @@ */ - #ifndef YAHOO2_CALLBACKS_H #define YAHOO2_CALLBACKS_H @@ -66,7 +65,6 @@ typedef enum { typedef void (*yahoo_connect_callback)(int fd, int error, void *callback_data); - /* * The following functions need to be implemented in the client * interface. They will be called by the library when each @@ -95,9 +93,7 @@ struct yahoo_callbacks { * succ - enum yahoo_login_status * url - url to reactivate account if locked */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_login_response)(int id, int succ, char *url); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_login_response)(int id, int succ, const char *url); /* @@ -110,8 +106,6 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_login_response)(int id, int succ, char *url); void YAHOO_CALLBACK_TYPE(ext_yahoo_got_buddies)(int id, YList * buds); - - /* * Name: ext_yahoo_got_ignore * Called when the ignore list is got from the server @@ -122,9 +116,6 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_got_buddies)(int id, YList * buds); void YAHOO_CALLBACK_TYPE(ext_yahoo_got_ignore)(int id, YList * igns); - - - /* * Name: ext_yahoo_got_identities * Called when the contact list is got from the server @@ -135,9 +126,6 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_got_ignore)(int id, YList * igns); void YAHOO_CALLBACK_TYPE(ext_yahoo_got_identities)(int id, YList * ids); - - - /* * Name: ext_yahoo_got_cookies * Called when the cookie list is got from the server @@ -147,6 +135,14 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_got_identities)(int id, YList * ids); void YAHOO_CALLBACK_TYPE(ext_yahoo_got_cookies)(int id); +/* + * Name: ext_yahoo_got_ping + * Called when the ping packet is received from the server + * Params: + * id - the id that identifies the server connection + * errormsg - optional error message + */ +void YAHOO_CALLBACK_TYPE(ext_yahoo_got_ping)(int id, const char *errormsg); /* @@ -158,11 +154,11 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_got_cookies)(int id); * stat - status code (enum yahoo_status) * msg - the message if stat == YAHOO_STATUS_CUSTOM * away - whether the contact is away or not (YAHOO_STATUS_CUSTOM) - * for YAHOO_STATUS_IDLE, this is the number of seconds he is idle + * idle - this is the number of seconds he is idle [if he is idle] + * mobile - this is set for mobile users/buddies + * TODO: add support for pager, chat, and game states */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_status_changed)(int id, char *who, int stat, char *msg, int away); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_status_changed)(int id, const char *who, int stat, const char *msg, int away, int idle, int mobile); /* @@ -170,6 +166,7 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_status_changed)(int id, char *who, int stat, * Called when remote user sends you a message. * Params: * id - the id that identifies the server connection + * me - the identity the message was sent to * who - the handle of the remote user * msg - the message - NULL if stat == 2 * tm - timestamp of message if offline @@ -179,9 +176,7 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_status_changed)(int id, char *who, int stat, * 5 * utf8 - whether the message is encoded as utf8 or not */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_got_im)(int id, char *who, char *msg, long tm, int stat, int utf8); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_got_im)(int id, const char *me, const char *who, const char *msg, long tm, int stat, int utf8); /* @@ -189,14 +184,13 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_got_im)(int id, char *who, char *msg, long tm * Called when remote user sends you a conference invitation. * Params: * id - the id that identifies the server connection + * me - the identity the invitation was sent to * who - the user inviting you * room - the room to join * msg - the message * members - the initial members of the conference (null terminated list) */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_got_conf_invite)(int id, char *who, char *room, char *msg, YList *members); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_got_conf_invite)(int id, const char *me, const char *who, const char *room, const char *msg, YList *members); /* @@ -204,13 +198,12 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_got_conf_invite)(int id, char *who, char *roo * Called when someone declines to join the conference. * Params: * id - the id that identifies the server connection + * me - the identity in the conference * who - the user who has declined * room - the room * msg - the declining message */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_conf_userdecline)(int id, char *who, char *room, char *msg); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_conf_userdecline)(int id, const char *me, const char *who, const char *room, const char *msg); /* @@ -218,12 +211,11 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_conf_userdecline)(int id, char *who, char *ro * Called when someone joins the conference. * Params: * id - the id that identifies the server connection + * me - the identity in the conference * who - the user who has joined * room - the room joined */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_conf_userjoin)(int id, char *who, char *room); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_conf_userjoin)(int id, const char *me, const char *who, const char *room); /* @@ -231,33 +223,21 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_conf_userjoin)(int id, char *who, char *room) * Called when someone leaves the conference. * Params: * id - the id that identifies the server connection + * me - the identity in the conference * who - the user who has left * room - the room left */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_conf_userleave)(int id, char *who, char *room); - - - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_conf_userleave)(int id, const char *me, const char *who, const char *room); /* * Name: ext_yahoo_chat_cat_xml - * Called when joining the chatroom. + * Called when ? * Params: * id - the id that identifies the server connection - * room - the room joined, used in all other chat calls, freed by - * library after call - * topic - the topic of the room, freed by library after call - * members - the initial members of the chatroom (null terminated YList of - * yahoo_chat_member's) Must be freed by the client + * xml - ? */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_cat_xml)(int id, char *xml); - - - - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_cat_xml)(int id, const char *xml); /* @@ -265,6 +245,7 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_cat_xml)(int id, char *xml); * Called when joining the chatroom. * Params: * id - the id that identifies the server connection + * me - the identity in the chatroom * room - the room joined, used in all other chat calls, freed by * library after call * topic - the topic of the room, freed by library after call @@ -272,11 +253,7 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_cat_xml)(int id, char *xml); * of yahoo_chat_member's) Must be freed by the client * fd - the socket where the connection is coming from (for tracking) */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_join)(int id, char *room, char *topic, YList *members, int fd); - - - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_join)(int id, const char *me, const char *room, const char *topic, YList *members, int fd); /* @@ -284,12 +261,11 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_join)(int id, char *room, char *topic, Y * Called when someone joins the chatroom. * Params: * id - the id that identifies the server connection + * me - the identity in the chatroom * room - the room joined * who - the user who has joined, Must be freed by the client */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_userjoin)(int id, char *room, struct yahoo_chat_member *who); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_userjoin)(int id, const char *me, const char *room, struct yahoo_chat_member *who); /* @@ -297,12 +273,11 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_userjoin)(int id, char *room, struct yah * Called when someone leaves the chatroom. * Params: * id - the id that identifies the server connection + * me - the identity in the chatroom * room - the room left * who - the user who has left (Just the User ID) */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_userleave)(int id, char *room, char *who); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_userleave)(int id, const char *me, const char *room, const char *who); /* @@ -310,6 +285,7 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_userleave)(int id, char *room, char *who * Called when someone messages in the chatroom. * Params: * id - the id that identifies the server connection + * me - the identity in the chatroom * room - the room * who - the user who messaged (Just the user id) * msg - the message @@ -317,7 +293,8 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_userleave)(int id, char *room, char *who * 2 = /me type message * utf8 - whether the message is utf8 encoded or not */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_message)(int id, char *who, char *room, char *msg, int msgtype, int utf8); +void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_message)(int id, const char *me, const char *who, const char *room, const char *msg, int msgtype, int utf8); + /* * @@ -328,10 +305,12 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_message)(int id, char *who, char *room, * of the disconnect request before doing anything here (auto-join's etc) * Params: * id - the id that identifies this connection + * me - the identity in the chatroom * Returns: * nothing. */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_yahoologout)(int id); +void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_yahoologout)(int id, const char *me); + /* * @@ -343,25 +322,25 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_yahoologout)(int id); * of the error before doing anything about it. * Params: * id - the id that identifies this connection + * me - the identity in the chatroom * Returns: * nothing. */ +void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_yahooerror)(int id, const char *me); -void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_yahooerror)(int id); /* * Name: ext_yahoo_conf_message * Called when someone messages in the conference. * Params: * id - the id that identifies the server connection + * me - the identity the conf message was sent to * who - the user who messaged * room - the room * msg - the message * utf8 - whether the message is utf8 encoded or not */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_conf_message)(int id, char *who, char *room, char *msg, int utf8); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_conf_message)(int id, const char *me, const char *who, const char *room, const char *msg, int utf8); /* @@ -369,6 +348,7 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_conf_message)(int id, char *who, char *room, * Called when someone sends you a file * Params: * id - the id that identifies the server connection + * me - the identity the file was sent to * who - the user who sent the file * url - the file url * expires - the expiry date of the file on the server (timestamp) @@ -376,9 +356,7 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_conf_message)(int id, char *who, char *room, * fname- the file name if direct transfer * fsize- the file size if direct transfer */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_got_file)(int id, char *who, char *url, long expires, char *msg, char *fname, unsigned long fesize); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_got_file)(int id, const char *me, const char *who, const char *url, long expires, const char *msg, const char *fname, unsigned long fesize); /* @@ -390,9 +368,7 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_got_file)(int id, char *who, char *url, long * who - who was added * msg - any message sent */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_contact_added)(int id, char *myid, char *who, char *msg); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_contact_added)(int id, const char *myid, const char *who, const char *msg); /* @@ -403,9 +379,7 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_contact_added)(int id, char *myid, char *who, * who - who rejected you * msg - any message sent */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_rejected)(int id, char *who, char *msg); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_rejected)(int id, const char *who, const char *msg); /* @@ -413,12 +387,11 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_rejected)(int id, char *who, char *msg); * Called when remote user starts or stops typing. * Params: * id - the id that identifies the server connection + * me - the handle of the identity the notification is sent to * who - the handle of the remote user * stat - 1 if typing, 0 if stopped typing */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_typing_notify)(int id, char *who, int stat); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_typing_notify)(int id, const char *me, const char *who, int stat); /* @@ -426,12 +399,11 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_typing_notify)(int id, char *who, int stat); * Called when remote user starts or stops a game. * Params: * id - the id that identifies the server connection + * me - the handle of the identity the notification is sent to * who - the handle of the remote user * stat - 1 if game, 0 if stopped gaming */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_game_notify)(int id, char *who, int stat); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_game_notify)(int id, const char *me, const char *who, int stat); /* @@ -443,9 +415,7 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_game_notify)(int id, char *who, int stat); * subj - the subject of the mail - NULL if only mail count * cnt - mail count - 0 if new mail notification */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_mail_notify)(int id, char *from, char *subj, int cnt); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_mail_notify)(int id, const char *from, const char *subj, int cnt); /* @@ -455,17 +425,49 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_mail_notify)(int id, char *from, char *subj, * id - the id that identifies the server connection * msg - the message */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_system_message)(int id, char *msg); - - - - - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_system_message)(int id, const char *msg); +/* + * Name: ext_yahoo_got_buddyicon + * Buddy icon received + * Params: + * id - the id that identifies the server connection + * me - the handle of the identity the notification is sent to + * who - the person the buddy icon is for + * url - the url to use to load the icon + * checksum - the checksum of the icon content + */ +void YAHOO_CALLBACK_TYPE(ext_yahoo_got_buddyicon)(int id, const char *me, const char *who, const char *url, int checksum); +/* + * Name: ext_yahoo_got_buddyicon_checksum + * Buddy icon checksum received + * Params: + * id - the id that identifies the server connection + * me - the handle of the identity the notification is sent to + * who - the yahoo id of the buddy icon checksum is for + * checksum - the checksum of the icon content + */ +void YAHOO_CALLBACK_TYPE(ext_yahoo_got_buddyicon_checksum)(int id, const char *me,const char *who, int checksum); +/* + * Name: ext_yahoo_got_buddyicon_request + * Buddy icon request received + * Params: + * id - the id that identifies the server connection + * me - the handle of the identity the notification is sent to + * who - the yahoo id of the buddy that requested the buddy icon + */ +void YAHOO_CALLBACK_TYPE(ext_yahoo_got_buddyicon_request)(int id, const char *me, const char *who); +/* + * Name: ext_yahoo_got_buddyicon_request + * Buddy icon request received + * Params: + * id - the id that identifies the server connection + * url - remote url, the uploaded buddy icon can be fetched from + */ +void YAHOO_CALLBACK_TYPE(ext_yahoo_buddyicon_uploaded)(int id, const char *url); /* * Name: ext_yahoo_got_webcam_image @@ -495,18 +497,15 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_got_webcam_image)(int id, const char * who, unsigned int timestamp); - - /* * Name: ext_yahoo_webcam_invite * Called when you get a webcam invitation * Params: * id - the id that identifies the server connection + * me - identity the invitation is to * from - who the invitation is from */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_webcam_invite)(int id, char *from); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_webcam_invite)(int id, const char *me, const char *from); /* @@ -514,11 +513,11 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_webcam_invite)(int id, char *from); * Called when you get a response to a webcam invitation * Params: * id - the id that identifies the server connection + * me - identity the invitation response is to * from - who the invitation response is from * accept - 0 (decline), 1 (accept) */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_webcam_invite_reply)(int id, char *from, int accept); - +void YAHOO_CALLBACK_TYPE(ext_yahoo_webcam_invite_reply)(int id, const char *me, const char *from, int accept); /* @@ -533,7 +532,7 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_webcam_invite_reply)(int id, char *from, int * 3 = user declines permission * 4 = user does not have webcam online */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_webcam_closed)(int id, char *who, int reason); +void YAHOO_CALLBACK_TYPE(ext_yahoo_webcam_closed)(int id, const char *who, int reason); /* @@ -551,7 +550,6 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_webcam_closed)(int id, char *who, int reason) void YAHOO_CALLBACK_TYPE(ext_yahoo_got_search_result)(int id, int found, int start, int total, YList *contacts); - /* * Name: ext_yahoo_error * Called on error. @@ -559,10 +557,9 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_got_search_result)(int id, int found, int sta * id - the id that identifies the server connection * err - the error message * fatal- whether this error is fatal to the connection or not + * num - Which error is this */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_error)(int id, char *err, int fatal); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_error)(int id, const char *err, int fatal, int num); /* @@ -573,9 +570,7 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_error)(int id, char *err, int fatal); * who - the viewer * connect - 0=disconnect 1=connect 2=request */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_webcam_viewer)(int id, char *who, int connect); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_webcam_viewer)(int id, const char *who, int connect); /* @@ -588,8 +583,6 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_webcam_viewer)(int id, char *who, int connect void YAHOO_CALLBACK_TYPE(ext_yahoo_webcam_data_request)(int id, int send); - - /* * Name: ext_yahoo_log * Called to log a message. @@ -598,13 +591,7 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_webcam_data_request)(int id, int send); * Returns: * 0 */ -int YAHOO_CALLBACK_TYPE(ext_yahoo_log)(char *fmt, ...); - - - - - - +int YAHOO_CALLBACK_TYPE(ext_yahoo_log)(const char *fmt, ...); /* @@ -623,8 +610,6 @@ int YAHOO_CALLBACK_TYPE(ext_yahoo_log)(char *fmt, ...); int YAHOO_CALLBACK_TYPE(ext_yahoo_add_handler)(int id, int fd, yahoo_input_condition cond, void *data); - - /* * Name: ext_yahoo_remove_handler * Remove the listener for the fd. @@ -635,9 +620,6 @@ int YAHOO_CALLBACK_TYPE(ext_yahoo_add_handler)(int id, int fd, yahoo_input_condi void YAHOO_CALLBACK_TYPE(ext_yahoo_remove_handler)(int id, int tag); - - - /* * Name: ext_yahoo_connect * Connect to a host:port @@ -647,13 +629,7 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_remove_handler)(int id, int tag); * Returns: * a unix file descriptor to the socket */ -int YAHOO_CALLBACK_TYPE(ext_yahoo_connect)(char *host, int port); - - - - - - +int YAHOO_CALLBACK_TYPE(ext_yahoo_connect)(const char *host, int port); /* @@ -674,7 +650,7 @@ int YAHOO_CALLBACK_TYPE(ext_yahoo_connect)(char *host, int port); * Returns: * a unix file descriptor to the socket */ -int YAHOO_CALLBACK_TYPE(ext_yahoo_connect_async)(int id, char *host, int port, +int YAHOO_CALLBACK_TYPE(ext_yahoo_connect_async)(int id, const char *host, int port, yahoo_connect_callback callback, void *callback_data); #ifdef USE_STRUCT_CALLBACKS @@ -685,7 +661,7 @@ int YAHOO_CALLBACK_TYPE(ext_yahoo_connect_async)(int id, char *host, int port, * before doing anything else */ void yahoo_register_callbacks(struct yahoo_callbacks * tyc); - + #undef YAHOO_CALLBACK_TYPE #endif @@ -695,3 +671,4 @@ void yahoo_register_callbacks(struct yahoo_callbacks * tyc); #endif #endif + diff --git a/protocols/yahoo/yahoo2_types.h b/protocols/yahoo/yahoo2_types.h index 1a92b267..df1756eb 100644 --- a/protocols/yahoo/yahoo2_types.h +++ b/protocols/yahoo/yahoo2_types.h @@ -29,6 +29,7 @@ extern "C" { #endif enum yahoo_status { + YAHOO_STATUS_DISCONNECTED = -1, YAHOO_STATUS_AVAILABLE = 0, YAHOO_STATUS_BRB, YAHOO_STATUS_BUSY, @@ -42,13 +43,15 @@ enum yahoo_status { YAHOO_STATUS_INVISIBLE = 12, YAHOO_STATUS_CUSTOM = 99, YAHOO_STATUS_IDLE = 999, + YAHOO_STATUS_WEBLOGIN = 0x5a55aa55, YAHOO_STATUS_OFFLINE = 0x5a55aa56, /* don't ask */ - YAHOO_STATUS_NOTIFY = 0x16 + YAHOO_STATUS_NOTIFY = 0x16 /* TYPING */ }; #define YAHOO_STATUS_GAME 0x2 /* Games don't fit into the regular status model */ enum yahoo_login_status { YAHOO_LOGIN_OK = 0, + YAHOO_LOGIN_LOGOFF = 2, YAHOO_LOGIN_UNAME = 3, YAHOO_LOGIN_PASSWD = 13, YAHOO_LOGIN_LOCK = 14, @@ -57,6 +60,9 @@ enum yahoo_login_status { }; enum yahoo_error { + E_UNKNOWN = -1, + E_CONNECTION = -2, + E_SYSTEM = -3, E_CUSTOM = 0, /* responses from ignore buddy */ @@ -78,6 +84,7 @@ enum yahoo_log_level { YAHOO_LOG_DEBUG }; +#define YAHOO_PROTO_VER 0x000b /* Yahoo style/color directives */ #define YAHOO_COLOR_BLACK "\033[30m" @@ -115,6 +122,12 @@ enum yahoo_webcam_direction_type { YAHOO_WEBCAM_UPLOAD }; +enum yahoo_stealth_visibility_type { + YAHOO_STEALTH_DEFAULT = 0, + YAHOO_STEALTH_ONLINE, + YAHOO_STEALTH_PERM_OFFLINE +}; + /* chat member attribs */ #define YAHOO_CHAT_MALE 0x8000 #define YAHOO_CHAT_FEMALE 0x10000 diff --git a/protocols/yahoo/yahoo_util.c b/protocols/yahoo/yahoo_util.c index 7babfa49..5375205f 100644 --- a/protocols/yahoo/yahoo_util.c +++ b/protocols/yahoo/yahoo_util.c @@ -68,13 +68,15 @@ char ** y_strsplit(char * str, char * sep, int nelem) char *s, *p; int i=0; int l = strlen(sep); - if(nelem < 0) { + if(nelem <= 0) { char * s; nelem=0; - for(s=strstr(str, sep); s; s=strstr(s+l, sep),nelem++) - ; - if(strcmp(str+strlen(str)-l, sep)) - nelem++; + if (*str) { + for(s=strstr(str, sep); s; s=strstr(s+l, sep),nelem++) + ; + if(strcmp(str+strlen(str)-l, sep)) + nelem++; + } } vector = y_new(char *, nelem + 1); @@ -86,7 +88,7 @@ char ** y_strsplit(char * str, char * sep, int nelem) vector[i][len] = '\0'; } - if(i<nelem) /* str didn't end with sep */ + if(i<nelem && *str) /* str didn't end with sep, and str isn't empty */ vector[i++] = strdup(p); vector[i] = NULL; @@ -29,11 +29,11 @@ static void query_display( irc_t *irc, query_t *q ); static query_t *query_default( irc_t *irc ); -query_t *query_add( irc_t *irc, struct gaim_connection *gc, char *question, void *yes, void *no, void *data ) +query_t *query_add( irc_t *irc, struct im_connection *ic, char *question, void *yes, void *no, void *data ) { query_t *q = g_new0( query_t, 1 ); - q->gc = gc; + q->ic = ic; q->question = g_strdup( question ); q->yes = yes; q->no = no; @@ -96,7 +96,7 @@ void query_del( irc_t *irc, query_t *q ) g_free( q ); } -void query_del_by_gc( irc_t *irc, struct gaim_connection *gc ) +void query_del_by_conn( irc_t *irc, struct im_connection *ic ) { query_t *q, *n, *def; int count = 0; @@ -106,7 +106,7 @@ void query_del_by_gc( irc_t *irc, struct gaim_connection *gc ) while( q ) { - if( q->gc == gc ) + if( q->ic == ic ) { n = q->next; query_del( irc, q ); @@ -121,7 +121,7 @@ void query_del_by_gc( irc_t *irc, struct gaim_connection *gc ) } if( count > 0 ) - serv_got_crap( gc, "Flushed %d unanswered question(s) for this connection.", count ); + imcb_log( ic, "Flushed %d unanswered question(s) for this connection.", count ); q = query_default( irc ); if( q && q != def ) @@ -139,12 +139,12 @@ void query_answer( irc_t *irc, query_t *q, int ans ) } if( ans ) { - serv_got_crap( q->gc, "Accepted: %s", q->question ); + imcb_log( q->ic, "Accepted: %s", q->question ); q->yes( NULL, q->data ); } else { - serv_got_crap( q->gc, "Rejected: %s", q->question ); + imcb_log( q->ic, "Rejected: %s", q->question ); q->no( NULL, q->data ); } q->data = NULL; @@ -157,9 +157,9 @@ void query_answer( irc_t *irc, query_t *q, int ans ) static void query_display( irc_t *irc, query_t *q ) { - if( q->gc ) + if( q->ic ) { - serv_got_crap( q->gc, "New request: %s\nYou can use the \2yes\2/\2no\2 commands to accept/reject this request.", q->question ); + imcb_log( q->ic, "New request: %s\nYou can use the \2yes\2/\2no\2 commands to accept/reject this request.", q->question ); } else { @@ -28,7 +28,7 @@ typedef struct query { - struct gaim_connection *gc; + struct im_connection *ic; char *question; void (* yes) ( gpointer w, void *data ); void (* no) ( gpointer w, void *data ); @@ -36,9 +36,9 @@ typedef struct query struct query *next; } query_t; -query_t *query_add( irc_t *irc, struct gaim_connection *gc, char *question, void *yes, void *no, void *data ); +query_t *query_add( irc_t *irc, struct im_connection *ic, char *question, void *yes, void *no, void *data ); void query_del( irc_t *irc, query_t *q ); -void query_del_by_gc( irc_t *irc, struct gaim_connection *gc ); +void query_del_by_conn( irc_t *irc, struct im_connection *ic ); void query_answer( irc_t *irc, query_t *q, int ans ); #endif diff --git a/root_commands.c b/root_commands.c index e0cd15b9..a7582936 100644 --- a/root_commands.c +++ b/root_commands.c @@ -247,7 +247,7 @@ static void cmd_account( irc_t *irc, char **cmd ) { irc_usermsg( irc, "Invalid account" ); } - else if( a->gc ) + else if( a->ic ) { irc_usermsg( irc, "Account is still logged in, can't delete" ); } @@ -268,9 +268,9 @@ static void cmd_account( irc_t *irc, char **cmd ) { char *con; - if( a->gc && ( a->gc->flags & OPT_LOGGED_IN ) ) + if( a->ic && ( a->ic->flags & OPT_LOGGED_IN ) ) con = " (connected)"; - else if( a->gc ) + else if( a->ic ) con = " (connecting)"; else if( a->reconnect ) con = " (awaiting reconnect)"; @@ -289,7 +289,7 @@ static void cmd_account( irc_t *irc, char **cmd ) { if( ( a = account_get( irc, cmd[2] ) ) ) { - if( a->gc ) + if( a->ic ) { irc_usermsg( irc, "Account already online" ); return; @@ -311,7 +311,7 @@ static void cmd_account( irc_t *irc, char **cmd ) irc_usermsg( irc, "Trying to get all accounts connected..." ); for( a = irc->accounts; a; a = a->next ) - if( !a->gc && a->auto_connect ) + if( !a->ic && a->auto_connect ) account_on( irc, a ); } else @@ -328,7 +328,7 @@ static void cmd_account( irc_t *irc, char **cmd ) for( a = irc->accounts; a; a = a->next ) { - if( a->gc ) + if( a->ic ) account_off( irc, a ); else if( a->reconnect ) cancel_auto_reconnect( a ); @@ -336,7 +336,7 @@ static void cmd_account( irc_t *irc, char **cmd ) } else if( ( a = account_get( irc, cmd[2] ) ) ) { - if( a->gc ) + if( a->ic ) { account_off( irc, a ); } @@ -386,13 +386,13 @@ static void cmd_account( irc_t *irc, char **cmd ) { set_t *s = set_find( &a->set, set_name ); - if( a->gc && s && s->flags & ACC_SET_OFFLINE_ONLY ) + if( a->ic && s && s->flags & ACC_SET_OFFLINE_ONLY ) { g_free( acc_handle ); irc_usermsg( irc, "This setting can only be changed when the account is %s-line", "off" ); return; } - else if( !a->gc && s && s->flags & ACC_SET_ONLINE_ONLY ) + else if( !a->ic && s && s->flags & ACC_SET_ONLINE_ONLY ) { g_free( acc_handle ); irc_usermsg( irc, "This setting can only be changed when the account is %s-line", "on" ); @@ -436,11 +436,11 @@ 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; + int add_on_server = 1; if( g_strcasecmp( cmd[1], "-tmp" ) == 0 ) { - add_for_real = 0; + add_on_server = 0; cmd ++; /* So evil... :-D */ } @@ -449,7 +449,7 @@ static void cmd_add( irc_t *irc, char **cmd ) irc_usermsg( irc, "Invalid account" ); return; } - else if( !( a->gc && ( a->gc->flags & OPT_LOGGED_IN ) ) ) + else if( !( a->ic && ( a->ic->flags & OPT_LOGGED_IN ) ) ) { irc_usermsg( irc, "That account is not on-line" ); return; @@ -475,28 +475,28 @@ static void cmd_add( irc_t *irc, char **cmd ) /* 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->acc->prpl->add_buddy( a->gc, cmd[2] ); - - add_buddy( a->gc, NULL, cmd[2], cmd[2] ); + if( add_on_server ) + a->ic->acc->prpl->add_buddy( a->ic, cmd[2], NULL ); + + /* add_buddy( a->ic, 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 ); + irc_usermsg( irc, "Adding `%s' to your contact list", cmd[2] ); } static void cmd_info( irc_t *irc, char **cmd ) { - struct gaim_connection *gc; + struct im_connection *ic; account_t *a; if( !cmd[2] ) { user_t *u = user_find( irc, cmd[1] ); - if( !u || !u->gc ) + if( !u || !u->ic ) { irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] ); return; } - gc = u->gc; + ic = u->ic; cmd[2] = u->handle; } else if( !( a = account_get( irc, cmd[1] ) ) ) @@ -504,19 +504,19 @@ static void cmd_info( irc_t *irc, char **cmd ) irc_usermsg( irc, "Invalid account" ); return; } - else if( !( ( gc = a->gc ) && ( a->gc->flags & OPT_LOGGED_IN ) ) ) + else if( !( ( ic = a->ic ) && ( a->ic->flags & OPT_LOGGED_IN ) ) ) { irc_usermsg( irc, "That account is not on-line" ); return; } - if( !gc->acc->prpl->get_info ) + if( !ic->acc->prpl->get_info ) { irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] ); } else { - gc->acc->prpl->get_info( gc, cmd[2] ); + ic->acc->prpl->get_info( ic, cmd[2] ); } } @@ -551,7 +551,7 @@ static void cmd_rename( irc_t *irc, char **cmd ) } else if( u->send_handler == buddy_send_handler ) { - nick_set( u->gc->acc, u->handle, cmd[2] ); + nick_set( u->ic->acc, u->handle, cmd[2] ); } irc_usermsg( irc, "Nick successfully changed" ); @@ -563,16 +563,16 @@ static void cmd_remove( irc_t *irc, char **cmd ) user_t *u; char *s; - if( !( u = user_find( irc, cmd[1] ) ) || !u->gc ) + if( !( u = user_find( irc, cmd[1] ) ) || !u->ic ) { irc_usermsg( irc, "Buddy `%s' not found", cmd[1] ); return; } s = g_strdup( u->handle ); - u->gc->acc->prpl->remove_buddy( u->gc, u->handle, NULL ); + u->ic->acc->prpl->remove_buddy( u->ic, u->handle, NULL ); + nick_del( u->ic->acc, u->handle ); user_del( irc, cmd[1] ); - nick_del( u->gc->acc, s ); irc_usermsg( irc, "Buddy `%s' (nick %s) removed from contact list", s, cmd[1] ); g_free( s ); @@ -582,10 +582,10 @@ static void cmd_remove( irc_t *irc, char **cmd ) static void cmd_block( irc_t *irc, char **cmd ) { - struct gaim_connection *gc; + struct im_connection *ic; account_t *a; - if( !cmd[2] && ( a = account_get( irc, cmd[1] ) ) && a->gc ) + if( !cmd[2] && ( a = account_get( irc, cmd[1] ) ) && a->ic ) { char *format; GSList *l; @@ -596,9 +596,9 @@ static void cmd_block( irc_t *irc, char **cmd ) format = "%-32.32s %-16.16s"; irc_usermsg( irc, format, "Handle", "Nickname" ); - for( l = a->gc->deny; l; l = l->next ) + for( l = a->ic->deny; l; l = l->next ) { - user_t *u = user_findhandle( a->gc, l->data ); + user_t *u = user_findhandle( a->ic, l->data ); irc_usermsg( irc, format, l->data, u ? u->nick : "(none)" ); } irc_usermsg( irc, "End of list." ); @@ -608,12 +608,12 @@ static void cmd_block( irc_t *irc, char **cmd ) else if( !cmd[2] ) { user_t *u = user_find( irc, cmd[1] ); - if( !u || !u->gc ) + if( !u || !u->ic ) { irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] ); return; } - gc = u->gc; + ic = u->ic; cmd[2] = u->handle; } else if( !( a = account_get( irc, cmd[1] ) ) ) @@ -621,30 +621,30 @@ static void cmd_block( irc_t *irc, char **cmd ) irc_usermsg( irc, "Invalid account" ); return; } - else if( !( ( gc = a->gc ) && ( a->gc->flags & OPT_LOGGED_IN ) ) ) + else if( !( ( ic = a->ic ) && ( a->ic->flags & OPT_LOGGED_IN ) ) ) { irc_usermsg( irc, "That account is not on-line" ); return; } - if( !gc->acc->prpl->add_deny || !gc->acc->prpl->rem_permit ) + if( !ic->acc->prpl->add_deny || !ic->acc->prpl->rem_permit ) { irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] ); } else { - bim_rem_allow( gc, cmd[2] ); - bim_add_block( gc, cmd[2] ); + imc_rem_allow( ic, cmd[2] ); + imc_add_block( ic, cmd[2] ); irc_usermsg( irc, "Buddy `%s' moved from your allow- to your block-list", cmd[2] ); } } static void cmd_allow( irc_t *irc, char **cmd ) { - struct gaim_connection *gc; + struct im_connection *ic; account_t *a; - if( !cmd[2] && ( a = account_get( irc, cmd[1] ) ) && a->gc ) + if( !cmd[2] && ( a = account_get( irc, cmd[1] ) ) && a->ic ) { char *format; GSList *l; @@ -655,9 +655,9 @@ static void cmd_allow( irc_t *irc, char **cmd ) format = "%-32.32s %-16.16s"; irc_usermsg( irc, format, "Handle", "Nickname" ); - for( l = a->gc->permit; l; l = l->next ) + for( l = a->ic->permit; l; l = l->next ) { - user_t *u = user_findhandle( a->gc, l->data ); + user_t *u = user_findhandle( a->ic, l->data ); irc_usermsg( irc, format, l->data, u ? u->nick : "(none)" ); } irc_usermsg( irc, "End of list." ); @@ -667,12 +667,12 @@ static void cmd_allow( irc_t *irc, char **cmd ) else if( !cmd[2] ) { user_t *u = user_find( irc, cmd[1] ); - if( !u || !u->gc ) + if( !u || !u->ic ) { irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] ); return; } - gc = u->gc; + ic = u->ic; cmd[2] = u->handle; } else if( !( a = account_get( irc, cmd[1] ) ) ) @@ -680,20 +680,20 @@ static void cmd_allow( irc_t *irc, char **cmd ) irc_usermsg( irc, "Invalid account" ); return; } - else if( !( ( gc = a->gc ) && ( a->gc->flags & OPT_LOGGED_IN ) ) ) + else if( !( ( ic = a->ic ) && ( a->ic->flags & OPT_LOGGED_IN ) ) ) { irc_usermsg( irc, "That account is not on-line" ); return; } - if( !gc->acc->prpl->rem_deny || !gc->acc->prpl->add_permit ) + if( !ic->acc->prpl->rem_deny || !ic->acc->prpl->add_permit ) { irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] ); } else { - bim_rem_block( gc, cmd[2] ); - bim_add_allow( gc, cmd[2] ); + imc_rem_block( ic, cmd[2] ); + imc_add_allow( ic, cmd[2] ); irc_usermsg( irc, "Buddy `%s' moved from your block- to your allow-list", cmd[2] ); } @@ -802,32 +802,32 @@ static void cmd_blist( irc_t *irc, char **cmd ) irc_usermsg( irc, format, "Nick", "User/Host/Network", "Status" ); - 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->ic && u->online && !u->away ) { if( online == 1 ) { - g_snprintf( s, sizeof( s ) - 1, "%s@%s (%s)", u->user, u->host, u->gc->acc->prpl->name ); + g_snprintf( s, sizeof( s ) - 1, "%s@%s (%s)", u->user, u->host, u->ic->acc->prpl->name ); irc_usermsg( irc, format, u->nick, s, "Online" ); } n_online ++; } - 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->ic && u->online && u->away ) { if( away == 1 ) { - g_snprintf( s, sizeof( s ) - 1, "%s@%s (%s)", u->user, u->host, u->gc->acc->prpl->name ); + g_snprintf( s, sizeof( s ) - 1, "%s@%s (%s)", u->user, u->host, u->ic->acc->prpl->name ); irc_usermsg( irc, format, u->nick, s, u->away ); } n_away ++; } - for( u = irc->users; u; u = u->next ) if( u->gc && !u->online ) + for( u = irc->users; u; u = u->next ) if( u->ic && !u->online ) { if( offline == 1 ) { - g_snprintf( s, sizeof( s ) - 1, "%s@%s (%s)", u->user, u->host, u->gc->acc->prpl->name ); + g_snprintf( s, sizeof( s ) - 1, "%s@%s (%s)", u->user, u->host, u->ic->acc->prpl->name ); irc_usermsg( irc, format, u->nick, s, "Offline" ); } n_offline ++; @@ -844,15 +844,15 @@ static void cmd_nick( irc_t *irc, char **cmd ) { irc_usermsg( irc, "Invalid account"); } - else if( !( a->gc && ( a->gc->flags & OPT_LOGGED_IN ) ) ) + else if( !( a->ic && ( a->ic->flags & OPT_LOGGED_IN ) ) ) { irc_usermsg( irc, "That account is not on-line" ); } else if ( !cmd[2] ) { - irc_usermsg( irc, "Your name is `%s'" , a->gc->displayname ? a->gc->displayname : "NULL" ); + irc_usermsg( irc, "Your name is `%s'" , a->ic->displayname ? a->ic->displayname : "NULL" ); } - else if ( !a->prpl->set_info ) + else if ( !a->prpl->set_my_name ) { irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] ); } @@ -860,7 +860,7 @@ static void cmd_nick( irc_t *irc, char **cmd ) { irc_usermsg( irc, "Setting your name to `%s'", cmd[2] ); - a->prpl->set_info( a->gc, cmd[2] ); + a->prpl->set_my_name( a->ic, cmd[2] ); } } @@ -878,12 +878,59 @@ static void cmd_qlist( irc_t *irc, char **cmd ) irc_usermsg( irc, "Pending queries:" ); for( num = 0; q; q = q->next, num ++ ) - if( q->gc ) /* Not necessary yet, but it might come later */ - irc_usermsg( irc, "%d, %s(%s): %s", num, q->gc->acc->prpl->name, q->gc->username, q->question ); + if( q->ic ) /* Not necessary yet, but it might come later */ + irc_usermsg( irc, "%d, %s(%s): %s", num, q->ic->acc->prpl->name, q->ic->acc->user, q->question ); else irc_usermsg( irc, "%d, BitlBee: %s", num, q->question ); } +static void cmd_join_chat( irc_t *irc, char **cmd ) +{ + account_t *a; + struct im_connection *ic; + char *chat, *channel, *nick = NULL, *password = NULL; + struct groupchat *c; + + if( !( a = account_get( irc, cmd[1] ) ) ) + { + irc_usermsg( irc, "Invalid account" ); + return; + } + else if( !( a->ic && ( a->ic->flags & OPT_LOGGED_IN ) ) ) + { + irc_usermsg( irc, "That account is not on-line" ); + return; + } + else if( a->prpl->chat_join == NULL ) + { + irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] ); + return; + } + ic = a->ic; + + chat = cmd[2]; + if( cmd[3] ) + { + channel = g_strdup( cmd[3] ); + } + else + { + char *s; + + channel = g_strdup( chat ); + if( ( s = strchr( channel, '@' ) ) ) + *s = 0; + } + if( cmd[3] && cmd[4] ) + nick = cmd[4]; + if( cmd[3] && cmd[4] && cmd[5] ) + password = cmd[5]; + + c = a->prpl->chat_join( ic, chat, nick, password ); + + g_free( channel ); +} + const command_t commands[] = { { "help", 0, cmd_help, 0 }, { "identify", 1, cmd_identify, 0 }, @@ -903,5 +950,6 @@ const command_t commands[] = { { "blist", 0, cmd_blist, 0 }, { "nick", 1, cmd_nick, 0 }, { "qlist", 0, cmd_qlist, 0 }, + { "join_chat", 2, cmd_join_chat, 0 }, { NULL } }; @@ -91,9 +91,6 @@ int set_getint( set_t **head, char *key ) if( !s ) return 0; - if( ( g_strcasecmp( s, "true" ) == 0 ) || ( g_strcasecmp( s, "yes" ) == 0 ) || ( g_strcasecmp( s, "on" ) == 0 ) ) - return 1; - if( sscanf( s, "%d", &i ) != 1 ) return 0; @@ -36,7 +36,10 @@ struct set; remembers a default value for every setting. And to prevent the user from setting invalid values, you can write an evaluator function for every setting, which can check a new value and block it by returning - NULL, or replace it by returning a new value. See struct set.eval. */ + NULL, or replace it by returning a new value. See struct set.eval. + One thing that is really missing here is additional data for the + evaluator. This could be useful to add minimum and maximum values for + integers, for example. */ typedef char *(*set_eval) ( struct set *set, char *value ); @@ -50,7 +53,9 @@ typedef struct set char *def; /* Default value. If the set_setstr() function notices a new value is exactly the same as the default, value gets set to NULL. So when - you read a setting, don't forget about this! */ + you read a setting, don't forget about this! + In fact, you should only read values using + set_getstr/int(). */ int flags; /* See account.h, for example. set.c doesn't use this (yet?). */ @@ -72,9 +77,8 @@ set_t *set_find( set_t **head, char *key ); returned string, and don't free() it! */ G_MODULE_EXPORT char *set_getstr( set_t **head, char *key ); -/* Get an integer. Right now this also converts true/false/on/off/etc to - numbers, but this is for historical reasons, please use set_getbool() - for booleans instead. */ +/* Get an integer. In previous versions set_getint() was also used to read + boolean values, but this SHOULD be done with set_getbool() now! */ G_MODULE_EXPORT int set_getint( set_t **head, char *key ); G_MODULE_EXPORT int set_getbool( set_t **head, char *key ); diff --git a/storage_text.c b/storage_text.c index 3a11facf..7c29d95a 100644 --- a/storage_text.c +++ b/storage_text.c @@ -97,7 +97,7 @@ static storage_status_t text_load ( const char *my_nick, const char* password, i if( !fp ) return STORAGE_NO_SUCH_USER; while( fscanf( fp, "%s %d %s", s, &proto, nick ) > 0 ) { - if( ( acc = acc_lookup[proto] ) == NULL ) + if( proto < 0 || proto > 8 || ( acc = acc_lookup[proto] ) == NULL ) continue; http_decode( s ); diff --git a/tests/Makefile b/tests/Makefile index 2c45354d..4d4ed8d3 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,4 +1,4 @@ -include ../Makefile.settings +-include ../Makefile.settings LFLAGS +=-lcheck @@ -8,6 +8,8 @@ all: check clean: rm -f check *.o +distclean: clean + main_objs = account.o bitlbee.o conf.o crypting.o help.o ipc.o irc.o irc_commands.o log.o nick.o query.o root_commands.o set.o storage.o storage_xml.o storage_text.o user.o test_objs = check.o check_util.o check_nick.o check_md5.o check_irc.o check_help.o check_user.o check_crypting.o check_set.o @@ -140,21 +140,21 @@ user_t *user_find( irc_t *irc, char *nick ) return( NULL ); } -user_t *user_findhandle( struct gaim_connection *gc, char *handle ) +user_t *user_findhandle( struct im_connection *ic, char *handle ) { user_t *u; char *nick; /* First, let's try a hash lookup. If it works, it's probably faster. */ - if( ( nick = g_hash_table_lookup( gc->acc->nicks, handle ) ) && - ( u = user_find( gc->irc, nick ) ) && - ( gc->acc->prpl->handle_cmp( handle, u->handle ) == 0 ) ) + if( ( nick = g_hash_table_lookup( ic->acc->nicks, handle ) ) && + ( u = user_find( ic->irc, nick ) ) && + ( ic->acc->prpl->handle_cmp( handle, u->handle ) == 0 ) ) return u; /* However, it doesn't always work, so in that case we'll have to dig through the whole userlist. :-( */ - for( u = gc->irc->users; u; u = u->next ) - if( u->gc == gc && u->handle && gc->acc->prpl->handle_cmp( u->handle, handle ) == 0 ) + for( u = ic->irc->users; u; u = u->next ) + if( u->ic == ic && u->handle && ic->acc->prpl->handle_cmp( u->handle, handle ) == 0 ) return u; return NULL; @@ -39,7 +39,7 @@ typedef struct __USER char *handle; char *group; - struct gaim_connection *gc; + struct im_connection *ic; char *sendbuf; time_t last_typing_notice; @@ -55,7 +55,7 @@ typedef struct __USER user_t *user_add( struct irc *irc, char *nick ); int user_del( irc_t *irc, char *nick ); G_MODULE_EXPORT user_t *user_find( irc_t *irc, char *nick ); -G_MODULE_EXPORT user_t *user_findhandle( struct gaim_connection *gc, char *handle ); +G_MODULE_EXPORT user_t *user_findhandle( struct im_connection *ic, char *handle ); void user_rename( irc_t *irc, char *oldnick, char *newnick ); #endif /* __USER_H__ */ |