diff options
Diffstat (limited to 'protocols')
41 files changed, 3438 insertions, 13819 deletions
| diff --git a/protocols/jabber/Makefile b/protocols/jabber/Makefile index 27a29be4..3c9e4949 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..f05cc93d --- /dev/null +++ b/protocols/jabber/io.c @@ -0,0 +1,550 @@ +/***************************************************************************\ +*                                                                           * +*  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 gaim_connection *gc ); + +int jabber_write_packet( struct gaim_connection *gc, struct xt_node *node ) +{ +	char *buf; +	int st; +	 +	buf = xt_to_string( node ); +	st = jabber_write( gc, buf, strlen( buf ) ); +	g_free( buf ); +	 +	return st; +} + +int jabber_write( struct gaim_connection *gc, char *buf, int len ) +{ +	struct jabber_data *jd = gc->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( gc ) ) && jd->tx_len > 0 ) +			jd->w_inpa = b_input_add( jd->fd, GAIM_INPUT_WRITE, jabber_write_callback, gc ); +	} +	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 gaim_connection *)data)->proto_data; +	 +	return jd->fd != -1 && +	       jabber_write_queue( data ) && +	       jd->tx_len > 0; +} + +static gboolean jabber_write_queue( struct gaim_connection *gc ) +{ +	struct jabber_data *jd = gc->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; +		 +		hide_login_progress_error( gc, "Short write() to server" ); +		signoff( gc ); +		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 gaim_connection *gc = data; +	struct jabber_data *jd = gc->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 ) +		{ +			hide_login_progress_error( gc, "XML stream error" ); +			signoff( gc ); +			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( gc ); +		} +		 +		/* 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( gc ) ) +				{ +					/* If there's no version= tag, we suppose +					   this server does NOT implement: XMPP 1.0, +					   SASL and TLS. */ +					if( set_getbool( &gc->acc->set, "tls" ) ) +					{ +						hide_login_progress( gc, "TLS is turned on for this " +						          "account, but is not supported by this server" ); +						signoff( gc ); +						return FALSE; +					} +					else +					{ +						return jabber_init_iq_auth( gc ); +					} +				} +			} +			else +			{ +				hide_login_progress( gc, "XML stream error" ); +				signoff( gc ); +				return FALSE; +			} +		} +	} +	else if( st == 0 || ( st < 0 && !sockerr_again() ) ) +	{ +		closesocket( jd->fd ); +		jd->fd = -1; +		 +		hide_login_progress_error( gc, "Error while reading from server" ); +		signoff( gc ); +		return FALSE; +	} +	 +	/* EAGAIN/etc or a successful read. */ +	return TRUE; +} + +gboolean jabber_connected_plain( gpointer data, gint source, b_input_condition cond ) +{ +	struct gaim_connection *gc = data; +	 +	if( source == -1 ) +	{ +		hide_login_progress( gc, "Could not connect to server" ); +		signoff( gc ); +		return FALSE; +	} +	 +	set_login_progress( gc, 1, "Connected to server, logging in" ); +	 +	return jabber_start_stream( gc ); +} + +gboolean jabber_connected_ssl( gpointer data, void *source, b_input_condition cond ) +{ +	struct gaim_connection *gc = data; +	struct jabber_data *jd = gc->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; +		 +		hide_login_progress( gc, "Could not connect to server" ); +		signoff( gc ); +		return FALSE; +	} +	 +	set_login_progress( gc, 1, "Connected to server, logging in" ); +	 +	return jabber_start_stream( gc ); +} + +static xt_status jabber_end_of_stream( struct xt_node *node, gpointer data ) +{ +	signoff( data ); +	return XT_ABORT; +} + +static xt_status jabber_pkt_features( struct xt_node *node, gpointer data ) +{ +	struct gaim_connection *gc = data; +	struct jabber_data *jd = gc->proto_data; +	struct xt_node *c, *reply; +	int trytls; +	 +	trytls = g_strcasecmp( set_getstr( &gc->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( &gc->acc->set, "tls" ) ) ) +		{ +			hide_login_progress( gc, "Server requires TLS connections, but TLS is turned off for this account" ); +			signoff( gc ); +			 +			return XT_ABORT; +		} +		 +		/* Only run this if the tls setting is set to true or try: */ +		if( ( trytls || set_getbool( &gc->acc->set, "tls" ) ) ) +		{ +			reply = xt_new_node( "starttls", NULL, NULL ); +			xt_add_attr( reply, "xmlns", XMLNS_TLS ); +			if( !jabber_write_packet( gc, 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( &gc->acc->set, "tls" ) ) +		{ +			hide_login_progress( gc, "TLS is turned on for this account, but is not supported by this server" ); +			signoff( gc ); +			 +			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( gc ) ) +	{ +		if( !jabber_init_iq_auth( gc ) ) +			return XT_ABORT; +	} +	 +	if( ( c = xt_find_node( node->children, "bind" ) ) ) +	{ +		reply = xt_new_node( "bind", NULL, xt_new_node( "resource", set_getstr( &gc->acc->set, "resource" ), NULL ) ); +		xt_add_attr( reply, "xmlns", XMLNS_BIND ); +		reply = jabber_make_packet( "iq", "set", NULL, reply ); +		jabber_cache_add( gc, reply, jabber_pkt_bind_sess ); +		 +		if( !jabber_write_packet( gc, 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( gc, reply, jabber_pkt_bind_sess ); +		 +		if( !jabber_write_packet( gc, 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( gc ) ) +			return XT_ABORT; +	} +	 +	return XT_HANDLED; +} + +static xt_status jabber_pkt_proceed_tls( struct xt_node *node, gpointer data ) +{ +	struct gaim_connection *gc = data; +	struct jabber_data *jd = gc->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; +	 +	set_login_progress( gc, 1, "Converting stream to TLS" ); +	 +	jd->ssl = ssl_starttls( jd->fd, jabber_connected_ssl, gc ); +	 +	return XT_HANDLED; +} + +static xt_status jabber_pkt_stream_error( struct xt_node *node, gpointer data ) +{ +	struct gaim_connection *gc = data; +	struct xt_node *c; +	char *s, *type = NULL, *text = NULL; +	 +	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 ) +	{ +		hide_login_progress_error( gc, "Unknown stream error reported by server" ); +		signoff( gc ); +		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 ) +	{ +		hide_login_progress( gc, "Account and resource used from a different location" ); +		gc->wants_to_die = TRUE; +	} +	else +	{ +		s = g_strdup_printf( "Stream error: %s%s%s", type, text ? ": " : "", text ? text : "" ); +		hide_login_progress_error( gc, s ); +		g_free( s ); +	} +	 +	signoff( gc ); +	 +	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 gaim_connection *gc ) +{ +	struct jabber_data *jd = gc->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( gc ); +	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, gc ); +	 +	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( gc, greet, strlen( greet ) ); +	 +	g_free( greet ); +	 +	return st; +} + +void jabber_end_stream( struct gaim_connection *gc ) +{ +	struct jabber_data *jd = gc->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( gc->flags & OPT_LOGGED_IN ) +		{ +			node = jabber_make_packet( "presence", "unavailable", NULL, NULL ); +			st = jabber_write_packet( gc, node ); +			xt_free_node( node ); +		} +		 +		if( st ) +			jabber_write( gc, eos, strlen( eos ) ); +	} +} diff --git a/protocols/jabber/iq.c b/protocols/jabber/iq.c new file mode 100644 index 00000000..914dd02b --- /dev/null +++ b/protocols/jabber/iq.c @@ -0,0 +1,585 @@ +/***************************************************************************\ +*                                                                           * +*  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 gaim_connection *gc, struct xt_node *node, struct xt_node *orig ); +static xt_status jabber_iq_display_vcard( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig ); + +xt_status jabber_pkt_iq( struct xt_node *node, gpointer data ) +{ +	struct gaim_connection *gc = data; +	struct jabber_data *jd = gc->proto_data; +	struct xt_node *c, *reply = NULL; +	char *type, *s; +	int st, pack = 1; +	 +	type = xt_find_attr( node, "type" ); +	 +	if( !type ) +	{ +		hide_login_progress_error( gc, "Received IQ packet without type." ); +		signoff( gc ); +		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 ) +			serv_got_crap( gc, "WARNING: Received IQ-%s packet with unknown/expired ID %s!", type, s ); +		else if( entry->func ) +			return entry->func( gc, node, entry->node ); +	} +	else if( strcmp( type, "get" ) == 0 ) +	{ +		if( !( c = xt_find_node( node->children, "query" ) ) || +		    !( s = xt_find_attr( c, "xmlns" ) ) ) +		{ +			serv_got_crap( gc, "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" ) ) ) +		{ +			serv_got_crap( gc, "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( gc->acc->user ); +			 +			if( ( s = xt_find_attr( node, "from" ) ) == NULL || +			    ( strncmp( s, gc->acc->user, bare_len ) == 0 && +			      ( s[bare_len] == 0 || s[bare_len] == '/' ) ) ) +			{ +				jabber_parse_roster( gc, node, NULL ); +				 +				/* Should we generate a reply here? Don't think it's +				   very important... */ +			} +			else +			{ +				serv_got_crap( gc, "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( gc, reply ); +		xt_free_node( reply ); +		if( !st ) +			return XT_ABORT; +	} +	 +	return XT_HANDLED; +} + +static xt_status jabber_do_iq_auth( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig ); +static xt_status jabber_finish_iq_auth( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig ); + +int jabber_init_iq_auth( struct gaim_connection *gc ) +{ +	struct jabber_data *jd = gc->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( gc, node, jabber_do_iq_auth ); +	st = jabber_write_packet( gc, node ); +	 +	return st; +} + +static xt_status jabber_do_iq_auth( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig ) +{ +	struct jabber_data *jd = gc->proto_data; +	struct xt_node *reply, *query; +	xt_status st; +	char *s; +	 +	if( !( query = xt_find_node( node->children, "query" ) ) ) +	{ +		serv_got_crap( gc, "WARNING: Received incomplete IQ packet while authenticating" ); +		signoff( gc ); +		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( &gc->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*) gc->acc->pass, strlen( gc->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", gc->acc->pass, NULL ) ); +	} +	else +	{ +		xt_free_node( reply ); +		 +		hide_login_progress( gc, "Can't find suitable authentication method" ); +		signoff( gc ); +		return XT_ABORT; +	} +	 +	reply = jabber_make_packet( "iq", "set", NULL, reply ); +	jabber_cache_add( gc, reply, jabber_finish_iq_auth ); +	st = jabber_write_packet( gc, reply ); +	 +	return st ? XT_HANDLED : XT_ABORT; +} + +static xt_status jabber_finish_iq_auth( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig ) +{ +	struct jabber_data *jd = gc->proto_data; +	char *type; +	 +	if( !( type = xt_find_attr( node, "type" ) ) ) +	{ +		serv_got_crap( gc, "WARNING: Received incomplete IQ packet while authenticating" ); +		signoff( gc ); +		return XT_HANDLED; +	} +	 +	if( strcmp( type, "error" ) == 0 ) +	{ +		hide_login_progress( gc, "Authentication failure" ); +		signoff( gc ); +		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( gc ) ) +			return XT_ABORT; +	} +	 +	return XT_HANDLED; +} + +xt_status jabber_pkt_bind_sess( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig ) +{ +	struct jabber_data *jd = gc->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( &gc->acc->set, "resource" ) ) != 0 ) +			serv_got_crap( gc, "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( gc ) ) +			return XT_ABORT; +	} +	 +	return XT_HANDLED; +} + +int jabber_get_roster( struct gaim_connection *gc ) +{ +	struct xt_node *node; +	int st; +	 +	set_login_progress( gc, 1, "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( gc, node, jabber_parse_roster ); +	st = jabber_write_packet( gc, node ); +	 +	return st; +} + +static xt_status jabber_parse_roster( struct gaim_connection *gc, 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" ) ) ) +	{ +		serv_got_crap( gc, "WARNING: Received NULL roster packet" ); +		return XT_HANDLED; +	} +	 +	c = query->children; +	while( ( c = xt_find_node( c, "item" ) ) ) +	{ +		char *jid = xt_find_attr( c, "jid" ); +		char *name = xt_find_attr( c, "name" ); +		char *sub = xt_find_attr( c, "subscription" ); +		 +		if( !jid || !sub ) +		{ +			/* Maybe warn. But how likely is this to happen in the first place? */ +		} +		else if( initial ) +		{ +			if( ( strcmp( sub, "both" ) == 0 || strcmp( sub, "to" ) == 0 ) ) +				add_buddy( gc, NULL, jid, name ); +		} +		else +		{ +			/* This is a roster push item. Find out what changed exactly. */ +			if( ( strcmp( sub, "both" ) == 0 || strcmp( sub, "to" ) == 0 ) ) +			{ +				if( find_buddy( gc, jid ) == NULL ) +					add_buddy( gc, NULL, jid, name ); +				else if( name ) +					serv_buddy_rename( gc, 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( gc, jid ); +				serv_got_update( gc, jid, 0, 0, 0, 0, 0, 0 ); +				/* FIXME! */ +			} +		} +		 +		c = c->next; +	} +	 +	if( initial ) +		account_online( gc ); +	 +	return XT_HANDLED; +} + +int jabber_get_vcard( struct gaim_connection *gc, 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( gc, node, jabber_iq_display_vcard ); +	return jabber_write_packet( gc, node ); +} + +static xt_status jabber_iq_display_vcard( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig ) +{ +	struct xt_node *vc, *c, *sc; /* subchild, gc 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.. */ +		serv_got_crap( gc, "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* */ +	 +	serv_got_crap( gc, reply->str ); +	g_string_free( reply, TRUE ); +	 +	return XT_HANDLED; +} + +int jabber_add_to_roster( struct gaim_connection *gc, 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( gc, node ); +	 +	xt_free_node( node ); +	return st; +} + +int jabber_remove_from_roster( struct gaim_connection *gc, 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( gc, node ); +	 +	xt_free_node( node ); +	return st; +} diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index e765a475..a60cd4aa 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -1,2392 +1,396 @@ -/* -*- 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_acc_init( account_t *acc )  { -	static char buf[4096]; -	int len; - -	if (!gjc || gjc->state == JCONN_STATE_OFF) -		return; -	 -	if (gjc->ssl) -		len = ssl_read(gjc->ssl, buf, sizeof(buf) - 1); -	else -		len = read(gjc->fd, buf, sizeof(buf) - 1); +	set_t *s; -	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, "port", "5222", set_eval_int, acc ); +	s->flags |= ACC_SET_OFFLINE_ONLY; -	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); +	s = set_add( &acc->set, "priority", "0", set_eval_priority, acc ); -	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 gaim_connection *gc = new_gaim_conn( 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->gc = gc; +	gc->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 ) +	{ +		hide_login_progress( gc, "Incomplete account name (format it like <username@jabberserver.name>)" ); +		signoff( gc );  		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); +				/* See above. */ +				*s = 0; +				s ++;  			} -		} -	}  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; -			} -			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; -	} - -	/* 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); -			} -		} +	/* 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; +	 +	set_login_progress( gc, 0, "Connecting" ); +	 +	/* 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, gc ); +		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, gc );  	} - -	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 ) +	{ +		hide_login_progress( gc, "Could not connect to server" ); +		signoff( gc );  	} -	return;  } -static void jabber_acc_init(account_t *acc) +static void jabber_close( struct gaim_connection *gc )  { -	set_t *s; +	struct jabber_data *jd = gc->proto_data; -	s = set_add( &acc->set, "port", "5222", set_eval_int, acc ); -	s->flags |= ACC_SET_OFFLINE_ONLY; +	jabber_end_stream( gc ); -	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_send_im( struct gaim_connection *gc, char *who, char *message, int len, int away )  { -	struct gaim_connection *gc; -	struct jabber_data *jd; -	char *resource, *loginname; +	struct jabber_data *jd = gc->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( gc, 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( gc, 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); +	return st;  } -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) +static GList *jabber_away_states( struct gaim_connection *gc )  { -	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 GList *l = NULL; +	int i; +	 +	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_close(struct gaim_connection *gc) +static void jabber_get_info( struct gaim_connection *gc, char *who )  {  	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; -} - -/* - * Add/update buddy's roster entry on server - */ -static void jabber_roster_update(struct gaim_connection *gc, char *name) -{ -	xmlnode x, y; -	char *realwho; -	gjconn gjc; -	struct buddy *buddy = NULL; -	/* struct group *buddy_group = NULL; */ +	struct jabber_buddy *bud; -	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); -} - -static void jabber_remove_buddy(struct gaim_connection *gc, char *name, char *group) -{ -	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); +	if( strchr( who, '/' ) ) +		bud = jabber_buddy_by_jid( gc, 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 ) +	{ +		serv_got_crap( gc, "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( gc, 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) +static void jabber_set_away( struct gaim_connection *gc, char *state_txt, 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); +	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( gc );  } -/* - * 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_add_buddy( struct gaim_connection *gc, char *who )  { -	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; -	} +	if( jabber_add_to_roster( gc, who, NULL ) ) +		presence_send_request( gc, who, "subscribe" );  } -/* - * Used by XML_Parse to end an xmlnode - */ -static void xmlstr2xmlnode_endElement(void *userdata, const char *name) +static void jabber_remove_buddy( struct gaim_connection *gc, char *who, char *group )  { -	xmlstr2xmlnode_parser xmlp = (xmlstr2xmlnode_parser) userdata; -	xmlnode x; - -	if (xmlp->current != NULL && (x = xmlnode_get_parent(xmlp->current)) != NULL) { -		xmlp->current = x; -	} -} - -/* - * Parse an XML-encoded string into an xmlnode tree - * - * Caller is responsible for freeing the returned xmlnode - */ -static xmlnode xmlstr2xmlnode(char *xmlstring) -{ -	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); +	/* We should always do this part. Clean up our administration a little bit. */ +	jabber_buddy_remove_bare( gc, who ); +	 +	if( jabber_remove_from_roster( gc, who ) ) +		presence_send_request( gc, who, "unsubscribe" );  } -/* - * 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_keepalive( struct gaim_connection *gc )  { -	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)); +	/* Just any whitespace character is enough as a keepalive for XMPP sessions. */ +	jabber_write( gc, "\n", 1 ); +	 +	/* 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( gc );  } -/* - * Send vCard info to Jabber server - */ -static void jabber_set_info(struct gaim_connection *gc, char *info) +static int jabber_send_typing( struct gaim_connection *gc, char *who, int typing )  { -	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); +	struct jabber_buddy *bud; -	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); -} - -/* - * displays a Jabber vCard - */ -static void jabber_handlevcard(gjconn gjc, xmlnode querynode, char *from) -{ -	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; +	/* Enable typing notification related code from now. */ +	jd->flags |= JFLAG_WANT_TYPING; -	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"); +	if( ( bud = jabber_buddy_by_jid( gc, 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 == 0 ) +			type = "active"; +		else if( typing == 2 ) +			type = "paused"; +		else /* if( typing == 1 ) */ +			type = "composing"; +		 +		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( gc, 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()  { -	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->acc_init = jabber_acc_init;  	ret->close = jabber_close;  	ret->send_im = jabber_send_im; -	ret->set_info = jabber_set_info; -	ret->get_info = jabber_get_info; +	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_send = jabber_chat_send; +//	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..628cb03a 100644 --- a/protocols/jabber/jabber.h +++ b/protocols/jabber/jabber.h @@ -1,315 +1,191 @@ -/* - *  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; -/* --------------------------------------------------------- */ -/*                                                           */ -/* 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 gaim_connection *gc; +	 +	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 gaim_connection *gc, 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 gaim_connection *gc ); +xt_status jabber_pkt_bind_sess( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig ); +int jabber_get_roster( struct gaim_connection *gc ); +int jabber_get_vcard( struct gaim_connection *gc, char *bare_jid ); +int jabber_add_to_roster( struct gaim_connection *gc, char *handle, char *name ); +int jabber_remove_from_roster( struct gaim_connection *gc, 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 gaim_connection *gc ); +int presence_send_request( struct gaim_connection *gc, 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 gaim_connection *gc, struct xt_node *node, jabber_cache_event func ); +struct xt_node *jabber_cache_get( struct gaim_connection *gc, char *id ); +void jabber_cache_entry_free( gpointer entry ); +void jabber_cache_clean( struct gaim_connection *gc ); +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 gaim_connection *gc, 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 gaim_connection *gc, char *full_jid ); +struct jabber_buddy *jabber_buddy_by_jid( struct gaim_connection *gc, char *jid, get_buddy_flags_t flags ); +int jabber_buddy_remove( struct gaim_connection *gc, char *full_jid ); +int jabber_buddy_remove_bare( struct gaim_connection *gc, char *bare_jid ); + +extern const struct jabber_away_state jabber_away_state_list[]; + +/* io.c */ +int jabber_write_packet( struct gaim_connection *gc, struct xt_node *node ); +int jabber_write( struct gaim_connection *gc, 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 gaim_connection *gc ); +void jabber_end_stream( struct gaim_connection *gc ); + +/* 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 gaim_connection *gc ); -#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..4ca0c1fc --- /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->gc ) +	{ +		/* 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->gc ); +	} +	 +	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 gaim_connection *gc, struct xt_node *node, jabber_cache_event func ) +{ +	struct jabber_data *jd = gc->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 gaim_connection *gc ) +{ +	struct jabber_data *jd = gc->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 gaim_connection *gc; +	char *handle; +	char *realname; +}; + +static void jabber_buddy_ask_yes( gpointer w, struct jabber_buddy_ask_data *bla ) +{ +	presence_send_request( bla->gc, bla->handle, "subscribed" ); +	 +	if( find_buddy( bla->gc, bla->handle ) == NULL ) +		show_got_added( bla->gc, 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->gc, bla->handle, "subscribed" ); +	 +	g_free( bla->handle ); +	g_free( bla ); +} + +void jabber_buddy_ask( struct gaim_connection *gc, char *handle ) +{ +	struct jabber_buddy_ask_data *bla = g_new0( struct jabber_buddy_ask_data, 1 ); +	char *buf; +	 +	bla->gc = gc; +	bla->handle = g_strdup( handle ); +	 +	buf = g_strdup_printf( "The user %s wants to add you to his/her buddy list.", handle ); +	do_ask_dialog( gc, 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 gaim_connection *gc, char *full_jid_ ) +{ +	struct jabber_data *jd = gc->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 gaim_connection *gc, char *jid_, get_buddy_flags_t flags ) +{ +	struct jabber_data *jd = gc->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 ) && find_buddy( gc, jid ) ) +		{ +			*s = '/'; +			bud = jabber_buddy_add( gc, 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 ) && find_buddy( gc, jid_ ) ) ? +			           jabber_buddy_add( gc, 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( &gc->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 gaim_connection *gc, char *full_jid_ ) +{ +	struct jabber_data *jd = gc->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 gaim_connection *gc, char *bare_jid_ ) +{ +	struct jabber_data *jd = gc->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..ac72f661 --- /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 gaim_connection *gc = 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( gc, 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 ) +			serv_got_im( gc, bud ? bud->bare_jid : from, fullmsg->str, 0, 0, fullmsg->len ); +		 +		g_string_free( fullmsg, TRUE ); +		 +		/* Handling of incoming typing notifications. */ +		if( xt_find_node( node->children, "composing" ) ) +		{ +			bud->flags |= JBFLAG_DOES_XEP85; +			serv_got_typing( gc, bud ? bud->bare_jid : from, 0, 1 ); +		} +		/* 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; +			serv_got_typing( gc, bud ? bud->bare_jid : from, 0, 0 ); +		} +		else if( xt_find_node( node->children, "paused" ) ) +		{ +			bud->flags |= JBFLAG_DOES_XEP85; +			serv_got_typing( gc, bud ? bud->bare_jid : from, 0, 2 ); +		} +		 +		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..b56acb51 --- /dev/null +++ b/protocols/jabber/presence.c @@ -0,0 +1,166 @@ +/***************************************************************************\ +*                                                                           * +*  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 gaim_connection *gc = 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 ) +	{ +		if( !( bud = jabber_buddy_by_jid( gc, from, GET_BUDDY_EXACT | GET_BUDDY_CREAT ) ) ) +		{ +			serv_got_crap( gc, "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 ); +		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; +		 +		serv_got_update( gc, bud->bare_jid, 1, 0, 0, 0, +		                 bud->away_state ? UC_UNAVAILABLE : 0, 0 ); +	} +	else if( strcmp( type, "unavailable" ) == 0 ) +	{ +		if( jabber_buddy_by_jid( gc, from, GET_BUDDY_EXACT ) == NULL ) +		{ +			serv_got_crap( gc, "WARNING: Received presence information from unknown JID: %s", from ); +			return XT_HANDLED; +		} +		 +		jabber_buddy_remove( gc, 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( gc, from, 0 ) == NULL ) +				serv_got_update( gc, from, 0, 0, 0, 0, 0, 0 ); +			 +			*s = '/'; +		} +		else +		{ +			serv_got_update( gc, from, 0, 0, 0, 0, 0, 0 ); +		} +	} +	else if( strcmp( type, "subscribe" ) == 0 ) +	{ +		jabber_buddy_ask( gc, from ); +	} +	else if( strcmp( type, "subscribed" ) == 0 ) +	{ +		/* Not sure about this one, actually... */ +		serv_got_crap( gc, "%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 gaim_connection *gc ) +{ +	struct jabber_data *jd = gc->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( &gc->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( gc, node ); +	 +	xt_free_node( node ); +	return st; +} + +/* Send a subscribe/unsubscribe request to a buddy. */ +int presence_send_request( struct gaim_connection *gc, 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( gc, 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..68953ced --- /dev/null +++ b/protocols/jabber/sasl.c @@ -0,0 +1,332 @@ +/***************************************************************************\ +*                                                                           * +*  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 gaim_connection *gc = data; +	struct jabber_data *jd = gc->proto_data; +	struct xt_node *c, *reply; +	char *s; +	int sup_plain = 0, sup_digest = 0; +	 +	if( !sasl_supported( gc ) ) +	{ +		/* Should abort this now, since we should already be doing +		   IQ authentication. Strange things happen when you try +		   to do both... */ +		serv_got_crap( gc, "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 ) +	{ +		signoff( gc ); +		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 ) +	{ +		hide_login_progress( gc, "No known SASL authentication schemes supported" ); +		signoff( gc ); +		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( gc->acc->pass ) + 2; +		s = g_malloc( len + 1 ); +		s[0] = 0; +		strcpy( s + 1, jd->username ); +		strcpy( s + 2 + strlen( jd->username ), gc->acc->pass ); +		reply->text = base64_encode( s, len ); +		reply->text_len = strlen( reply->text ); +		g_free( s ); +	} +	 +	if( !jabber_write_packet( gc, 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 gaim_connection *gc = data; +	struct jabber_data *jd = gc->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, gc->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( gc, reply ) ) +		goto silent_error; +	 +	ret = XT_HANDLED; +	goto silent_error; + +error: +	hide_login_progress( gc, "Incorrect SASL challenge received" ); +	signoff( gc ); + +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 gaim_connection *gc = data; +	struct jabber_data *jd = gc->proto_data; +	char *s; +	 +	s = xt_find_attr( node, "xmlns" ); +	if( !s || strcmp( s, XMLNS_SASL ) != 0 ) +	{ +		signoff( gc ); +		return XT_ABORT; +	} +	 +	if( strcmp( node->name, "success" ) == 0 ) +	{ +		set_login_progress( gc, 1, "Authentication finished" ); +		jd->flags |= JFLAG_AUTHENTICATED | JFLAG_STREAM_RESTART; +	} +	else if( strcmp( node->name, "failure" ) == 0 ) +	{ +		hide_login_progress( gc, "Authentication failure" ); +		signoff( gc ); +		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 gaim_connection *gc ) +{ +	struct jabber_data *jd = gc->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..663bff8c 100644 --- a/protocols/msn/msn.c +++ b/protocols/msn/msn.c @@ -181,13 +181,14 @@ static int msn_send_im( struct gaim_connection *gc, char *who, char *message, in  static GList *msn_away_states( struct gaim_connection *gc )  { -	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 ) diff --git a/protocols/nogaim.c b/protocols/nogaim.c index 0270d5a0..b627a23a 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -279,11 +279,16 @@ void signoff( struct gaim_connection *gc )  	user_t *t, *u = irc->users;  	account_t *a; +	/* Nested calls might happen sometimes, this is probably the best +	   place to catch them. */ +	if( gc->flags & OPT_LOGGING_OUT ) +		return; +	else +		gc->flags |= OPT_LOGGING_OUT; +	  	serv_got_crap( gc, "Signing off.." );  	b_event_remove( gc->keepalive ); -	gc->flags |= OPT_LOGGING_OUT; -	  	gc->keepalive = 0;  	gc->acc->prpl->close( gc );  	b_event_remove( gc->inpa ); @@ -1013,8 +1018,6 @@ int bim_set_away( struct gaim_connection *gc, char *away )  			gc->acc->prpl->set_away( gc, GAIM_AWAY_CUSTOM, away );  	} -	g_list_free( ms ); -	  	return( 1 );  } | 
