diff options
| author | Jelmer Vernooij <jelmer@samba.org> | 2008-04-02 16:22:57 +0200 | 
|---|---|---|
| committer | Jelmer Vernooij <jelmer@samba.org> | 2008-04-02 16:22:57 +0200 | 
| commit | 85d7b857fb8ca8e3c03d4abb3368a0966760630c (patch) | |
| tree | a16163e557bcae3af41bde7d2d771d64ca248a97 /protocols | |
| parent | 875ad4201402b1a8f80ba22a6cdcdb152c6e5510 (diff) | |
| parent | dd345753c1742905c9f81aa71d8b09109fbc5456 (diff) | |
Merge trunk.
Diffstat (limited to 'protocols')
83 files changed, 6547 insertions, 18521 deletions
diff --git a/protocols/Makefile b/protocols/Makefile index 4016e7fd..18d79e8d 100644 --- a/protocols/Makefile +++ b/protocols/Makefile @@ -9,7 +9,7 @@  -include ../Makefile.settings  # [SH] Program variables -objects = http_client.o md5.o nogaim.o proxy.o sha.o $(SSL_CLIENT) +objects = nogaim.o  # [SH] The next two lines should contain the directory name (in $(subdirs))  #      and the name of the object file, which should be linked into @@ -25,6 +25,10 @@ LFLAGS += -r  # [SH] Phony targets  all: protocols.o +check: all +lcov: check +gcov: +	gcov *.c  .PHONY: all clean distclean $(subdirs) diff --git a/protocols/http_client.c b/protocols/http_client.c deleted file mode 100644 index e181438c..00000000 --- a/protocols/http_client.c +++ /dev/null @@ -1,421 +0,0 @@ -  /********************************************************************\ -  * BitlBee -- An IRC to other IM-networks gateway                     * -  *                                                                    * -  * Copyright 2002-2005 Wilmer van der Gaast and others                * -  \********************************************************************/ - -/* HTTP(S) module                                                       */ - -/* -  This program is free software; you can redistribute it and/or modify -  it under the terms of the GNU General Public License as published by -  the Free Software Foundation; either version 2 of the License, or -  (at your option) any later version. - -  This program is distributed in the hope that it will be useful, -  but WITHOUT ANY WARRANTY; without even the implied warranty of -  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -  GNU General Public License for more details. - -  You should have received a copy of the GNU General Public License with -  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; -  if not, write to the Free Software Foundation, Inc., 59 Temple Place, -  Suite 330, Boston, MA  02111-1307  USA -*/ - -#include <string.h> -#include <stdio.h> - -#include "http_client.h" -#include "url.h" -#include "sock.h" - - -static void http_connected( gpointer data, int source, GaimInputCondition cond ); -static void http_ssl_connected( gpointer data, void *source, GaimInputCondition cond ); -static void http_incoming_data( gpointer data, int source, GaimInputCondition cond ); - - -void *http_dorequest( char *host, int port, int ssl, char *request, http_input_function func, gpointer data ) -{ -	struct http_request *req; -	int error = 0; -	 -	req = g_new0( struct http_request, 1 ); -	 -	if( ssl ) -	{ -		req->ssl = ssl_connect( host, port, http_ssl_connected, req ); -		if( req->ssl == NULL ) -			error = 1; -	} -	else -	{ -		req->fd = proxy_connect( host, port, http_connected, req ); -		if( req->fd < 0 ) -			error = 1; -	} -	 -	if( error ) -	{ -		g_free( req ); -		return( NULL ); -	} -	 -	req->func = func; -	req->data = data; -	req->request = g_strdup( request ); -	req->request_length = strlen( request ); -	 -	return( req ); -} - -void *http_dorequest_url( char *url_string, http_input_function func, gpointer data ) -{ -	url_t *url = g_new0( url_t, 1 ); -	char *request; -	void *ret; -	 -	if( !url_set( url, url_string ) ) -	{ -		g_free( url ); -		return NULL; -	} -	 -	if( url->proto != PROTO_HTTP && url->proto != PROTO_HTTPS ) -	{ -		g_free( url ); -		return NULL; -	} -	 -	request = g_strdup_printf( "GET %s HTTP/1.0\r\n" -	                           "Host: %s\r\n" -	                           "User-Agent: BitlBee " BITLBEE_VERSION " " ARCH "/" CPU "\r\n" -	                           "\r\n", url->file, url->host ); -	 -	ret = http_dorequest( url->host, url->port, -	                      url->proto == PROTO_HTTPS, request, func, data ); -	 -	g_free( url ); -	g_free( request ); -	return ret; -} - -/* This one is actually pretty simple... Might get more calls if we can't write  -   the whole request at once. */ -static void http_connected( gpointer data, int source, GaimInputCondition cond ) -{ -	struct http_request *req = data; -	int st; -	 -	if( source < 0 ) -		goto error; -	 -	if( req->inpa > 0 ) -		gaim_input_remove( req->inpa ); -	 -	sock_make_nonblocking( req->fd ); -	 -	if( req->ssl ) -	{ -		st = ssl_write( req->ssl, req->request + req->bytes_written, -		                req->request_length - req->bytes_written ); -		if( st < 0 ) -		{ -			if( ssl_errno != SSL_AGAIN ) -			{ -				ssl_disconnect( req->ssl ); -				goto error; -			} -		} -	} -	else -	{ -		st = write( source, req->request + req->bytes_written, -		                    req->request_length - req->bytes_written ); -		if( st < 0 ) -		{ -			if( !sockerr_again() ) -			{ -				closesocket( req->fd ); -				goto error; -			} -		} -	} -	 -	if( st > 0 ) -		req->bytes_written += st; -	 -	if( req->bytes_written < req->request_length ) -		req->inpa = gaim_input_add( source, -		                            req->ssl ? ssl_getdirection( req->ssl ) : GAIM_INPUT_WRITE, -	        	                    http_connected, req ); -	else -		req->inpa = gaim_input_add( source, GAIM_INPUT_READ, http_incoming_data, req ); -	 -	return; -	 -error: -	req->func( req ); -	 -	g_free( req->request ); -	g_free( req ); -	 -	return; -} - -static void http_ssl_connected( gpointer data, void *source, GaimInputCondition cond ) -{ -	struct http_request *req = data; -	 -	if( source == NULL ) -		return http_connected( data, -1, cond ); -	 -	req->fd = ssl_getfd( source ); -	 -	return http_connected( data, req->fd, cond ); -} - -static void http_incoming_data( gpointer data, int source, GaimInputCondition cond ) -{ -	struct http_request *req = data; -	int evil_server = 0; -	char buffer[2048]; -	char *end1, *end2; -	int st; -	 -	if( req->inpa > 0 ) -		gaim_input_remove( req->inpa ); -	 -	if( req->ssl ) -	{ -		st = ssl_read( req->ssl, buffer, sizeof( buffer ) ); -		if( st < 0 ) -		{ -			if( ssl_errno != SSL_AGAIN ) -			{ -				/* goto cleanup; */ -				 -				/* YAY! We have to deal with crappy Microsoft -				   servers that LOVE to send invalid TLS -				   packets that abort connections! \o/ */ -				 -				goto got_reply; -			} -		} -		else if( st == 0 ) -		{ -			goto got_reply; -		} -	} -	else -	{ -		st = read( req->fd, buffer, sizeof( buffer ) ); -		if( st < 0 ) -		{ -			if( !sockerr_again() ) -			{ -				goto cleanup; -			} -		} -		else if( st == 0 ) -		{ -			goto got_reply; -		} -	} -	 -	if( st > 0 ) -	{ -		req->reply_headers = g_realloc( req->reply_headers, req->bytes_read + st + 1 ); -		memcpy( req->reply_headers + req->bytes_read, buffer, st ); -		req->bytes_read += st; -	} -	 -	/* There will be more! */ -	req->inpa = gaim_input_add( req->fd, -	                            req->ssl ? ssl_getdirection( req->ssl ) : GAIM_INPUT_READ, -	                            http_incoming_data, req ); -	 -	return; - -got_reply: -	/* Maybe if the webserver is overloaded, or when there's bad SSL -	   support... */ -	if( req->bytes_read == 0 ) -		goto cleanup; -	 -	/* Zero termination is very convenient. */ -	req->reply_headers[req->bytes_read] = 0; -	 -	/* Find the separation between headers and body, and keep stupid -	   webservers in mind. */ -	end1 = strstr( req->reply_headers, "\r\n\r\n" ); -	end2 = strstr( req->reply_headers, "\n\n" ); -	 -	if( end2 && end2 < end1 ) -	{ -		end1 = end2 + 1; -		evil_server = 1; -	} -	else if( end1 ) -	{ -		end1 += 2; -	} -	else -	{ -		goto cleanup; -	} -	 -	*end1 = 0; -	 -	if( evil_server ) -		req->reply_body = end1 + 1; -	else -		req->reply_body = end1 + 2; -	 -	req->body_size = req->reply_headers + req->bytes_read - req->reply_body; -	 -	if( ( end1 = strchr( req->reply_headers, ' ' ) ) != NULL ) -	{ -		if( sscanf( end1 + 1, "%d", &req->status_code ) != 1 ) -			req->status_code = -1; -	} -	else -	{ -		req->status_code = -1; -	} -	 -	if( req->status_code == 301 || req->status_code == 302 ) -	{ -		char *loc, *new_request, *new_host; -		int error = 0, new_port, new_proto; -		 -		loc = strstr( req->reply_headers, "\nLocation: " ); -		if( loc == NULL ) /* We can't handle this redirect... */ -			goto cleanup; -		 -		loc += 11; -		while( *loc == ' ' ) -			loc ++; -		 -		/* TODO/FIXME: Possibly have to handle relative redirections, -		   and rewrite Host: headers. Not necessary for now, it's -		   enough for passport authentication like this. */ -		 -		if( *loc == '/' ) -		{ -			/* Just a different pathname... */ -			 -			/* Since we don't cache the servername, and since we -			   don't need this yet anyway, I won't implement it. */ -			 -			goto cleanup; -		} -		else -		{ -			/* A whole URL */ -			url_t *url; -			char *s; -			 -			s = strstr( loc, "\r\n" ); -			if( s == NULL ) -				goto cleanup; -			 -			url = g_new0( url_t, 1 ); -			*s = 0; -			 -			if( !url_set( url, loc ) ) -			{ -				g_free( url ); -				goto cleanup; -			} -			 -			/* Okay, this isn't fun! We have to rebuild the request... :-( */ -			new_request = g_malloc( req->request_length + strlen( url->file ) ); -			 -			/* So, now I just allocated enough memory, so I'm -			   going to use strcat(), whether you like it or not. :-) */ -			 -			/* First, find the GET/POST/whatever from the original request. */ -			s = strchr( req->request, ' ' ); -			if( s == NULL ) -			{ -				g_free( new_request ); -				g_free( url ); -				goto cleanup; -			} -			 -			*s = 0; -			sprintf( new_request, "%s %s HTTP/1.0\r\n", req->request, url->file ); -			*s = ' '; -			 -			s = strstr( req->request, "\r\n" ); -			if( s == NULL ) -			{ -				g_free( new_request ); -				g_free( url ); -				goto cleanup; -			} -			 -			strcat( new_request, s + 2 ); -			new_host = g_strdup( url->host ); -			new_port = url->port; -			new_proto = url->proto; -			 -			g_free( url ); -		} -		 -		if( req->ssl ) -			ssl_disconnect( req->ssl ); -		else -			closesocket( req->fd ); -		 -		req->fd = -1; -		req->ssl = 0; -		 -		if( new_proto == PROTO_HTTPS ) -		{ -			req->ssl = ssl_connect( new_host, new_port, http_ssl_connected, req ); -			if( req->ssl == NULL ) -				error = 1; -		} -		else -		{ -			req->fd = proxy_connect( new_host, new_port, http_connected, req ); -			if( req->fd < 0 ) -				error = 1; -		} -		g_free( new_host ); -		 -		if( error ) -		{ -			g_free( new_request ); -			goto cleanup; -		} -		 -		g_free( req->request ); -		g_free( req->reply_headers ); -		req->request = new_request; -		req->request_length = strlen( new_request ); -		req->bytes_read = req->bytes_written = req->inpa = 0; -		req->reply_headers = req->reply_body = NULL; -		 -		return; -	} -	 -	/* Assume that a closed connection means we're finished, this indeed -	   breaks with keep-alive connections and faulty connections. */ -	req->finished = 1; - -cleanup: -	if( req->ssl ) -		ssl_disconnect( req->ssl ); -	else -		closesocket( req->fd ); -	 -	req->func( req ); -	 -	g_free( req->request ); -	g_free( req->reply_headers ); -	g_free( req ); -} diff --git a/protocols/http_client.h b/protocols/http_client.h deleted file mode 100644 index 860cdd86..00000000 --- a/protocols/http_client.h +++ /dev/null @@ -1,56 +0,0 @@ -  /********************************************************************\ -  * BitlBee -- An IRC to other IM-networks gateway                     * -  *                                                                    * -  * Copyright 2002-2005 Wilmer van der Gaast and others                * -  \********************************************************************/ - -/* HTTP(S) module                                                       */ - -/* -  This program is free software; you can redistribute it and/or modify -  it under the terms of the GNU General Public License as published by -  the Free Software Foundation; either version 2 of the License, or -  (at your option) any later version. - -  This program is distributed in the hope that it will be useful, -  but WITHOUT ANY WARRANTY; without even the implied warranty of -  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -  GNU General Public License for more details. - -  You should have received a copy of the GNU General Public License with -  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; -  if not, write to the Free Software Foundation, Inc., 59 Temple Place, -  Suite 330, Boston, MA  02111-1307  USA -*/ - -#include <glib.h> - -#include "ssl_client.h" - -struct http_request; - -typedef void (*http_input_function)( struct http_request * ); - -struct http_request -{ -	char *request; -	int request_length; -	int status_code; -	char *reply_headers; -	char *reply_body; -	int body_size; -	int finished; -	 -	void *ssl; -	int fd; -	 -	int inpa; -	int bytes_written; -	int bytes_read; -	 -	http_input_function func; -	gpointer data; -}; - -void *http_dorequest( char *host, int port, int ssl, char *request, http_input_function func, gpointer data ); -void *http_dorequest_url( char *url_string, http_input_function func, gpointer data ); diff --git a/protocols/jabber/Makefile b/protocols/jabber/Makefile index 9b414dc8..e7a505ba 100644 --- a/protocols/jabber/Makefile +++ b/protocols/jabber/Makefile @@ -9,13 +9,17 @@  -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 = conference.o io.o iq.o jabber.o jabber_util.o message.o presence.o sasl.o  CFLAGS += -Wall  LFLAGS += -r  # [SH] Phony targets  all: jabber_mod.o +check: all +lcov: check +gcov:  +	gcov *.c  .PHONY: all clean distclean 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/conference.c b/protocols/jabber/conference.c new file mode 100644 index 00000000..79fdd053 --- /dev/null +++ b/protocols/jabber/conference.c @@ -0,0 +1,375 @@ +/***************************************************************************\ +*                                                                           * +*  BitlBee - An IRC to IM gateway                                           * +*  Jabber module - Conference rooms                                         * +*                                                                           * +*  Copyright 2007 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_chat_join_failed( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ); + +struct groupchat *jabber_chat_join( struct im_connection *ic, char *room, char *nick, char *password ) +{ +	struct jabber_chat *jc; +	struct xt_node *node; +	struct groupchat *c; +	char *roomjid; +	 +	roomjid = g_strdup_printf( "%s/%s", room, nick ); +	node = xt_new_node( "x", NULL, NULL ); +	xt_add_attr( node, "xmlns", XMLNS_MUC ); +	node = jabber_make_packet( "presence", NULL, roomjid, node ); +	if( password ) +		xt_add_child( node, xt_new_node( "password", password, NULL ) ); +	jabber_cache_add( ic, node, jabber_chat_join_failed ); +	 +	if( !jabber_write_packet( ic, node ) ) +	{ +		g_free( roomjid ); +		return NULL; +	} +	 +	jc = g_new0( struct jabber_chat, 1 ); +	jc->name = jabber_normalize( room ); +	 +	if( ( jc->me = jabber_buddy_add( ic, roomjid ) ) == NULL ) +	{ +		g_free( roomjid ); +		g_free( jc->name ); +		g_free( jc ); +		return NULL; +	} +	 +	/* roomjid isn't normalized yet, and we need an original version +	   of the nick to send a proper presence update. */ +	jc->my_full_jid = roomjid; +	 +	c = imcb_chat_new( ic, room ); +	c->data = jc; +	 +	return c; +} + +static xt_status jabber_chat_join_failed( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ) +{ +	struct jabber_error *err; +	struct jabber_buddy *bud; +	char *room; +	 +	room = xt_find_attr( orig, "to" ); +	bud = jabber_buddy_by_jid( ic, room, 0 ); +	err = jabber_error_parse( xt_find_node( node->children, "error" ), XMLNS_STANZA_ERROR ); +	if( err ) +	{ +		imcb_error( ic, "Error joining groupchat %s: %s%s%s", room, err->code, +		            err->text ? ": " : "", err->text ? err->text : "" ); +		jabber_error_free( err ); +	} +	if( bud ) +		jabber_chat_free( jabber_chat_by_jid( ic, bud->bare_jid ) ); +	 +	return XT_HANDLED; +} + +struct groupchat *jabber_chat_by_jid( struct im_connection *ic, const char *name ) +{ +	char *normalized = jabber_normalize( name ); +	struct groupchat *ret; +	struct jabber_chat *jc; +	 +	for( ret = ic->groupchats; ret; ret = ret->next ) +	{ +		jc = ret->data; +		if( strcmp( normalized, jc->name ) == 0 ) +			break; +	} +	g_free( normalized ); +	 +	return ret; +} + +void jabber_chat_free( struct groupchat *c ) +{ +	struct jabber_chat *jc = c->data; +	 +	jabber_buddy_remove_bare( c->ic, jc->name ); +	 +	g_free( jc->my_full_jid ); +	g_free( jc->name ); +	g_free( jc ); +	 +	imcb_chat_free( c ); +} + +int jabber_chat_msg( struct groupchat *c, char *message, int flags ) +{ +	struct im_connection *ic = c->ic; +	struct jabber_chat *jc = c->data; +	struct xt_node *node; +	 +	jc->flags |= JCFLAG_MESSAGE_SENT; +	 +	node = xt_new_node( "body", message, NULL ); +	node = jabber_make_packet( "message", "groupchat", jc->name, node ); +	 +	if( !jabber_write_packet( ic, node ) ) +	{ +		xt_free_node( node ); +		return 0; +	} +	xt_free_node( node ); +	 +	return 1; +} + +int jabber_chat_topic( struct groupchat *c, char *topic ) +{ +	struct im_connection *ic = c->ic; +	struct jabber_chat *jc = c->data; +	struct xt_node *node; +	 +	node = xt_new_node( "subject", topic, NULL ); +	node = jabber_make_packet( "message", "groupchat", jc->name, node ); +	 +	if( !jabber_write_packet( ic, node ) ) +	{ +		xt_free_node( node ); +		return 0; +	} +	xt_free_node( node ); +	 +	return 1; +} + +int jabber_chat_leave( struct groupchat *c, const char *reason ) +{ +	struct im_connection *ic = c->ic; +	struct jabber_chat *jc = c->data; +	struct xt_node *node; +	 +	node = xt_new_node( "x", NULL, NULL ); +	xt_add_attr( node, "xmlns", XMLNS_MUC ); +	node = jabber_make_packet( "presence", "unavailable", jc->my_full_jid, node ); +	 +	if( !jabber_write_packet( ic, node ) ) +	{ +		xt_free_node( node ); +		return 0; +	} +	xt_free_node( node ); +	 +	return 1; +} + +void jabber_chat_invite( struct groupchat *c, char *who, char *message ) +{ +	struct xt_node *node; +	struct im_connection *ic = c->ic; +	struct jabber_chat *jc = c->data; + +	node = xt_new_node( "reason", message, NULL );  + +	node = xt_new_node( "invite", NULL, node ); +	xt_add_attr( node, "to", who );  + +	node = xt_new_node( "x", NULL, node );  +	xt_add_attr( node, "xmlns", XMLNS_MUC_USER );  +	 +	node = jabber_make_packet( "message", NULL, jc->name, node );  + +	jabber_write_packet( ic, node );  + +	xt_free_node( node ); +} + +/* Not really the same syntax as the normal pkt_ functions, but this isn't +   called by the xmltree parser directly and this way I can add some extra +   parameters so we won't have to repeat too many things done by the caller +   already. */ +void jabber_chat_pkt_presence( struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node ) +{ +	struct groupchat *chat; +	struct xt_node *c; +	char *type = xt_find_attr( node, "type" ); +	struct jabber_chat *jc; +	char *s; +	 +	if( ( chat = jabber_chat_by_jid( ic, bud->bare_jid ) ) == NULL ) +	{ +		/* How could this happen?? We could do kill( self, 11 ) +		   now or just wait for the OS to do it. :-) */ +		return; +	} +	 +	jc = chat->data; +	 +	if( type == NULL && !( bud->flags & JBFLAG_IS_CHATROOM ) ) +	{ +		bud->flags |= JBFLAG_IS_CHATROOM; +		/* If this one wasn't set yet, this buddy just joined the chat. +		   Slightly hackish way of finding out eh? ;-) */ +		 +		/* This is pretty messy... Here it sets ext_jid to the real +		   JID of the participant. Works for non-anonymized channels. +		   Might break if someone joins a chat twice, though. */ +		for( c = node->children; ( c = xt_find_node( c, "x" ) ); c = c->next ) +			if( ( s = xt_find_attr( c, "xmlns" ) ) && +			    ( strcmp( s, XMLNS_MUC_USER ) == 0 ) ) +			{ +				c = xt_find_node( c->children, "item" ); +				if( ( s = xt_find_attr( c, "jid" ) ) ) +				{ +					/* Yay, found what we need. :-) */ +					bud->ext_jid = jabber_normalize( s ); +					break; +				} +			} +		 +		/* Make up some other handle, if necessary. */ +		if( bud->ext_jid == NULL ) +		{ +			if( bud == jc->me ) +			{ +				bud->ext_jid = jabber_normalize( ic->acc->user ); +			} +			else +			{ +				int i; +				 +				/* Don't want the nick to be at the end, so let's +				   think of some slightly different notation to use +				   for anonymous groupchat participants in BitlBee. */ +				bud->ext_jid = g_strdup_printf( "%s=%s", bud->resource, bud->bare_jid ); +				 +				/* And strip any unwanted characters. */ +				for( i = 0; bud->resource[i]; i ++ ) +					if( bud->ext_jid[i] == '=' || bud->ext_jid[i] == '@' ) +						bud->ext_jid[i] = '_'; +				 +				/* Some program-specific restrictions. */ +				imcb_clean_handle( ic, bud->ext_jid ); +			} +			bud->flags |= JBFLAG_IS_ANONYMOUS; +		} +		 +		if( bud != jc->me ) +		{ +			imcb_add_buddy( ic, bud->ext_jid, NULL ); +			imcb_buddy_nick_hint( ic, bud->ext_jid, bud->resource ); +		} +		 +		s = strchr( bud->ext_jid, '/' ); +		if( s ) *s = 0; /* Should NEVER be NULL, but who knows... */ +		imcb_chat_add_buddy( chat, bud->ext_jid ); +		if( s ) *s = '/'; +	} +	else if( type ) /* type can only be NULL or "unavailable" in this function */ +	{ +		s = strchr( bud->ext_jid, '/' ); +		if( s ) *s = 0; +		imcb_chat_remove_buddy( chat, bud->ext_jid, NULL ); +		if( bud != jc->me && bud->flags & JBFLAG_IS_ANONYMOUS ) +			imcb_remove_buddy( ic, bud->ext_jid, NULL ); +		if( s ) *s = '/'; +		 +		if( bud == jc->me ) +			jabber_chat_free( chat ); +	} +} + +void jabber_chat_pkt_message( struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node ) +{ +	struct xt_node *subject = xt_find_node( node->children, "subject" ); +	struct xt_node *body = xt_find_node( node->children, "body" ); +	struct groupchat *chat = bud ? jabber_chat_by_jid( ic, bud->bare_jid ) : NULL; +	struct jabber_chat *jc = chat ? chat->data : NULL; +	char *s; +	 +	if( bud == NULL || ( jc && ~jc->flags & JCFLAG_MESSAGE_SENT && bud == jc->me ) ) +	{ +		char *nick; +		 +		if( body == NULL || body->text_len == 0 ) +			/* Meh. Empty messages aren't very interesting, no matter +			   how much some servers love to send them. */ +			return; +		 +		s = xt_find_attr( node, "from" ); /* pkt_message() already NULL-checked this one. */ +		nick = strchr( s, '/' ); +		if( nick ) +		{ +			/* If this message included a resource/nick we don't know, +			   we might still know the groupchat itself. */ +			*nick = 0; +			chat = jabber_chat_by_jid( ic, s ); +			*nick = '/'; +			 +			nick ++; +		} +		else +		{ +			/* message.c uses the EXACT_JID option, so bud should +			   always be NULL here for bare JIDs. */ +			chat = jabber_chat_by_jid( ic, s ); +		} +		 +		if( nick == NULL ) +		{ +			/* This is fine, the groupchat itself isn't in jd->buddies. */ +			if( chat ) +				imcb_chat_log( chat, "From conference server: %s", body->text ); +			else +				imcb_log( ic, "System message from unknown groupchat %s: %s", s, body->text ); +		} +		else +		{ +			/* This can happen too, at least when receiving a backlog when +			   just joining a channel. */ +			if( chat ) +				imcb_chat_log( chat, "Message from unknown participant %s: %s", nick, body->text ); +			else +				imcb_log( ic, "Groupchat message from unknown JID %s: %s", s, body->text ); +		} +		 +		return; +	} +	else if( chat == NULL ) +	{ +		/* How could this happen?? We could do kill( self, 11 ) +		   now or just wait for the OS to do it. :-) */ +		return; +	} +	 +	if( subject ) +	{ +		s = strchr( bud->ext_jid, '/' ); +		if( s ) *s = 0; +		imcb_chat_topic( chat, bud->ext_jid, subject->text_len > 0 ? +		                 subject->text : NULL, jabber_get_timestamp( node ) ); +		if( s ) *s = '/'; +	} +	if( body && body->text_len > 0 ) +	{ +		s = strchr( bud->ext_jid, '/' ); +		if( s ) *s = 0; +		imcb_chat_msg( chat, bud->ext_jid, body->text, 0, jabber_get_timestamp( node ) ); +		if( s ) *s = '/'; +	} +} 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..10efad37 --- /dev/null +++ b/protocols/jabber/io.c @@ -0,0 +1,566 @@ +/***************************************************************************\ +*                                                                           * +*  BitlBee - An IRC to IM gateway                                           * +*  Jabber module - I/O stuff (plain, SSL), queues, etc                      * +*                                                                           * +*  Copyright 2006 Wilmer van der Gaast <wilmer@gaast.net>                   * +*                                                                           * +*  This program is free software; you can redistribute it and/or modify     * +*  it under the terms of the GNU General Public License as published by     * +*  the Free Software Foundation; either version 2 of the License, or        * +*  (at your option) any later version.                                      * +*                                                                           * +*  This program is distributed in the hope that it will be useful,          * +*  but WITHOUT ANY WARRANTY; without even the implied warranty of           * +*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            * +*  GNU General Public License for more details.                             * +*                                                                           * +*  You should have received a copy of the GNU General Public License along  * +*  with this program; if not, write to the Free Software Foundation, Inc.,  * +*  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.              * +*                                                                           * +\***************************************************************************/ + +#include "jabber.h" +#include "ssl_client.h" + +static gboolean jabber_write_callback( gpointer data, gint fd, b_input_condition cond ); +static gboolean jabber_write_queue( struct im_connection *ic ); + +int jabber_write_packet( struct im_connection *ic, struct xt_node *node ) +{ +	char *buf; +	int st; +	 +	buf = xt_to_string( node ); +	st = jabber_write( ic, buf, strlen( buf ) ); +	g_free( buf ); +	 +	return st; +} + +int jabber_write( struct im_connection *ic, char *buf, int len ) +{ +	struct jabber_data *jd = ic->proto_data; +	gboolean ret; +	 +	if( jd->flags & JFLAG_XMLCONSOLE ) +	{ +		char *msg; +		 +		msg = g_strdup_printf( "TX: %s", buf ); +		imcb_buddy_msg( ic, JABBER_XMLCONSOLE_HANDLE, msg, 0, 0 ); +		g_free( msg ); +	} +	 +	if( jd->tx_len == 0 ) +	{ +		/* If the queue is empty, allocate a new buffer. */ +		jd->tx_len = len; +		jd->txq = g_memdup( buf, len ); +		 +		/* Try if we can write it immediately so we don't have to do +		   it via the event handler. If not, add the handler. (In +		   most cases it probably won't be necessary.) */ +		if( ( ret = jabber_write_queue( ic ) ) && jd->tx_len > 0 ) +			jd->w_inpa = b_input_add( jd->fd, GAIM_INPUT_WRITE, jabber_write_callback, ic ); +	} +	else +	{ +		/* Just add it to the buffer if it's already filled. The +		   event handler is already set. */ +		jd->txq = g_renew( char, jd->txq, jd->tx_len + len ); +		memcpy( jd->txq + jd->tx_len, buf, len ); +		jd->tx_len += len; +		 +		/* The return value for write() doesn't necessarily mean +		   that everything got sent, it mainly means that the +		   connection (officially) still exists and can still +		   be accessed without hitting SIGSEGV. IOW: */ +		ret = TRUE; +	} +	 +	return ret; +} + +/* Splitting up in two separate functions: One to use as a callback and one +   to use in the function above to escape from having to wait for the event +   handler to call us, if possible. +    +   Two different functions are necessary because of the return values: The +   callback should only return TRUE if the write was successful AND if the +   buffer is not empty yet (ie. if the handler has to be called again when +   the socket is ready for more data). */ +static gboolean jabber_write_callback( gpointer data, gint fd, b_input_condition cond ) +{ +	struct jabber_data *jd = ((struct im_connection *)data)->proto_data; +	 +	return jd->fd != -1 && +	       jabber_write_queue( data ) && +	       jd->tx_len > 0; +} + +static gboolean jabber_write_queue( struct im_connection *ic ) +{ +	struct jabber_data *jd = ic->proto_data; +	int st; +	 +	if( jd->ssl ) +		st = ssl_write( jd->ssl, jd->txq, jd->tx_len ); +	else +		st = write( jd->fd, jd->txq, jd->tx_len ); +	 +	if( st == jd->tx_len ) +	{ +		/* We wrote everything, clear the buffer. */ +		g_free( jd->txq ); +		jd->txq = NULL; +		jd->tx_len = 0; +		 +		return TRUE; +	} +	else if( st == 0 || ( st < 0 && !ssl_sockerr_again( jd->ssl ) ) ) +	{ +		/* Set fd to -1 to make sure we won't write to it anymore. */ +		closesocket( jd->fd );	/* Shouldn't be necessary after errors? */ +		jd->fd = -1; +		 +		imcb_error( ic, "Short write() to server" ); +		imc_logout( ic, TRUE ); +		return FALSE; +	} +	else if( st > 0 ) +	{ +		char *s; +		 +		s = g_memdup( jd->txq + st, jd->tx_len - st ); +		jd->tx_len -= st; +		g_free( jd->txq ); +		jd->txq = s; +		 +		return TRUE; +	} +	else +	{ +		/* Just in case we had EINPROGRESS/EAGAIN: */ +		 +		return TRUE; +	} +} + +static gboolean jabber_read_callback( gpointer data, gint fd, b_input_condition cond ) +{ +	struct im_connection *ic = data; +	struct jabber_data *jd = ic->proto_data; +	char buf[512]; +	int st; +	 +	if( jd->fd == -1 ) +		return FALSE; +	 +	if( jd->ssl ) +		st = ssl_read( jd->ssl, buf, sizeof( buf ) ); +	else +		st = read( jd->fd, buf, sizeof( buf ) ); +	 +	if( st > 0 ) +	{ +		/* Parse. */ +		if( xt_feed( jd->xt, buf, st ) < 0 ) +		{ +			imcb_error( ic, "XML stream error" ); +			imc_logout( ic, TRUE ); +			return FALSE; +		} +		 +		/* Execute all handlers. */ +		if( !xt_handle( jd->xt, NULL, 1 ) ) +		{ +			/* Don't do anything, the handlers should have +			   aborted the connection already. */ +			return FALSE; +		} +		 +		if( jd->flags & JFLAG_STREAM_RESTART ) +		{ +			jd->flags &= ~JFLAG_STREAM_RESTART; +			jabber_start_stream( ic ); +		} +		 +		/* Garbage collection. */ +		xt_cleanup( jd->xt, NULL, 1 ); +		 +		/* This is a bit hackish, unfortunately. Although xmltree +		   has nifty event handler stuff, it only calls handlers +		   when nodes are complete. Since the server should only +		   send an opening <stream:stream> tag, we have to check +		   this by hand. :-( */ +		if( !( jd->flags & JFLAG_STREAM_STARTED ) && jd->xt && jd->xt->root ) +		{ +			if( g_strcasecmp( jd->xt->root->name, "stream:stream" ) == 0 ) +			{ +				jd->flags |= JFLAG_STREAM_STARTED; +				 +				/* If there's no version attribute, assume +				   this is an old server that can't do SASL +				   authentication. */ +				if( !sasl_supported( ic ) ) +				{ +					/* If there's no version= tag, we suppose +					   this server does NOT implement: XMPP 1.0, +					   SASL and TLS. */ +					if( set_getbool( &ic->acc->set, "tls" ) ) +					{ +						imcb_error( ic, "TLS is turned on for this " +						          "account, but is not supported by this server" ); +						imc_logout( ic, FALSE ); +						return FALSE; +					} +					else +					{ +						return jabber_init_iq_auth( ic ); +					} +				} +			} +			else +			{ +				imcb_error( ic, "XML stream error" ); +				imc_logout( ic, TRUE ); +				return FALSE; +			} +		} +	} +	else if( st == 0 || ( st < 0 && !ssl_sockerr_again( jd->ssl ) ) ) +	{ +		closesocket( jd->fd ); +		jd->fd = -1; +		 +		imcb_error( ic, "Error while reading from server" ); +		imc_logout( ic, TRUE ); +		return FALSE; +	} +	 +	if( ssl_pending( jd->ssl ) ) +		/* OpenSSL empties the TCP buffers completely but may keep some +		   data in its internap buffers. select() won't see that, but +		   ssl_pending() does. */ +		return jabber_read_callback( data, fd, cond ); +	else +		return TRUE; +} + +gboolean jabber_connected_plain( gpointer data, gint source, b_input_condition cond ) +{ +	struct im_connection *ic = data; +	 +	if( g_slist_find( jabber_connections, ic ) == NULL ) +		return FALSE; +	 +	if( source == -1 ) +	{ +		imcb_error( ic, "Could not connect to server" ); +		imc_logout( ic, TRUE ); +		return FALSE; +	} +	 +	imcb_log( ic, "Connected to server, logging in" ); +	 +	return jabber_start_stream( ic ); +} + +gboolean jabber_connected_ssl( gpointer data, void *source, b_input_condition cond ) +{ +	struct im_connection *ic = data; +	struct jabber_data *jd; +	 +	if( g_slist_find( jabber_connections, ic ) == NULL ) +		return FALSE; +	 +	jd = ic->proto_data; +	 +	if( source == NULL ) +	{ +		/* The SSL connection will be cleaned up by the SSL lib +		   already, set it to NULL here to prevent a double cleanup: */ +		jd->ssl = NULL; +		 +		imcb_error( ic, "Could not connect to server" ); +		imc_logout( ic, TRUE ); +		return FALSE; +	} +	 +	imcb_log( ic, "Connected to server, logging in" ); +	 +	return jabber_start_stream( ic ); +} + +static xt_status jabber_end_of_stream( struct xt_node *node, gpointer data ) +{ +	imc_logout( data, TRUE ); +	return XT_ABORT; +} + +static xt_status jabber_pkt_features( struct xt_node *node, gpointer data ) +{ +	struct im_connection *ic = data; +	struct jabber_data *jd = ic->proto_data; +	struct xt_node *c, *reply; +	int trytls; +	 +	trytls = g_strcasecmp( set_getstr( &ic->acc->set, "tls" ), "try" ) == 0; +	c = xt_find_node( node->children, "starttls" ); +	if( c && !jd->ssl ) +	{ +		/* If the server advertises the STARTTLS feature and if we're +		   not in a secure connection already: */ +		 +		c = xt_find_node( c->children, "required" ); +		 +		if( c && ( !trytls && !set_getbool( &ic->acc->set, "tls" ) ) ) +		{ +			imcb_error( ic, "Server requires TLS connections, but TLS is turned off for this account" ); +			imc_logout( ic, FALSE ); +			 +			return XT_ABORT; +		} +		 +		/* Only run this if the tls setting is set to true or try: */ +		if( ( trytls || set_getbool( &ic->acc->set, "tls" ) ) ) +		{ +			reply = xt_new_node( "starttls", NULL, NULL ); +			xt_add_attr( reply, "xmlns", XMLNS_TLS ); +			if( !jabber_write_packet( ic, reply ) ) +			{ +				xt_free_node( reply ); +				return XT_ABORT; +			} +			xt_free_node( reply ); +			 +			return XT_HANDLED; +		} +	} +	else if( !c && !jd->ssl ) +	{ +		/* If the server does not advertise the STARTTLS feature and +		   we're not in a secure connection already: (Servers have a +		   habit of not advertising <starttls/> anymore when already +		   using SSL/TLS. */ +		 +		if( !trytls && set_getbool( &ic->acc->set, "tls" ) ) +		{ +			imcb_error( ic, "TLS is turned on for this account, but is not supported by this server" ); +			imc_logout( ic, FALSE ); +			 +			return XT_ABORT; +		} +	} +	 +	/* This one used to be in jabber_handlers[], but it has to be done +	   from here to make sure the TLS session will be initialized +	   properly before we attempt SASL authentication. */ +	if( ( c = xt_find_node( node->children, "mechanisms" ) ) ) +	{ +		if( sasl_pkt_mechanisms( c, data ) == XT_ABORT ) +			return XT_ABORT; +	} +	/* If the server *SEEMS* to support SASL authentication but doesn't +	   support it after all, we should try to do authentication the +	   other way. jabber.com doesn't seem to do SASL while it pretends +	   to be XMPP 1.0 compliant! */ +	else if( !( jd->flags & JFLAG_AUTHENTICATED ) && sasl_supported( ic ) ) +	{ +		if( !jabber_init_iq_auth( ic ) ) +			return XT_ABORT; +	} +	 +	if( ( c = xt_find_node( node->children, "bind" ) ) ) +	{ +		reply = xt_new_node( "bind", NULL, xt_new_node( "resource", set_getstr( &ic->acc->set, "resource" ), NULL ) ); +		xt_add_attr( reply, "xmlns", XMLNS_BIND ); +		reply = jabber_make_packet( "iq", "set", NULL, reply ); +		jabber_cache_add( ic, reply, jabber_pkt_bind_sess ); +		 +		if( !jabber_write_packet( ic, reply ) ) +			return XT_ABORT; +		 +		jd->flags |= JFLAG_WAIT_BIND; +	} +	 +	if( ( c = xt_find_node( node->children, "session" ) ) ) +	{ +		reply = xt_new_node( "session", NULL, NULL ); +		xt_add_attr( reply, "xmlns", XMLNS_SESSION ); +		reply = jabber_make_packet( "iq", "set", NULL, reply ); +		jabber_cache_add( ic, reply, jabber_pkt_bind_sess ); +		 +		if( !jabber_write_packet( ic, reply ) ) +			return XT_ABORT; +		 +		jd->flags |= JFLAG_WAIT_SESSION; +	} +	 +	/* This flag is already set if we authenticated via SASL, so now +	   we can resume the session in the new stream, if we don't have +	   to bind/initialize the session. */ +	if( jd->flags & JFLAG_AUTHENTICATED && ( jd->flags & ( JFLAG_WAIT_BIND | JFLAG_WAIT_SESSION ) ) == 0 ) +	{ +		if( !jabber_get_roster( ic ) ) +			return XT_ABORT; +	} +	 +	return XT_HANDLED; +} + +static xt_status jabber_pkt_proceed_tls( struct xt_node *node, gpointer data ) +{ +	struct im_connection *ic = data; +	struct jabber_data *jd = ic->proto_data; +	char *xmlns; +	 +	xmlns = xt_find_attr( node, "xmlns" ); +	 +	/* Just ignore it when it doesn't seem to be TLS-related (is that at +	   all possible??). */ +	if( !xmlns || strcmp( xmlns, XMLNS_TLS ) != 0 ) +		return XT_HANDLED; +	 +	/* We don't want event handlers to touch our TLS session while it's +	   still initializing! */ +	b_event_remove( jd->r_inpa ); +	if( jd->tx_len > 0 ) +	{ +		/* Actually the write queue should be empty here, but just +		   to be sure... */ +		b_event_remove( jd->w_inpa ); +		g_free( jd->txq ); +		jd->txq = NULL; +		jd->tx_len = 0; +	} +	jd->w_inpa = jd->r_inpa = 0; +	 +	imcb_log( ic, "Converting stream to TLS" ); +	 +	jd->ssl = ssl_starttls( jd->fd, jabber_connected_ssl, ic ); +	 +	return XT_HANDLED; +} + +static xt_status jabber_pkt_stream_error( struct xt_node *node, gpointer data ) +{ +	struct im_connection *ic = data; +	int allow_reconnect = TRUE; +	struct jabber_error *err; +	 +	err = jabber_error_parse( node, XMLNS_STREAM_ERROR ); +	 +	/* Tssk... */ +	if( err->code == NULL ) +	{ +		imcb_error( ic, "Unknown stream error reported by server" ); +		imc_logout( ic, allow_reconnect ); +		jabber_error_free( err ); +		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( err->code, "conflict" ) == 0 ) +	{ +		imcb_error( ic, "Account and resource used from a different location" ); +		allow_reconnect = FALSE; +	} +	else +	{ +		imcb_error( ic, "Stream error: %s%s%s", err->code, err->text ? ": " : "", +		            err->text ? err->text : "" ); +	} +	 +	jabber_error_free( err ); +	imc_logout( ic, allow_reconnect ); +	 +	return XT_ABORT; +} + +static xt_status jabber_xmlconsole( struct xt_node *node, gpointer data ) +{ +	struct im_connection *ic = data; +	struct jabber_data *jd = ic->proto_data; +	 +	if( jd->flags & JFLAG_XMLCONSOLE ) +	{ +		char *msg, *pkt; +		 +		pkt = xt_to_string( node ); +		msg = g_strdup_printf( "RX: %s", pkt ); +		imcb_buddy_msg( ic, JABBER_XMLCONSOLE_HANDLE, msg, 0, 0 ); +		g_free( msg ); +		g_free( pkt ); +	} +	 +	return XT_NEXT; +} + +static const struct xt_handler_entry jabber_handlers[] = { +	{ NULL,                 "stream:stream",        jabber_xmlconsole }, +	{ "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,                 NULL,                   NULL } +}; + +gboolean jabber_start_stream( struct im_connection *ic ) +{ +	struct jabber_data *jd = ic->proto_data; +	int st; +	char *greet; +	 +	/* We'll start our stream now, so prepare everything to receive one +	   from the server too. */ +	xt_free( jd->xt );	/* In case we're RE-starting. */ +	jd->xt = xt_new( jabber_handlers, ic ); +	 +	if( jd->r_inpa <= 0 ) +		jd->r_inpa = b_input_add( jd->fd, GAIM_INPUT_READ, jabber_read_callback, ic ); +	 +	greet = g_strdup_printf( "<?xml version='1.0' ?>" +	                         "<stream:stream to=\"%s\" xmlns=\"jabber:client\" " +	                          "xmlns:stream=\"http://etherx.jabber.org/streams\" version=\"1.0\">", jd->server ); +	 +	st = jabber_write( ic, greet, strlen( greet ) ); +	 +	g_free( greet ); +	 +	return st; +} + +void jabber_end_stream( struct im_connection *ic ) +{ +	struct jabber_data *jd = ic->proto_data; +	 +	/* Let's only do this if the queue is currently empty, otherwise it'd +	   take too long anyway. */ +	if( jd->tx_len == 0 ) +	{ +		char eos[] = "</stream:stream>"; +		struct xt_node *node; +		int st = 1; +		 +		if( ic->flags & OPT_LOGGED_IN ) +		{ +			node = jabber_make_packet( "presence", "unavailable", NULL, NULL ); +			st = jabber_write_packet( ic, node ); +			xt_free_node( node ); +		} +		 +		if( st ) +			jabber_write( ic, eos, strlen( eos ) ); +	} +} diff --git a/protocols/jabber/iq.c b/protocols/jabber/iq.c new file mode 100644 index 00000000..38c5a5a9 --- /dev/null +++ b/protocols/jabber/iq.c @@ -0,0 +1,594 @@ +/***************************************************************************\ +*                                                                           * +*  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" +#include "sha1.h" + +static xt_status jabber_parse_roster( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ); +static xt_status jabber_iq_display_vcard( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ); + +xt_status jabber_pkt_iq( struct xt_node *node, gpointer data ) +{ +	struct im_connection *ic = data; +	struct xt_node *c, *reply = NULL; +	char *type, *s; +	int st, pack = 1; +	 +	type = xt_find_attr( node, "type" ); +	 +	if( !type ) +	{ +		imcb_error( ic, "Received IQ packet without type." ); +		imc_logout( ic, TRUE ); +		return XT_ABORT; +	} +	 +	if( strcmp( type, "result" ) == 0 || strcmp( type, "error" ) == 0 ) +	{ +		return jabber_cache_handle_packet( ic, node ); +	} +	else if( strcmp( type, "get" ) == 0 ) +	{ +		if( !( ( c = xt_find_node( node->children, "query" ) ) || +		       ( c = xt_find_node( node->children, "ping" ) ) ) || /* O_o WHAT is wrong with just <query/> ????? */ +		    !( s = xt_find_attr( c, "xmlns" ) ) ) +		{ +			imcb_log( ic, "Warning: Received incomplete IQ-%s packet", type ); +			return XT_HANDLED; +		} +		 +		reply = xt_new_node( "query", NULL, NULL ); +		xt_add_attr( reply, "xmlns", s ); +		 +		/* Of course this is a very essential query to support. ;-) */ +		if( strcmp( s, XMLNS_VERSION ) == 0 ) +		{ +			xt_add_child( reply, xt_new_node( "name", "BitlBee", NULL ) ); +			xt_add_child( reply, xt_new_node( "version", BITLBEE_VERSION, NULL ) ); +			xt_add_child( reply, xt_new_node( "os", ARCH, NULL ) ); +		} +		else if( strcmp( s, XMLNS_TIME ) == 0 ) +		{ +			time_t time_ep; +			char buf[1024]; +			 +			buf[sizeof(buf)-1] = 0; +			time_ep = time( NULL ); +			 +			strftime( buf, sizeof( buf ) - 1, "%Y%m%dT%H:%M:%S", gmtime( &time_ep ) ); +			xt_add_child( reply, xt_new_node( "utc", buf, NULL ) ); +			 +			strftime( buf, sizeof( buf ) - 1, "%Z", localtime( &time_ep ) ); +			xt_add_child( reply, xt_new_node( "tz", buf, NULL ) ); +		} +		else if( strcmp( s, XMLNS_PING ) == 0 ) +		{ +			xt_free_node( reply ); +			reply = jabber_make_packet( "iq", "result", xt_find_attr( node, "from" ), NULL ); +			if( ( s = xt_find_attr( node, "id" ) ) ) +				xt_add_attr( reply, "id", s ); +			pack = 0; +		} +		else if( strcmp( s, XMLNS_DISCOVER ) == 0 ) +		{ +			const char *features[] = { XMLNS_DISCOVER, +			                           XMLNS_VERSION, +			                           XMLNS_TIME, +			                           XMLNS_CHATSTATES, +			                           XMLNS_MUC, +			                           XMLNS_PING, +			                           NULL }; +			const char **f; +			 +			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 ); +			 +			for( f = features; *f; f ++ ) +			{ +				c = xt_new_node( "feature", NULL, NULL ); +				xt_add_attr( c, "var", *f ); +				xt_add_child( reply, c ); +			} +		} +		else +		{ +			xt_free_node( reply ); +			reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel" ); +			pack = 0; +		} +	} +	else if( strcmp( type, "set" ) == 0 ) +	{ +		if( !( c = xt_find_node( node->children, "query" ) ) || +		    !( s = xt_find_attr( c, "xmlns" ) ) ) +		{ +			imcb_log( ic, "Warning: Received incomplete IQ-%s packet", type ); +			return XT_HANDLED; +		} +		 +		/* This is a roster push. XMPP servers send this when someone +		   was added to (or removed from) the buddy list. AFAIK they're +		   sent even if we added this buddy in our own session. */ +		if( strcmp( s, XMLNS_ROSTER ) == 0 ) +		{ +			int bare_len = strlen( ic->acc->user ); +			 +			if( ( s = xt_find_attr( node, "from" ) ) == NULL || +			    ( strncmp( s, ic->acc->user, bare_len ) == 0 && +			      ( s[bare_len] == 0 || s[bare_len] == '/' ) ) ) +			{ +				jabber_parse_roster( ic, node, NULL ); +				 +				/* Should we generate a reply here? Don't think it's +				   very important... */ +			} +			else +			{ +				imcb_log( ic, "Warning: %s tried to fake a roster push!", s ? s : "(unknown)" ); +				 +				xt_free_node( reply ); +				reply = jabber_make_error_packet( node, "not-allowed", "cancel" ); +				pack = 0; +			} +		} +		else +		{ +			xt_free_node( reply ); +			reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel" ); +			pack = 0; +		} +	} +	 +	/* If we recognized the xmlns and managed to generate a reply, +	   finish and send it. */ +	if( reply ) +	{ +		/* Normally we still have to pack it into an iq-result +		   packet, but for errors, for example, we don't. */ +		if( pack ) +		{ +			reply = jabber_make_packet( "iq", "result", xt_find_attr( node, "from" ), reply ); +			if( ( s = xt_find_attr( node, "id" ) ) ) +				xt_add_attr( reply, "id", s ); +		} +		 +		st = jabber_write_packet( ic, reply ); +		xt_free_node( reply ); +		if( !st ) +			return XT_ABORT; +	} +	 +	return XT_HANDLED; +} + +static xt_status jabber_do_iq_auth( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ); +static xt_status jabber_finish_iq_auth( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ); + +int jabber_init_iq_auth( struct im_connection *ic ) +{ +	struct jabber_data *jd = ic->proto_data; +	struct xt_node *node; +	int st; +	 +	node = xt_new_node( "query", NULL, xt_new_node( "username", jd->username, NULL ) ); +	xt_add_attr( node, "xmlns", XMLNS_AUTH ); +	node = jabber_make_packet( "iq", "get", NULL, node ); +	 +	jabber_cache_add( ic, node, jabber_do_iq_auth ); +	st = jabber_write_packet( ic, node ); +	 +	return st; +} + +static xt_status jabber_do_iq_auth( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ) +{ +	struct jabber_data *jd = ic->proto_data; +	struct xt_node *reply, *query; +	xt_status st; +	char *s; +	 +	if( !( query = xt_find_node( node->children, "query" ) ) ) +	{ +		imcb_log( ic, "Warning: Received incomplete IQ packet while authenticating" ); +		imc_logout( ic, FALSE ); +		return XT_HANDLED; +	} +	 +	/* Time to authenticate ourselves! */ +	reply = xt_new_node( "query", NULL, NULL ); +	xt_add_attr( reply, "xmlns", XMLNS_AUTH ); +	xt_add_child( reply, xt_new_node( "username", jd->username, NULL ) ); +	xt_add_child( reply, xt_new_node( "resource", set_getstr( &ic->acc->set, "resource" ), NULL ) ); +	 +	if( xt_find_node( query->children, "digest" ) && ( s = xt_find_attr( jd->xt->root, "id" ) ) ) +	{ +		/* We can do digest authentication, it seems, and of +		   course we prefer that. */ +		sha1_state_t sha; +		char hash_hex[41]; +		unsigned char hash[20]; +		int i; +		 +		sha1_init( &sha ); +		sha1_append( &sha, (unsigned char*) s, strlen( s ) ); +		sha1_append( &sha, (unsigned char*) ic->acc->pass, strlen( ic->acc->pass ) ); +		sha1_finish( &sha, hash ); +		 +		for( i = 0; i < 20; i ++ ) +			sprintf( hash_hex + i * 2, "%02x", hash[i] ); +		 +		xt_add_child( reply, xt_new_node( "digest", hash_hex, NULL ) ); +	} +	else if( xt_find_node( query->children, "password" ) ) +	{ +		/* We'll have to stick with plaintext. Let's hope we're using SSL/TLS... */ +		xt_add_child( reply, xt_new_node( "password", ic->acc->pass, NULL ) ); +	} +	else +	{ +		xt_free_node( reply ); +		 +		imcb_error( ic, "Can't find suitable authentication method" ); +		imc_logout( ic, FALSE ); +		return XT_ABORT; +	} +	 +	reply = jabber_make_packet( "iq", "set", NULL, reply ); +	jabber_cache_add( ic, reply, jabber_finish_iq_auth ); +	st = jabber_write_packet( ic, reply ); +	 +	return st ? XT_HANDLED : XT_ABORT; +} + +static xt_status jabber_finish_iq_auth( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ) +{ +	struct jabber_data *jd = ic->proto_data; +	char *type; +	 +	if( !( type = xt_find_attr( node, "type" ) ) ) +	{ +		imcb_log( ic, "Warning: Received incomplete IQ packet while authenticating" ); +		imc_logout( ic, FALSE ); +		return XT_HANDLED; +	} +	 +	if( strcmp( type, "error" ) == 0 ) +	{ +		imcb_error( ic, "Authentication failure" ); +		imc_logout( ic, FALSE ); +		return XT_ABORT; +	} +	else if( strcmp( type, "result" ) == 0 ) +	{ +		/* This happens when we just successfully authenticated the +		   old (non-SASL) way. */ +		jd->flags |= JFLAG_AUTHENTICATED; +		if( !jabber_get_roster( ic ) ) +			return XT_ABORT; +	} +	 +	return XT_HANDLED; +} + +xt_status jabber_pkt_bind_sess( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ) +{ +	struct jabber_data *jd = ic->proto_data; +	struct xt_node *c; +	char *s; +	 +	if( ( c = xt_find_node( node->children, "bind" ) ) ) +	{ +		c = xt_find_node( c->children, "jid" ); +		if( c && c->text_len && ( s = strchr( c->text, '/' ) ) && +		    strcmp( s + 1, set_getstr( &ic->acc->set, "resource" ) ) != 0 ) +			imcb_log( ic, "Server changed session resource string to `%s'", s + 1 ); +		 +		jd->flags &= ~JFLAG_WAIT_BIND; +	} +	else +	{ +		jd->flags &= ~JFLAG_WAIT_SESSION; +	} +	 +	if( ( jd->flags & ( JFLAG_WAIT_BIND | JFLAG_WAIT_SESSION ) ) == 0 ) +	{ +		if( !jabber_get_roster( ic ) ) +			return XT_ABORT; +	} +	 +	return XT_HANDLED; +} + +int jabber_get_roster( struct im_connection *ic ) +{ +	struct xt_node *node; +	int st; +	 +	imcb_log( ic, "Authenticated, requesting buddy list" ); +	 +	node = xt_new_node( "query", NULL, NULL ); +	xt_add_attr( node, "xmlns", XMLNS_ROSTER ); +	node = jabber_make_packet( "iq", "get", NULL, node ); +	 +	jabber_cache_add( ic, node, jabber_parse_roster ); +	st = jabber_write_packet( ic, node ); +	 +	return st; +} + +static xt_status jabber_parse_roster( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ) +{ +	struct xt_node *query, *c; +	int initial = ( orig != NULL ); +	 +	if( !( query = xt_find_node( node->children, "query" ) ) ) +	{ +		imcb_log( ic, "Warning: Received NULL roster packet" ); +		return XT_HANDLED; +	} +	 +	c = query->children; +	while( ( c = xt_find_node( c, "item" ) ) ) +	{ +		struct xt_node *group = xt_find_node( node->children, "group" ); +		char *jid = xt_find_attr( c, "jid" ); +		char *name = xt_find_attr( c, "name" ); +		char *sub = xt_find_attr( c, "subscription" ); +		 +		if( jid && sub ) +		{ +			if( ( strcmp( sub, "both" ) == 0 || strcmp( sub, "to" ) == 0 ) ) +			{ +				if( initial || imcb_find_buddy( ic, jid ) == NULL ) +					imcb_add_buddy( ic, jid, ( group && group->text_len ) ? +					                           group->text : NULL ); +				 +				if( name ) +					imcb_rename_buddy( ic, jid, name ); +			} +			else if( strcmp( sub, "remove" ) == 0 ) +			{ +				jabber_buddy_remove_bare( ic, jid ); +				imcb_remove_buddy( ic, jid, NULL ); +			} +		} +		 +		c = c->next; +	} +	 +	if( initial ) +		imcb_connected( ic ); +	 +	return XT_HANDLED; +} + +int jabber_get_vcard( struct im_connection *ic, char *bare_jid ) +{ +	struct xt_node *node; +	 +	if( strchr( bare_jid, '/' ) ) +		return 1;	/* This was an error, but return 0 should only be done if the connection died... */ +	 +	node = xt_new_node( "vCard", NULL, NULL ); +	xt_add_attr( node, "xmlns", XMLNS_VCARD ); +	node = jabber_make_packet( "iq", "get", bare_jid, node ); +	 +	jabber_cache_add( ic, node, jabber_iq_display_vcard ); +	return jabber_write_packet( ic, node ); +} + +static xt_status jabber_iq_display_vcard( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ) +{ +	struct xt_node *vc, *c, *sc; /* subchild, ic is already in use ;-) */ +	GString *reply; +	char *s; +	 +	if( ( s = xt_find_attr( node, "type" ) ) == NULL || +	    strcmp( s, "result" ) != 0 || +	    ( vc = xt_find_node( node->children, "vCard" ) ) == NULL ) +	{ +		s = xt_find_attr( orig, "to" ); /* If this returns NULL something's wrong.. */ +		imcb_log( ic, "Could not retrieve vCard of %s", s ? s : "(NULL)" ); +		return XT_HANDLED; +	} +	 +	s = xt_find_attr( orig, "to" ); +	reply = g_string_new( "vCard information for " ); +	reply = g_string_append( reply, s ? s : "(NULL)" ); +	reply = g_string_append( reply, ":\n" ); +	 +	/* I hate this format, I really do... */ +	 +	if( ( c = xt_find_node( vc->children, "FN" ) ) && c->text_len ) +		g_string_append_printf( reply, "Name: %s\n", c->text ); +	 +	if( ( c = xt_find_node( vc->children, "N" ) ) && c->children ) +	{ +		reply = g_string_append( reply, "Full name:" ); +		 +		if( ( sc = xt_find_node( c->children, "PREFIX" ) ) && sc->text_len ) +			g_string_append_printf( reply, " %s", sc->text ); +		if( ( sc = xt_find_node( c->children, "GIVEN" ) ) && sc->text_len ) +			g_string_append_printf( reply, " %s", sc->text ); +		if( ( sc = xt_find_node( c->children, "MIDDLE" ) ) && sc->text_len ) +			g_string_append_printf( reply, " %s", sc->text ); +		if( ( sc = xt_find_node( c->children, "FAMILY" ) ) && sc->text_len ) +			g_string_append_printf( reply, " %s", sc->text ); +		if( ( sc = xt_find_node( c->children, "SUFFIX" ) ) && sc->text_len ) +			g_string_append_printf( reply, " %s", sc->text ); +		 +		reply = g_string_append_c( reply, '\n' ); +	} +	 +	if( ( c = xt_find_node( vc->children, "NICKNAME" ) ) && c->text_len ) +		g_string_append_printf( reply, "Nickname: %s\n", c->text ); +	 +	if( ( c = xt_find_node( vc->children, "BDAY" ) ) && c->text_len ) +		g_string_append_printf( reply, "Date of birth: %s\n", c->text ); +	 +	/* Slightly alternative use of for... ;-) */ +	for( c = vc->children; ( c = xt_find_node( c, "EMAIL" ) ); c = c->next ) +	{ +		if( ( sc = xt_find_node( c->children, "USERID" ) ) == NULL || sc->text_len == 0 ) +			continue; +		 +		if( xt_find_node( c->children, "HOME" ) ) +			s = "Home"; +		else if( xt_find_node( c->children, "WORK" ) ) +			s = "Work"; +		else +			s = "Misc."; +		 +		g_string_append_printf( reply, "%s e-mail address: %s\n", s, sc->text ); +	} +	 +	if( ( c = xt_find_node( vc->children, "URL" ) ) && c->text_len ) +		g_string_append_printf( reply, "Homepage: %s\n", c->text ); +	 +	/* Slightly alternative use of for... ;-) */ +	for( c = vc->children; ( c = xt_find_node( c, "ADR" ) ); c = c->next ) +	{ +		if( xt_find_node( c->children, "HOME" ) ) +			s = "Home"; +		else if( xt_find_node( c->children, "WORK" ) ) +			s = "Work"; +		else +			s = "Misc."; +		 +		g_string_append_printf( reply, "%s address: ", s ); +		 +		if( ( sc = xt_find_node( c->children, "STREET" ) ) && sc->text_len ) +			g_string_append_printf( reply, "%s ", sc->text ); +		if( ( sc = xt_find_node( c->children, "EXTADR" ) ) && sc->text_len ) +			g_string_append_printf( reply, "%s, ", sc->text ); +		if( ( sc = xt_find_node( c->children, "PCODE" ) ) && sc->text_len ) +			g_string_append_printf( reply, "%s, ", sc->text ); +		if( ( sc = xt_find_node( c->children, "LOCALITY" ) ) && sc->text_len ) +			g_string_append_printf( reply, "%s, ", sc->text ); +		if( ( sc = xt_find_node( c->children, "REGION" ) ) && sc->text_len ) +			g_string_append_printf( reply, "%s, ", sc->text ); +		if( ( sc = xt_find_node( c->children, "CTRY" ) ) && sc->text_len ) +			g_string_append_printf( reply, "%s", sc->text ); +		 +		if( reply->str[reply->len-2] == ',' ) +			reply = g_string_truncate( reply, reply->len-2 ); +		 +		reply = g_string_append_c( reply, '\n' ); +	} +	 +	for( c = vc->children; ( c = xt_find_node( c, "TEL" ) ); c = c->next ) +	{ +		if( ( sc = xt_find_node( c->children, "NUMBER" ) ) == NULL || sc->text_len == 0 ) +			continue; +		 +		if( xt_find_node( c->children, "HOME" ) ) +			s = "Home"; +		else if( xt_find_node( c->children, "WORK" ) ) +			s = "Work"; +		else +			s = "Misc."; +		 +		g_string_append_printf( reply, "%s phone number: %s\n", s, sc->text ); +	} +	 +	if( ( c = xt_find_node( vc->children, "DESC" ) ) && c->text_len ) +		g_string_append_printf( reply, "Other information:\n%s", c->text ); +	 +	/* *sigh* */ +	 +	imcb_log( ic, "%s", reply->str ); +	g_string_free( reply, TRUE ); +	 +	return XT_HANDLED; +} + +static xt_status jabber_add_to_roster_callback( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ); + +int jabber_add_to_roster( struct im_connection *ic, char *handle, char *name ) +{ +	struct xt_node *node; +	int st; +	 +	/* Build the item entry */ +	node = xt_new_node( "item", NULL, NULL ); +	xt_add_attr( node, "jid", handle ); +	if( name ) +		xt_add_attr( node, "name", name ); +	 +	/* And pack it into a roster-add packet */ +	node = xt_new_node( "query", NULL, node ); +	xt_add_attr( node, "xmlns", XMLNS_ROSTER ); +	node = jabber_make_packet( "iq", "set", NULL, node ); +	jabber_cache_add( ic, node, jabber_add_to_roster_callback ); +	 +	st = jabber_write_packet( ic, node ); +	 +	return st; +} + +static xt_status jabber_add_to_roster_callback( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ) +{ +	char *s, *jid = NULL; +	struct xt_node *c; +	 +	if( ( c = xt_find_node( orig->children, "query" ) ) && +	    ( c = xt_find_node( c->children, "item" ) ) && +	    ( jid = xt_find_attr( c, "jid" ) ) && +	    ( s = xt_find_attr( node, "type" ) ) && +	    strcmp( s, "result" ) == 0 ) +	{ +		if( imcb_find_buddy( ic, jid ) == NULL ) +			imcb_add_buddy( ic, jid, NULL ); +	} +	else +	{ +		imcb_log( ic, "Error while adding `%s' to your contact list.", +		          jid ? jid : "(unknown handle)" ); +	} +	 +	return XT_HANDLED; +} + +int jabber_remove_from_roster( struct im_connection *ic, char *handle ) +{ +	struct xt_node *node; +	int st; +	 +	/* Build the item entry */ +	node = xt_new_node( "item", NULL, NULL ); +	xt_add_attr( node, "jid", handle ); +	xt_add_attr( node, "subscription", "remove" ); +	 +	/* And pack it into a roster-add packet */ +	node = xt_new_node( "query", NULL, node ); +	xt_add_attr( node, "xmlns", XMLNS_ROSTER ); +	node = jabber_make_packet( "iq", "set", NULL, node ); +	 +	st = jabber_write_packet( ic, node ); +	 +	xt_free_node( node ); +	return st; +} diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index ac6481a1..0e23b4d4 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -1,2350 +1,534 @@ -/* -*- 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); +#include "ssl_client.h" +#include "xmltree.h" +#include "bitlbee.h" +#include "jabber.h" +#include "md5.h" +#include "base64.h" -	return; -} +GSList *jabber_connections; -static void gjab_recv(gjconn gjc) +static void jabber_init( account_t *acc )  { -	static char buf[4096]; -	int len; - -	if (!gjc || gjc->state == JCONN_STATE_OFF) -		return; +	set_t *s; -	if (gjc->ssl) -		len = ssl_read(gjc->ssl, buf, sizeof(buf) - 1); -	else -		len = read(gjc->fd, buf, sizeof(buf) - 1); +	s = set_add( &acc->set, "port", JABBER_PORT_DEFAULT, set_eval_int, acc ); +	s->flags |= ACC_SET_OFFLINE_ONLY; -	if (len > 0) { -		struct jabber_data *jd = GJ_GC(gjc)->proto_data; -		buf[len] = '\0'; -		XML_Parse(gjc->parser, buf, len, 0); -		if (jd->die) -			signoff(GJ_GC(gjc)); -	} else if (len == 0 || (len < 0 && (!sockerr_again() || gjc->ssl))) { -		STATE_EVT(JCONN_STATE_OFF) -	} -} - -static void startElement(void *userdata, const char *name, const char **attribs) -{ -	xmlnode x; -	gjconn gjc = (gjconn) userdata; - -	if (gjc->current) { -		/* Append the node to the current one */ -		x = xmlnode_insert_tag(gjc->current, name); -		xmlnode_put_expat_attribs(x, attribs); - -		gjc->current = x; -	} else { -		x = xmlnode_new_tag(name); -		xmlnode_put_expat_attribs(x, attribs); -		if (strcmp(name, "stream:stream") == 0) { -			/* special case: name == stream:stream */ -			/* id attrib of stream is stored for digest auth */ -			gjc->sid = g_strdup(xmlnode_get_attrib(x, "id")); -			/* STATE_EVT(JCONN_STATE_AUTH) */ -			xmlnode_free(x); -		} else { -			gjc->current = x; -		} -	} -} - -static void endElement(void *userdata, const char *name) -{ -	gjconn gjc = (gjconn) userdata; -	xmlnode x; -	jpacket p; - -	if (gjc->current == NULL) { -		/* we got </stream:stream> */ -		STATE_EVT(JCONN_STATE_OFF) -		    return; -	} - -	x = xmlnode_get_parent(gjc->current); - -	if (!x) { -		/* it is time to fire the event */ -		p = jpacket_new(gjc->current); - -		if (gjc->on_packet) -			(gjc->on_packet) (gjc, p); -		else -			xmlnode_free(gjc->current); -	} - -	gjc->current = x; -} - -static void jabber_callback(gpointer data, gint source, GaimInputCondition condition) -{ -	struct gaim_connection *gc = (struct gaim_connection *)data; -	struct jabber_data *jd = (struct jabber_data *)gc->proto_data; - -	gjab_recv(jd->gjc); -} - -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 void gjab_connected(gpointer data, gint source, GaimInputCondition 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; -	} - -	jd = gc->proto_data; -	gjc = jd->gjc; - -	if (gjc->fd != source) -		gjc->fd = source; - -	if (source == -1) { -		STATE_EVT(JCONN_STATE_OFF) -		return; -	} - -	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 = gaim_input_add(gjc->fd, GAIM_INPUT_READ, jabber_callback, gc); -} - -static void gjab_connected_ssl(gpointer data, void *source, GaimInputCondition cond) -{ -	struct gaim_connection *gc = data; -	struct jabber_data *jd; -	gjconn gjc; +	s = set_add( &acc->set, "priority", "0", set_eval_priority, acc ); -	jd = gc->proto_data; -	gjc = jd->gjc; +	s = set_add( &acc->set, "resource", "BitlBee", NULL, acc ); +	s->flags |= ACC_SET_OFFLINE_ONLY; -	if (source == NULL) { -		STATE_EVT(JCONN_STATE_OFF) -		return; -	} +	s = set_add( &acc->set, "resource_select", "priority", NULL, acc ); -	if (!g_slist_find(get_connections(), gc)) { -		ssl_disconnect(source); -		return; -	} +	s = set_add( &acc->set, "server", NULL, set_eval_account, acc ); +	s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY; +	 +	s = set_add( &acc->set, "ssl", "false", set_eval_bool, acc ); +	s->flags |= ACC_SET_OFFLINE_ONLY; -	gjab_connected(data, gjc->fd, cond); +	s = set_add( &acc->set, "tls", "try", set_eval_tls, acc ); +	s->flags |= ACC_SET_OFFLINE_ONLY; +	 +	s = set_add( &acc->set, "xmlconsole", "false", set_eval_bool, acc ); +	s->flags |= ACC_SET_OFFLINE_ONLY;  } -static void gjab_start(gjconn gjc) -{ -	struct aim_user *user; -	int port = -1, ssl = 0; -	char *server = NULL, *s; - -	if (!gjc || gjc->state != JCONN_STATE_OFF) -		return; +static void jabber_generate_id_hash( struct jabber_data *jd ); -	user = GJ_GC(gjc)->user; -	if (*user->proto_opt[0]) { -		/* If there's a dot, assume there's a hostname in the beginning */ -		if (strchr(user->proto_opt[0], '.')) { -			server = g_strdup(user->proto_opt[0]); -			if ((s = strchr(server, ':'))) -				*s = 0; -		} -		 -		/* After the hostname, there can be a port number */ -		s = strchr(user->proto_opt[0], ':'); -		if (s && isdigit(s[1])) -			sscanf(s + 1, "%d", &port); -		 -		/* And if there's the string ssl, the user wants an SSL-connection */ -		if (strstr(user->proto_opt[0], ":ssl") || g_strcasecmp(user->proto_opt[0], "ssl") == 0) -			ssl = 1; -	} +static void jabber_login( account_t *acc ) +{ +	struct im_connection *ic = imcb_new( acc ); +	struct jabber_data *jd = g_new0( struct jabber_data, 1 ); +	struct ns_srv_reply *srv = NULL; +	char *connect_to, *s; -	if (port == -1 && !ssl) -		port = DEFAULT_PORT; -	else if (port == -1 && ssl) -		port = DEFAULT_PORT_SSL; -	else 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; -	} +	/* For now this is needed in the _connected() handlers if using +	   GLib event handling, to make sure we're not handling events +	   on dead connections. */ +	jabber_connections = g_slist_prepend( jabber_connections, ic ); -	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->ic = ic; +	ic->proto_data = jd; -	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)); -	} +	jd->username = g_strdup( acc->user ); +	jd->server = strchr( jd->username, '@' ); -	g_free(server); +	jd->fd = jd->r_inpa = jd->w_inpa = -1; -	if (!user->gc || (gjc->fd < 0)) { -		STATE_EVT(JCONN_STATE_OFF) +	if( jd->server == NULL ) +	{ +		imcb_error( ic, "Incomplete account name (format it like <username@jabberserver.name>)" ); +		imc_logout( ic, FALSE );  		return;  	} -} - -/* - * Find existing/active Jabber chat - */ -static struct jabber_chat *find_existing_chat(struct gaim_connection *gc, jid chat) -{ -	GSList *jcs = ((struct jabber_data *)gc->proto_data)->chats; -	struct jabber_chat *jc = NULL; - -	while (jcs) { -		jc = jcs->data; -		if (jc->state == JCS_ACTIVE && !jid_cmpx(chat, jc->Jid, JID_USER | JID_SERVER)) -			break; -		jc = NULL; -		jcs = jcs->next; -	} - -	return jc; -} - -/* - * Find pending chat - */ -static struct jabber_chat *find_pending_chat(struct gaim_connection *gc, jid chat) -{ -	GSList *jcs = ((struct jabber_data *)gc->proto_data)->chats; -	struct jabber_chat *jc = NULL; - -	while (jcs) { -		jc = jcs->data; -		if (jc->state == JCS_PENDING && !jid_cmpx(chat, jc->Jid, JID_USER | JID_SERVER)) -			break; -		jc = NULL; -		jcs = jcs->next; -	} - -	return jc; -} - -static gboolean find_chat_buddy(struct conversation *b, char *name) -{ -	GList *m = b->in_room; - -	while (m) { -		if (!strcmp(m->data, name)) -			return TRUE; -		m = m->next; -	} - -	return FALSE; -} - -/* - * Remove a buddy from the (gaim) buddylist (if he's on it) - */ -static void jabber_remove_gaim_buddy(struct gaim_connection *gc, char *buddyname) -{ -	struct buddy *b; - -	if ((b = find_buddy(gc, buddyname)) != NULL) { -		/* struct group *group; - -		group = find_group_by_buddy(gc, buddyname); -		remove_buddy(gc, group, b); */ -		jabber_remove_buddy(gc, b->name, JABBER_GROUP); -	} -} - -/* - * keep track of away msg same as yahoo plugin - */ -static void jabber_track_away(gjconn gjc, jpacket p, char *name, char *type) -{ -	struct jabber_data *jd = GJ_GC(gjc)->proto_data; -	gpointer val = g_hash_table_lookup(jd->hash, name); -	char *show; -	char *vshow = NULL; -	char *status = NULL; -	char *msg = NULL; - -	if (type && (g_strcasecmp(type, "unavailable") == 0)) { -		vshow = _("Unavailable"); -	} else { -		if((show = xmlnode_get_tag_data(p->x, "show")) != NULL) { -			if (!g_strcasecmp(show, "away")) { -				vshow = _("Away"); -			} else if (!g_strcasecmp(show, "chat")) { -				vshow = _("Online"); -			} else if (!g_strcasecmp(show, "xa")) { -				vshow = _("Extended Away"); -			} else if (!g_strcasecmp(show, "dnd")) { -				vshow = _("Do Not Disturb"); -			} -		} -	} - -	status = xmlnode_get_tag_data(p->x, "status"); - -	if(vshow != NULL || status != NULL ) { -		/* kinda hokey, but it works :-) */ -		msg = g_strdup_printf("%s%s%s", -			(vshow == NULL? "" : vshow), -			(vshow == NULL || status == NULL? "" : ": "), -			(status == NULL? "" : status)); -	} else { -		msg = g_strdup(_("Online")); -	} - -	if (val) { -		g_free(val); -		g_hash_table_insert(jd->hash, name, msg); -	} else { -		g_hash_table_insert(jd->hash, g_strdup(name), msg); -	} -} - -static time_t iso8601_to_time(char *timestamp) -{ -	struct tm t; -	time_t retval = 0; - -	if(sscanf(timestamp,"%04d%02d%02dT%02d:%02d:%02d", -		&t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec)) +	 +	/* So don't think of free()ing jd->server.. :-) */ +	*jd->server = 0; +	jd->server ++; +	 +	if( ( s = strchr( jd->server, '/' ) ) )  	{ -		t.tm_year -= 1900; -		t.tm_mon -= 1; -		t.tm_isdst = 0; -		retval = mktime(&t); -#		ifdef HAVE_TM_GMTOFF -			retval += t.tm_gmtoff; -#		else -#		        ifdef HAVE_TIMEZONE -				tzset();	/* making sure */ -				retval -= timezone; -#		        endif -#		endif +		*s = 0; +		set_setstr( &acc->set, "resource", s + 1 ); +		 +		/* Also remove the /resource from the original variable so we +		   won't have to do this again every time. */ +		s = strchr( acc->user, '/' ); +		*s = 0;  	} - -	return retval; -} - -static void jabber_handlemessage(gjconn gjc, jpacket p) -{ -	xmlnode y, xmlns, z; -	time_t time_sent = time(NULL); - -	char *from = NULL, *msg = NULL, *type = NULL; -	char m[BUF_LONG * 2]; - -	type = xmlnode_get_attrib(p->x, "type"); - -	z = xmlnode_get_firstchild(p->x); - -	while(z) +	 +	/* This code isn't really pretty. Backwards compatibility never is... */ +	s = acc->server; +	while( s )  	{ -	   if(NSCHECK(z,NS_DELAY)) -	   { -	      char *timestamp = xmlnode_get_attrib(z,"stamp"); -	      time_sent = iso8601_to_time(timestamp); -	   } -	   z = xmlnode_get_nextsibling(z); -	} - -	if (!type || !g_strcasecmp(type, "normal") || !g_strcasecmp(type, "chat")) { - -		/* XXX namespaces could be handled better. (mid) */ -		if ((xmlns = xmlnode_get_tag(p->x, "x"))) -			type = xmlnode_get_attrib(xmlns, "xmlns"); - -		from = jid_full(p->from); -		/* -		if ((y = xmlnode_get_tag(p->x, "html"))) { -			msg = xmlnode_get_data(y); -		} else -		*/ -		if ((y = xmlnode_get_tag(p->x, "body"))) { -			msg = xmlnode_get_data(y); -		} - - -		if (!from) -			return; - -		if (type && !g_strcasecmp(type, "jabber:x:conference")) { -			/* do nothing */ -		} else if (msg) { /* whisper */ -			struct jabber_chat *jc; -			g_snprintf(m, sizeof(m), "%s", msg); -			if (((jc = find_existing_chat(GJ_GC(gjc), p->from)) != NULL) && jc->b) -				serv_got_chat_in(GJ_GC(gjc), jc->b->id, p->from->resource, 1, m, time_sent); -			else { -				int flags = 0; -				 -				if(p->from->user) { -				    from = g_strdup_printf("%s@%s", p->from->user, p->from->server); -				} else { -				    /* server message? */ -				    from = g_strdup(p->from->server); -				} -				serv_got_im(GJ_GC(gjc), from, m, flags, time_sent, -1); -				g_free(from); -			} -		} - -	} else if (!g_strcasecmp(type, "error")) { -		if ((y = xmlnode_get_tag(p->x, "error"))) { -			type = xmlnode_get_attrib(y, "code"); -			msg = xmlnode_get_data(y); -		} - -		if (msg) { -			from = g_strdup_printf("Error %s", type ? type : ""); -			do_error_dialog(GJ_GC(gjc), msg, from); -			g_free(from); -		} -	} else if (!g_strcasecmp(type, "headline")) { -		char *subject, *body, *url; -		 -		y = xmlnode_get_tag( p->x, "body" ); -		body = y ? g_strdup( xmlnode_get_data( y ) ) : NULL; +		static int had_port = 0; -		y = xmlnode_get_tag( p->x, "subject" ); -		subject = y ? g_strdup( xmlnode_get_data( y ) ) : NULL; -		 -		url = NULL; -		z = xmlnode_get_firstchild(p->x); -		while( z ) +		if( strncmp( s, "ssl", 3 ) == 0 ) +		{ +			set_setstr( &acc->set, "ssl", "true" ); +			 +			/* 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 ++; +			 +			/* Only set this if the user didn't specify a custom +			   port number already... */ +			if( !had_port ) +				set_setint( &acc->set, "port", 5223 ); +		} +		else if( isdigit( *s ) )  		{ -			char *xtype = xmlnode_get_attrib( z, "xmlns" ); +			int i; -			if( xtype && g_strcasecmp( xtype, "jabber:x:oob" ) == 0 && -			             ( y = xmlnode_get_tag( z, "url" ) ) ) +			/* 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 )  			{ -				url = g_strdup( xmlnode_get_data( y ) ); -				break; +				sscanf( s, "%d", &i ); +				set_setint( &acc->set, "port", i ); +				 +				/* See above. */ +				*s = 0; +				s ++;  			} -			z = xmlnode_get_nextsibling( z ); +			had_port = 1;  		} -		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; +		s = strchr( s, ':' ); +		if( s ) +		{ +			*s = 0; +			s ++;  		} -	} else { -		state = 0;  	} - -	who = jid_new(gjc->p, from); -	if (who->user == NULL) { -		/* FIXME: transport */ +	 +	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 ); +	 +	/* Figure out the hostname to connect to. */ +	if( acc->server && *acc->server ) +		connect_to = acc->server; +	else if( ( srv = srv_lookup( "xmpp-client", "tcp", jd->server ) ) || +		 ( srv = srv_lookup( "jabber-client", "tcp", jd->server ) ) ) +		connect_to = srv->name; +	else +		connect_to = jd->server; +	 +	imcb_log( ic, "Connecting" ); +	 +	if( set_getint( &acc->set, "port" ) < JABBER_PORT_MIN || +	    set_getint( &acc->set, "port" ) > JABBER_PORT_MAX ) +	{ +		imcb_log( ic, "Incorrect port number, must be in the %d-%d range", +		               JABBER_PORT_MIN, JABBER_PORT_MAX ); +		imc_logout( ic, FALSE );  		return;  	} - -	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); +	 +	/* For non-SSL connections we can try to use the port # from the SRV +	   reply, but let's not do that when using SSL, SSL usually runs on +	   non-standard ports... */ +	if( set_getbool( &acc->set, "ssl" ) ) +	{ +		jd->ssl = ssl_connect( connect_to, set_getint( &acc->set, "port" ), jabber_connected_ssl, ic ); +		jd->fd = jd->ssl ? ssl_getfd( jd->ssl ) : -1;  	} -	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; +	else +	{ +		jd->fd = proxy_connect( connect_to, srv ? srv->port : set_getint( &acc->set, "port" ), jabber_connected_plain, ic );  	} - -	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) { +	g_free( srv ); +	 +	if( jd->fd == -1 ) +	{ +		imcb_error( ic, "Could not connect to server" ); +		imc_logout( ic, TRUE ); +		  		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); -				 -				add_buddy(GJ_GC(gjc), groupname, buddyname, -					name ? name : buddyname); -				if(present) { -					serv_got_update(GJ_GC(gjc), buddyname, 1, 0, signon, idle, uc, 0); -				} -			} else if(name != NULL && strcmp(b->show, name)) { -				strncpy(b->show, name, BUDDY_ALIAS_MAXLEN); -				b->show[BUDDY_ALIAS_MAXLEN - 1] = '\0';	/* cheap safety feature */ -				serv_buddy_rename(GJ_GC(gjc), buddyname, b->show); -			} -		} -	}  else if (BUD_USUB_TO_PEND(sub, ask) || BUD_USUBD_TO(sub, ask) || !g_strcasecmp(sub, "remove")) { -		jabber_remove_gaim_buddy(GJ_GC(gjc), buddyname); -	} -	g_free(buddyname); - -} - -static void jabber_handleroster(gjconn gjc, xmlnode querynode) -{ -	xmlnode x; - -	x = xmlnode_get_firstchild(querynode); -	while (x) { -		jabber_handlebuddy(gjc, x); -		x = xmlnode_get_nextsibling(x); +	 +	if( set_getbool( &acc->set, "xmlconsole" ) ) +	{ +		jd->flags |= JFLAG_XMLCONSOLE; +		/* Shouldn't really do this at this stage already, maybe. But +		   I think this shouldn't break anything. */ +		imcb_add_buddy( ic, JABBER_XMLCONSOLE_HANDLE, NULL );  	} - -	account_online(GJ_GC(gjc)); +	 +	jabber_generate_id_hash( jd );  } -static void jabber_handleauthresp(gjconn gjc, jpacket p) +static void jabber_generate_id_hash( struct jabber_data *jd )  { -	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; -		} -	} 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")); -		} - -		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); +	md5_state_t id_hash; +	md5_byte_t binbuf[16]; +	char *s; -	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]; +	md5_init( &id_hash ); +	md5_append( &id_hash, (unsigned char *) jd->username, strlen( jd->username ) ); +	md5_append( &id_hash, (unsigned char *) jd->server, strlen( jd->server ) ); +	s = set_getstr( &jd->ic->acc->set, "resource" ); +	md5_append( &id_hash, (unsigned char *) s, strlen( s ) ); +	random_bytes( binbuf, 16 ); +	md5_append( &id_hash, binbuf, 16 ); +	md5_finish( &id_hash, binbuf ); -	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); -			} -		} -	} - -	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; -	} - -	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; -	} -	return; +	s = base64_encode( binbuf, 9 ); +	jd->cached_id_prefix = g_strdup_printf( "%s%s", JABBER_CACHED_ID, s ); +	g_free( s );  } -static void jabber_login(struct aim_user *user) +static void jabber_logout( struct im_connection *ic )  { -	struct gaim_connection *gc = new_gaim_conn(user); -	struct jabber_data *jd = gc->proto_data = g_new0(struct jabber_data, 1); -	char *loginname = create_valid_jid(user->username, DEFAULT_SERVER, "BitlBee"); - -	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, user->password, gc))) { -		g_free(loginname); -		hide_login_progress(gc, _("Unable to connect")); -		signoff(gc); -		return; -	} - -	g_free(loginname); -	gjab_state_handler(jd->gjc, jabber_handlestate); -	gjab_packet_handler(jd->gjc, jabber_handlepacket); -	jd->gjc->queries = g_hash_table_new(g_str_hash, g_str_equal); -	gjab_start(jd->gjc); -} - -static gboolean jabber_destroy_hash(gpointer key, gpointer val, gpointer data) { -   	g_free(key); -	g_free(val); -	return TRUE; +	struct jabber_data *jd = ic->proto_data; +	 +	if( jd->fd >= 0 ) +		jabber_end_stream( ic ); +	 +	while( ic->groupchats ) +		jabber_chat_free( ic->groupchats ); +	 +	if( jd->r_inpa >= 0 ) +		b_event_remove( jd->r_inpa ); +	if( jd->w_inpa >= 0 ) +		b_event_remove( jd->w_inpa ); +	 +	if( jd->ssl ) +		ssl_disconnect( jd->ssl ); +	if( jd->fd >= 0 ) +		closesocket( jd->fd ); +	 +	if( jd->tx_len ) +		g_free( jd->txq ); +	 +	if( jd->node_cache ) +		g_hash_table_destroy( jd->node_cache ); +	 +	xt_free( jd->xt ); +	 +	g_free( jd->cached_id_prefix ); +	g_free( jd->away_message ); +	g_free( jd->username ); +	g_free( jd ); +	 +	jabber_connections = g_slist_remove( jabber_connections, ic );  } -static gboolean jabber_free(gpointer data) +static int jabber_buddy_msg( struct im_connection *ic, char *who, char *message, int flags )  { -	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; +	struct jabber_data *jd = ic->proto_data; +	struct jabber_buddy *bud; +	struct xt_node *node; +	char *s; +	int st; +	 +	if( g_strcasecmp( who, JABBER_XMLCONSOLE_HANDLE ) == 0 ) +		return jabber_write( ic, message, strlen( message ) ); +	 +	if( ( s = strchr( who, '=' ) ) && jabber_chat_by_jid( ic, s + 1 ) ) +		bud = jabber_buddy_by_ext_jid( ic, who, 0 ); +	else +		bud = jabber_buddy_by_jid( ic, who, 0 ); +	 +	node = xt_new_node( "body", message, NULL ); +	node = jabber_make_packet( "message", "chat", bud ? bud->full_jid : who, node ); +	 +	if( bud && ( jd->flags & JFLAG_WANT_TYPING ) && +	    ( ( bud->flags & JBFLAG_DOES_XEP85 ) || +	     !( bud->flags & JBFLAG_PROBED_XEP85 ) ) ) +	{ +		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;  	} -	g_free(jd); - -	return FALSE; +	 +	st = jabber_write_packet( ic, node ); +	xt_free_node( node ); +	 +	return st;  } -static void jabber_close(struct gaim_connection *gc) +static GList *jabber_away_states( struct im_connection *ic )  { -	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) -		gaim_input_remove(gc->inpa); - -	if(jd) { -		g_timeout_add(50, jabber_free, jd); -		if(jd->gjc != NULL) -			xmlnode_free(jd->gjc->current); -	} -	gc->proto_data = NULL; +	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 int jabber_send_im(struct gaim_connection *gc, char *who, char *message, int len, int flags) +static void jabber_get_info( struct im_connection *ic, char *who )  { -	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); +	struct jabber_data *jd = ic->proto_data; +	struct jabber_buddy *bud; +	 +	if( strchr( who, '/' ) ) +		bud = jabber_buddy_by_jid( ic, who, 0 );  	else -		realwho = g_strdup(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); +	{ +		char *s = jabber_normalize( who ); +		bud = g_hash_table_lookup( jd->buddies, s ); +		g_free( s );  	} - -	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; */ -	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); +	while( bud ) +	{ +		imcb_log( ic, "Buddy %s (%d) information:\nAway state: %s\nAway message: %s", +		                   bud->full_jid, bud->priority, +		                   bud->away_state ? bud->away_state->full_name : "(none)", +		                   bud->away_message ? : "(none)" ); +		bud = bud->next;  	} +	 +	jabber_get_vcard( ic, bud ? bud->full_jid : who );  } -/* - * Change buddy's group on server roster - */ -static void jabber_group_change(struct gaim_connection *gc, char *name, char *old_group, char *new_group) +static void jabber_set_away( struct im_connection *ic, char *state_txt, char *message )  { -	if(strcmp(old_group, new_group)) { -		jabber_roster_update(gc, name); -	} +	struct jabber_data *jd = ic->proto_data; +	struct jabber_away_state *state; +	 +	/* Save all this info. We need it, for example, when changing the priority setting. */ +	state = (void *) jabber_away_state_by_name( state_txt ); +	jd->away_state = state ? state : (void *) jabber_away_state_list; /* Fall back to "Away" if necessary. */ +	g_free( jd->away_message ); +	jd->away_message = ( message && *message ) ? g_strdup( message ) : NULL; +	 +	presence_send_update( ic );  } -static void jabber_add_buddy(struct gaim_connection *gc, char *name) +static void jabber_add_buddy( struct im_connection *ic, char *who, char *group )  { -	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)) +	struct jabber_data *jd = ic->proto_data; +	 +	if( g_strcasecmp( who, JABBER_XMLCONSOLE_HANDLE ) == 0 ) +	{ +		jd->flags |= JFLAG_XMLCONSOLE; +		imcb_add_buddy( ic, JABBER_XMLCONSOLE_HANDLE, NULL );  		return; - -	if (!strchr(name, '@')) -		realwho = g_strdup_printf("%s@%s", name, gjc->user->server); -	else { -		jid who; -		 -		if((who = jid_new(gjc->p, name)) == NULL) { -			char *msg = g_strdup_printf("%s: \"%s\"", _("Invalid Jabber I.D."), name); -			do_error_dialog(GJ_GC(gjc), msg, _("Jabber Error")); -			g_free(msg); -			jabber_remove_gaim_buddy(gc, name); -			return; -		} -		if (who->user == NULL) { -			/* FIXME: transport */ -			return; -		} -		realwho = g_strdup_printf("%s@%s", who->user, who->server);  	} - -	x = xmlnode_new_tag("presence"); -	xmlnode_put_attrib(x, "to", realwho); -	xmlnode_put_attrib(x, "type", "subscribe"); -	gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x); -	xmlnode_free(x); - -	jabber_roster_update(gc, realwho); - -	g_free(realwho); +	 +	if( jabber_add_to_roster( ic, who, NULL ) ) +		presence_send_request( ic, who, "subscribe" );  } -static void jabber_remove_buddy(struct gaim_connection *gc, char *name, char *group) +static void jabber_remove_buddy( struct im_connection *ic, char *who, char *group )  { -	xmlnode x; -	char *realwho; -	gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; - -	if (!name) +	struct jabber_data *jd = ic->proto_data; +	 +	if( g_strcasecmp( who, JABBER_XMLCONSOLE_HANDLE ) == 0 ) +	{ +		jd->flags &= ~JFLAG_XMLCONSOLE; +		/* Not necessary for now. And for now the code isn't too +		   happy if the buddy is completely gone right after calling +		   this function already. +		imcb_remove_buddy( ic, JABBER_XMLCONSOLE_HANDLE, NULL ); +		*/  		return; - -	if (!strchr(name, '@')) -		realwho = g_strdup_printf("%s@%s", name, gjc->user->server); -	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);  	} -	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"); -	} -	*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); +	/* We should always do this part. Clean up our administration a little bit. */ +	jabber_buddy_remove_bare( ic, who ); +	if( jabber_remove_from_roster( ic, who ) ) +		presence_send_request( ic, who, "unsubscribe" );  } -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 struct groupchat *jabber_chat_join_( struct im_connection *ic, char *room, char *nick, char *password )  { -	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); +	if( strchr( room, '@' ) == NULL ) +		imcb_error( ic, "Invalid room name: %s", room ); +	else if( jabber_chat_by_jid( ic, room ) ) +		imcb_error( ic, "Already present in chat `%s'", room ); +	else +		return jabber_chat_join( ic, room, nick, password ); +	 +	return NULL;  } -/* - * 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_chat_msg_( struct groupchat *c, char *message, int flags )  { -	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( c && message ) +		jabber_chat_msg( c, message, flags );  } -/* - * Used by XML_Parse to end an xmlnode - */ -static void xmlstr2xmlnode_endElement(void *userdata, const char *name) +static void jabber_chat_topic_( struct groupchat *c, char *topic )  { -	xmlstr2xmlnode_parser xmlp = (xmlstr2xmlnode_parser) userdata; -	xmlnode x; - -	if (xmlp->current != NULL && (x = xmlnode_get_parent(xmlp->current)) != NULL) { -		xmlp->current = x; -	} +	if( c && topic ) +		jabber_chat_topic( c, topic );  } -/* - * Parse an XML-encoded string into an xmlnode tree - * - * Caller is responsible for freeing the returned xmlnode - */ -static xmlnode xmlstr2xmlnode(char *xmlstring) +static void jabber_chat_leave_( struct groupchat *c )  { -	xmlstr2xmlnode_parser my_parser = g_new(xmlstr2xmlnode_parser_struct, 1); -	xmlnode x = NULL; - -	my_parser->parser = XML_ParserCreate(NULL); -	my_parser->current = NULL; - -	XML_SetUserData(my_parser->parser, (void *)my_parser); -	XML_SetElementHandler(my_parser->parser, xmlstr2xmlnode_startElement, xmlstr2xmlnode_endElement); -	XML_SetCharacterDataHandler(my_parser->parser, xmlstr2xmlnode_charData); -	XML_Parse(my_parser->parser, xmlstring, strlen(xmlstring), 0); - -	x = my_parser->current; - -	XML_ParserFree(my_parser->parser); -	g_free(my_parser); - -	return(x); +	if( c ) +		jabber_chat_leave( c, NULL );  } -/* - * 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_chat_invite_( struct groupchat *c, char *who, char *msg )  { -	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; +	struct jabber_chat *jc = c->data; +	gchar *msg_alt = NULL; -		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)); +	if( msg == NULL ) +		msg_alt = g_strdup_printf( "%s invited you to %s", c->ic->acc->user, jc->name ); +	 +	if( c && who ) +		jabber_chat_invite( c, who, msg ? msg : msg_alt ); +	 +	g_free( msg_alt );  } -/* - * Send vCard info to Jabber server - */ -static void jabber_set_info(struct gaim_connection *gc, char *info) +static void jabber_keepalive( struct im_connection *ic )  { -	xmlnode x, vc_node; -	char *id; -	struct jabber_data *jd = gc->proto_data; -	gjconn gjc = jd->gjc; - -	x = xmlnode_new_tag("iq"); -	xmlnode_put_attrib(x,"type","set"); - -	id = gjab_getid(gjc); +	/* Just any whitespace character is enough as a keepalive for XMPP sessions. */ +	jabber_write( ic, "\n", 1 ); -	xmlnode_put_attrib(x, "id", id); - -	/* -	 * Send only if there's actually any *information* to send -	 */ -	if((vc_node = xmlstr2xmlnode(info)) != NULL && xmlnode_get_name(vc_node) != NULL && -			g_strncasecmp(xmlnode_get_name(vc_node), "vcard", 5) == 0) { -		xmlnode_insert_tag_node(x, vc_node); -		gjab_send(gjc, x); -	} - -	xmlnode_free(x); +	/* This runs the garbage collection every minute, which means every packet +	   is in the cache for about a minute (which should be enough AFAIK). */ +	jabber_cache_clean( ic );  } -/* - * displays a Jabber vCard - */ -static void jabber_handlevcard(gjconn gjc, xmlnode querynode, char *from) +static int jabber_send_typing( struct im_connection *ic, char *who, int typing )  { -	struct jabber_data *jd = GJ_GC(gjc)->proto_data; -	jid who = jid_new(gjc->p, from); -	char *status = NULL, *text = NULL; -	GString *str = g_string_sized_new(100); -	xmlnode child; - -	gchar *buddy = NULL; +	struct jabber_data *jd = ic->proto_data; +	struct jabber_buddy *bud; -	if(querynode == NULL) { -		serv_got_crap(GJ_GC(gjc), "%s - Received empty info reply from %s", _("User Info"), from); -		return; -	} - -	if(who->resource != NULL && (who->resource)[0] != '\0') { -		buddy = g_strdup_printf("%s@%s/%s", who->user, who->server, who->resource); -	} else { -		buddy = g_strdup_printf("%s@%s", who->user, who->server); -	} - -	if((status = g_hash_table_lookup(jd->hash, buddy)) == NULL) { -		status = _("Unknown"); +	/* Enable typing notification related code from now. */ +	jd->flags |= JFLAG_WANT_TYPING; +	 +	if( ( bud = jabber_buddy_by_jid( ic, who, 0 ) ) == NULL ) +	{ +		/* Sending typing notifications to unknown buddies is +		   unsupported for now. Shouldn't be a problem, I think. */ +		return 0;  	} - -	g_string_sprintfa(str, "%s: %s - %s: %s", _("Jabber ID"), buddy, _("Status"), -	                       status); - -	for(child = querynode->firstchild; child; child = child->next) +	 +	if( bud->flags & JBFLAG_DOES_XEP85 )  	{ -		xmlnode child2; - -		if(child->type != NTYPE_TAG) -			continue; - -		text = xmlnode_get_data(child); -		if(text && !strcmp(child->name, "FN")) { -			info_string_append(str, "\n", _("Full Name"), text); -		} else if (!strcmp(child->name, "N")) { -			for (child2 = child->firstchild; child2; child2 = child2->next) { -				char *text2 = NULL; - -				if (child2->type != NTYPE_TAG) -					continue; - -				text2 = xmlnode_get_data(child2); -				if (text2 && !strcmp(child2->name, "FAMILY")) { -					info_string_append(str, "\n", _("Family Name"), text2); -				} else if (text2 && !strcmp(child2->name, "GIVEN")) { -					info_string_append(str, "\n", _("Given Name"), text2); -				} else if (text2 && !strcmp(child2->name, "MIDDLE")) { -					info_string_append(str, "\n", _("Middle Name"), text2); -				} -			} -		} else if (text && !strcmp(child->name, "NICKNAME")) { -			info_string_append(str, "\n", _("Nickname"), text); -		} else if (text && !strcmp(child->name, "BDAY")) { -			info_string_append(str, "\n", _("Birthday"), text); -		} else if (!strcmp(child->name, "ADR")) { -			/* show wich address it is */ -			/* Just for the beauty of bitlbee  -			if (child->firstchild) -				g_string_sprintfa(str, "%s:\n", _("Address")); -			*/ -			for(child2 = child->firstchild; child2; child2 = child2->next) { -				char *text2 = NULL; - -				if(child2->type != NTYPE_TAG) -					continue; - -				text2 = xmlnode_get_data(child2); -				if(text2 && !strcmp(child2->name, "POBOX")) { -					info_string_append(str, "\n", -							_("P.O. Box"), text2); -				} else if(text2 && !strcmp(child2->name, "EXTADR")) { -					info_string_append(str, "\n", -							_("Extended Address"), text2); -				} else if(text2 && !strcmp(child2->name, "STREET")) { -					info_string_append(str, "\n", -							_("Street Address"), text2); -				} else if(text2 && !strcmp(child2->name, "LOCALITY")) { -					info_string_append(str, "\n", -							_("Locality"), text2); -				} else if(text2 && !strcmp(child2->name, "REGION")) { -					info_string_append(str, "\n", -							_("Region"), text2); -				} else if(text2 && !strcmp(child2->name, "PCODE")) { -					info_string_append(str, "\n", -							_("Postal Code"), text2); -				} else if(text2 && (!strcmp(child2->name, "CTRY") -							|| !strcmp(child2->name, "COUNTRY"))) { -					info_string_append(str, "\n", _("Country"), text2); -				} -			} -		} else if(!strcmp(child->name, "TEL")) { -			char *number = NULL; -			if ((child2 = xmlnode_get_tag(child, "NUMBER"))) { -				/* show what kind of number it is */ -				number = xmlnode_get_data(child2); -				if(number) { -					info_string_append(str, "\n", _("Telephone"), number); -				} -			} else if((number = xmlnode_get_data(child))) { -				/* lots of clients (including gaim) do this, -				 * but it's out of spec */ -				info_string_append(str, "\n", _("Telephone"), number); -			} -		} else if(!strcmp(child->name, "EMAIL")) { -			char *userid = NULL; -			if((child2 = xmlnode_get_tag(child, "USERID"))) { -				/* show what kind of email it is */ -				userid = xmlnode_get_data(child2); -				if(userid) { -					info_string_append(str, "\n", _("Email"), userid); -				} -			} else if((userid = xmlnode_get_data(child))) { -				/* lots of clients (including gaim) do this, -				 * but it's out of spec */ -				info_string_append(str, "\n", _("Email"), userid); -			} -		} else if(!strcmp(child->name, "ORG")) { -			for(child2 = child->firstchild; child2; child2 = child2->next) { -				char *text2 = NULL; - -				if(child2->type != NTYPE_TAG) -					continue; - -				text2 = xmlnode_get_data(child2); -				if(text2 && !strcmp(child2->name, "ORGNAME")) { -					info_string_append(str, "\n", _("Organization Name"), text2); -				} else if(text2 && !strcmp(child2->name, "ORGUNIT")) { -					info_string_append(str, "\n", _("Organization Unit"), text2); -				} -			} -		} else if(text && !strcmp(child->name, "TITLE")) { -			info_string_append(str, "\n", _("Title"), text); -		} else if(text && !strcmp(child->name, "ROLE")) { -			info_string_append(str, "\n", _("Role"), text); -		} else if(text && !strcmp(child->name, "DESC")) { -			g_string_sprintfa(str, "\n%s:\n%s\n%s", _("Description"),  -					text, _("End of Description")); -		} +		/* We're only allowed to send this stuff if we know the other +		   side supports it. */ +		 +		struct xt_node *node; +		char *type; +		int st; +		 +		if( typing & OPT_TYPING ) +			type = "composing"; +		else if( typing & OPT_THINKING ) +			type = "paused"; +		else +			type = "active"; +		 +		node = xt_new_node( type, NULL, NULL ); +		xt_add_attr( node, "xmlns", XMLNS_CHATSTATES ); +		node = jabber_make_packet( "message", "chat", bud->full_jid, node ); +		 +		st = jabber_write_packet( ic, node ); +		xt_free_node( node ); +		 +		return st;  	} - -	serv_got_crap(GJ_GC(gjc), "%s\n%s", _("User Info"), str->str); - -	g_free(buddy); -	g_string_free(str, TRUE); +	 +	return 1;  } -void jabber_init() +void jabber_initmodule()  { -	struct prpl *ret = g_new0(struct prpl, 1); - +	struct prpl *ret = g_new0( struct prpl, 1 ); +	  	ret->name = "jabber"; -	ret->away_states = jabber_away_states;  	ret->login = jabber_login; -	ret->close = jabber_close; -	ret->send_im = jabber_send_im; -	ret->set_info = jabber_set_info; -	ret->get_info = jabber_get_info; +	ret->init = jabber_init; +	ret->logout = jabber_logout; +	ret->buddy_msg = jabber_buddy_msg; +	ret->away_states = jabber_away_states;  	ret->set_away = jabber_set_away; -	ret->get_away = jabber_get_away_msg; +//	ret->set_info = jabber_set_info; +	ret->get_info = jabber_get_info;  	ret->add_buddy = jabber_add_buddy;  	ret->remove_buddy = jabber_remove_buddy; +	ret->chat_msg = jabber_chat_msg_; +	ret->chat_topic = jabber_chat_topic_; +	ret->chat_invite = jabber_chat_invite_; +	ret->chat_leave = jabber_chat_leave_; +	ret->chat_join = jabber_chat_join_;  	ret->keepalive = jabber_keepalive; -	ret->alias_buddy = jabber_roster_update; -	ret->group_buddy = jabber_group_change; -	ret->cmp_buddynames = g_strcasecmp; +	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..1ff0e8dd 100644 --- a/protocols/jabber/jabber.h +++ b/protocols/jabber/jabber.h @@ -1,315 +1,256 @@ -/* - *  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" + +extern GSList *jabber_connections; + +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. */ +	JFLAG_XMLCONSOLE = 64,          /* If the user added an xmlconsole buddy. */ +} 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); - - -/* --------------------------------------------------------- */ -/*                                                           */ -/* Error structures & constants                              */ -/*                                                           */ -/* --------------------------------------------------------- */ -typedef struct terror_struct +	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). */ +	JBFLAG_IS_CHATROOM = 4,         /* It's convenient to use this JID thingy for +	                                   groupchat state info too. */ +	JBFLAG_IS_ANONYMOUS = 8,        /* For anonymous chatrooms, when we don't have +	                                   have a real JID. */ +} jabber_buddy_flags_t; + +typedef enum  { -    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"} +	JCFLAG_MESSAGE_SENT = 1,        /* Set this after sending the first message, so +	                                   we can detect echoes/backlogs. */ +} jabber_chat_flags_t; -/* --------------------------------------------------------- */ -/*                                                           */ -/* 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 jabber_data  { -    /* 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); - -} *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); +	struct im_connection *ic; +	 +	int fd; +	void *ssl; +	char *txq; +	int tx_len; +	int r_inpa, w_inpa; +	 +	struct xt_parser *xt; +	jabber_flags_t flags; +	 +	char *username;		/* USERNAME@server */ +	char *server;		/* username@SERVER -=> server/domain, not hostname */ +	 +	/* After changing one of these two (or the priority setting), call +	   presence_send_update() to inform the server about the changes. */ +	struct jabber_away_state *away_state; +	char *away_message; +	 +	char *cached_id_prefix; +	GHashTable *node_cache; +	GHashTable *buddies; +}; + +struct jabber_away_state +{ +	char code[5]; +	char *full_name; +}; -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); +typedef xt_status (*jabber_cache_event) ( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ); -char *jab_auth(jconn j); -char *jab_reg(jconn j); +struct jabber_cache_entry +{ +	time_t saved_at; +	struct xt_node *node; +	jabber_cache_event func; +}; +struct jabber_buddy +{ +	char *bare_jid; +	char *full_jid; +	char *resource; +	 +	char *ext_jid; /* The JID to use in BitlBee. The real JID if possible, */ +	               /* otherwise something similar to the conference JID. */ +	 +	int priority; +	struct jabber_away_state *away_state; +	char *away_message; +	 +	time_t last_act; +	jabber_buddy_flags_t flags; +	 +	struct jabber_buddy *next; +}; + +struct jabber_chat +{ +	int flags; +	char *name; +	char *my_full_jid; /* Separate copy because of case sensitivity. */ +	struct jabber_buddy *me; +}; + +#define JABBER_XMLCONSOLE_HANDLE "xmlconsole" + +#define JABBER_PORT_DEFAULT "5222" +#define JABBER_PORT_MIN 5220 +#define JABBER_PORT_MAX 5229 + +/* 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. Also +   we'll append a hash to make sure we won't trigger on cached packets from +   other BitlBee users. :-) */ +#define JABBER_PACKET_ID "BeeP" +#define JABBER_CACHED_ID "BeeC" + +/* The number of seconds to keep cached packets before garbage collecting +   them. This gc is done on every keepalive (every minute). */ +#define JABBER_CACHE_MAX_AGE 600 + +/* 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_PING         "urn:xmpp:ping"                      /* XEP-0199 */ +#define XMLNS_VCARD        "vcard-temp"                         /* XEP-0054 */ +#define XMLNS_DELAY        "jabber:x:delay"                     /* XEP-0091 */ +#define XMLNS_CHATSTATES   "http://jabber.org/protocol/chatstates"  /* 0085 */ +#define XMLNS_DISCOVER     "http://jabber.org/protocol/disco#info"  /* 0030 */ +#define XMLNS_MUC          "http://jabber.org/protocol/muc"     /* XEP-0045 */ +#define XMLNS_MUC_USER     "http://jabber.org/protocol/muc#user"/* XEP-0045 */ +#define XMLNS_CAPS         "http://jabber.org/protocol/caps"    /* XEP-0115 */ + +/* iq.c */ +xt_status jabber_pkt_iq( struct xt_node *node, gpointer data ); +int jabber_init_iq_auth( struct im_connection *ic ); +xt_status jabber_pkt_bind_sess( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ); +int jabber_get_roster( struct im_connection *ic ); +int jabber_get_vcard( struct im_connection *ic, char *bare_jid ); +int jabber_add_to_roster( struct im_connection *ic, char *handle, char *name ); +int jabber_remove_from_roster( struct im_connection *ic, char *handle ); + +/* message.c */ +xt_status jabber_pkt_message( struct xt_node *node, gpointer data ); + +/* presence.c */ +xt_status jabber_pkt_presence( struct xt_node *node, gpointer data ); +int presence_send_update( struct im_connection *ic ); +int presence_send_request( struct im_connection *ic, char *handle, char *request ); + +/* jabber_util.c */ +char *set_eval_priority( set_t *set, char *value ); +char *set_eval_tls( set_t *set, char *value ); +struct xt_node *jabber_make_packet( char *name, char *type, char *to, struct xt_node *children ); +struct xt_node *jabber_make_error_packet( struct xt_node *orig, char *err_cond, char *err_type ); +void jabber_cache_add( struct im_connection *ic, struct xt_node *node, jabber_cache_event func ); +struct xt_node *jabber_cache_get( struct im_connection *ic, char *id ); +void jabber_cache_entry_free( gpointer entry ); +void jabber_cache_clean( struct im_connection *ic ); +xt_status jabber_cache_handle_packet( struct im_connection *ic, struct xt_node *node ); +const struct jabber_away_state *jabber_away_state_by_code( char *code ); +const struct jabber_away_state *jabber_away_state_by_name( char *name ); +void jabber_buddy_ask( struct im_connection *ic, char *handle ); +char *jabber_normalize( const char *orig ); + +typedef enum +{ +	GET_BUDDY_CREAT = 1,	/* Try to create it, if necessary. */ +	GET_BUDDY_EXACT = 2,	/* Get an exact match (only makes sense with bare JIDs). */ +	GET_BUDDY_FIRST = 4,	/* No selection, simply get the first resource for this JID. */ +} get_buddy_flags_t; +struct jabber_error +{ +	char *code, *text, *type; +}; + +struct jabber_buddy *jabber_buddy_add( struct im_connection *ic, char *full_jid ); +struct jabber_buddy *jabber_buddy_by_jid( struct im_connection *ic, char *jid, get_buddy_flags_t flags ); +struct jabber_buddy *jabber_buddy_by_ext_jid( struct im_connection *ic, char *jid, get_buddy_flags_t flags ); +int jabber_buddy_remove( struct im_connection *ic, char *full_jid ); +int jabber_buddy_remove_bare( struct im_connection *ic, char *bare_jid ); +time_t jabber_get_timestamp( struct xt_node *xt ); +struct jabber_error *jabber_error_parse( struct xt_node *node, char *xmlns ); +void jabber_error_free( struct jabber_error *err ); + +extern const struct jabber_away_state jabber_away_state_list[]; + +/* io.c */ +int jabber_write_packet( struct im_connection *ic, struct xt_node *node ); +int jabber_write( struct im_connection *ic, char *buf, int len ); +gboolean jabber_connected_plain( gpointer data, gint source, b_input_condition cond ); +gboolean jabber_connected_ssl( gpointer data, void *source, b_input_condition cond ); +gboolean jabber_start_stream( struct im_connection *ic ); +void jabber_end_stream( struct im_connection *ic ); + +/* sasl.c */ +xt_status sasl_pkt_mechanisms( struct xt_node *node, gpointer data ); +xt_status sasl_pkt_challenge( struct xt_node *node, gpointer data ); +xt_status sasl_pkt_result( struct xt_node *node, gpointer data ); +gboolean sasl_supported( struct im_connection *ic ); + +/* conference.c */ +struct groupchat *jabber_chat_join( struct im_connection *ic, char *room, char *nick, char *password ); +struct groupchat *jabber_chat_by_jid( struct im_connection *ic, const char *name ); +void jabber_chat_free( struct groupchat *c ); +int jabber_chat_msg( struct groupchat *ic, char *message, int flags ); +int jabber_chat_topic( struct groupchat *c, char *topic ); +int jabber_chat_leave( struct groupchat *c, const char *reason ); +void jabber_chat_pkt_presence( struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node ); +void jabber_chat_pkt_message( struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node ); +void jabber_chat_invite( struct groupchat *c, char *who, char *message ); -#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..6e872040 --- /dev/null +++ b/protocols/jabber/jabber_util.c @@ -0,0 +1,710 @@ +/***************************************************************************\ +*                                                                           * +*  BitlBee - An IRC to IM gateway                                           * +*  Jabber module - Misc. stuff                                              * +*                                                                           * +*  Copyright 2006 Wilmer van der Gaast <wilmer@gaast.net>                   * +*                                                                           * +*  This program is free software; you can redistribute it and/or modify     * +*  it under the terms of the GNU General Public License as published by     * +*  the Free Software Foundation; either version 2 of the License, or        * +*  (at your option) any later version.                                      * +*                                                                           * +*  This program is distributed in the hope that it will be useful,          * +*  but WITHOUT ANY WARRANTY; without even the implied warranty of           * +*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            * +*  GNU General Public License for more details.                             * +*                                                                           * +*  You should have received a copy of the GNU General Public License along  * +*  with this program; if not, write to the Free Software Foundation, Inc.,  * +*  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.              * +*                                                                           * +\***************************************************************************/ + +#include "jabber.h" + +static unsigned int next_id = 1; + +char *set_eval_priority( set_t *set, char *value ) +{ +	account_t *acc = set->data; +	int i; +	 +	if( sscanf( value, "%d", &i ) == 1 ) +	{ +		/* Priority is a signed 8-bit integer, according to RFC 3921. */ +		if( i < -128 || i > 127 ) +			return NULL; +	} +	else +		return NULL; +	 +	/* Only run this stuff if the account is online ATM, +	   and if the setting seems to be acceptable. */ +	if( acc->ic ) +	{ +		/* Although set_eval functions usually are very nice and +		   convenient, they have one disadvantage: If I would just +		   call p_s_u() now to send the new prio setting, it would +		   send the old setting because the set->value gets changed +		   after the (this) eval returns a non-NULL value. +		    +		   So now I can choose between implementing post-set +		   functions next to evals, or just do this little hack: */ +		 +		g_free( set->value ); +		set->value = g_strdup( value ); +		 +		/* (Yes, sorry, I prefer the hack. :-P) */ +		 +		presence_send_update( acc->ic ); +	} +	 +	return value; +} + +char *set_eval_tls( set_t *set, char *value ) +{ +	if( g_strcasecmp( value, "try" ) == 0 ) +		return value; +	else +		return set_eval_bool( set, value ); +} + +struct xt_node *jabber_make_packet( char *name, char *type, char *to, struct xt_node *children ) +{ +	struct xt_node *node; +	 +	node = xt_new_node( name, NULL, children ); +	 +	if( type ) +		xt_add_attr( node, "type", type ); +	if( to ) +		xt_add_attr( node, "to", to ); +	 +	/* IQ packets should always have an ID, so let's generate one. It +	   might get overwritten by jabber_cache_add() if this packet has +	   to be saved until we receive a response. Cached packets get +	   slightly different IDs so we can recognize them. */ +	if( strcmp( name, "iq" ) == 0 ) +	{ +		char *id = g_strdup_printf( "%s%05x", JABBER_PACKET_ID, ( next_id++ ) & 0xfffff ); +		xt_add_attr( node, "id", id ); +		g_free( id ); +	} +	 +	return node; +} + +struct xt_node *jabber_make_error_packet( struct xt_node *orig, char *err_cond, char *err_type ) +{ +	struct xt_node *node, *c; +	char *to; +	 +	/* Create the "defined-condition" tag. */ +	c = xt_new_node( err_cond, NULL, NULL ); +	xt_add_attr( c, "xmlns", XMLNS_STANZA_ERROR ); +	 +	/* Put it in an <error> tag. */ +	c = xt_new_node( "error", NULL, c ); +	xt_add_attr( c, "type", err_type ); +	 +	/* To make the actual error packet, we copy the original packet and +	   add our <error>/type="error" tag. Including the original packet +	   is recommended, so let's just do it. */ +	node = xt_dup( orig ); +	xt_add_child( node, c ); +	xt_add_attr( node, "type", "error" ); +	 +	/* Return to sender. */ +	if( ( to = xt_find_attr( node, "from" ) ) ) +	{ +		xt_add_attr( node, "to", to ); +		xt_remove_attr( node, "from" ); +	} +		 +	return node; +} + +/* Cache a node/packet for later use. Mainly useful for IQ packets if you need +   them when you receive the response. Use this BEFORE sending the packet so +   it'll get a new id= tag, and do NOT free() the packet after sending it! */ +void jabber_cache_add( struct im_connection *ic, struct xt_node *node, jabber_cache_event func ) +{ +	struct jabber_data *jd = ic->proto_data; +	struct jabber_cache_entry *entry = g_new0( struct jabber_cache_entry, 1 ); +	char *id; +	 +	id = g_strdup_printf( "%s%05x", jd->cached_id_prefix, ( next_id++ ) & 0xfffff ); +	xt_add_attr( node, "id", id ); +	g_free( id ); +	 +	entry->node = node; +	entry->func = func; +	entry->saved_at = time( NULL ); +	g_hash_table_insert( jd->node_cache, xt_find_attr( node, "id" ), entry ); +} + +void jabber_cache_entry_free( gpointer data ) +{ +	struct jabber_cache_entry *entry = data; +	 +	xt_free_node( entry->node ); +	g_free( entry ); +} + +gboolean jabber_cache_clean_entry( gpointer key, gpointer entry, gpointer nullpointer ); + +/* This one should be called from time to time (from keepalive, in this case) +   to make sure things don't stay in the node cache forever. By marking nodes +   during the first run and deleting marked nodes during a next run, every +   node should be available in the cache for at least a minute (assuming the +   function is indeed called every minute). */ +void jabber_cache_clean( struct im_connection *ic ) +{ +	struct jabber_data *jd = ic->proto_data; +	time_t threshold = time( NULL ) - JABBER_CACHE_MAX_AGE; +	 +	g_hash_table_foreach_remove( jd->node_cache, jabber_cache_clean_entry, &threshold ); +} + +gboolean jabber_cache_clean_entry( gpointer key, gpointer entry_, gpointer threshold_ ) +{ +	struct jabber_cache_entry *entry = entry_; +	time_t *threshold = threshold_; +	 +	return entry->saved_at < *threshold; +} + +xt_status jabber_cache_handle_packet( struct im_connection *ic, struct xt_node *node ) +{ +	struct jabber_data *jd = ic->proto_data; +	struct jabber_cache_entry *entry; +	char *s; +	 +	if( ( s = xt_find_attr( node, "id" ) ) == NULL || +	    strncmp( s, jd->cached_id_prefix, strlen( jd->cached_id_prefix ) ) != 0 ) +	{ +		/* Silently ignore it, without an ID (or a non-cache +		   ID) we don't know how to handle the packet and we +		   probably don't have to. */ +		return XT_HANDLED; +	} +	 +	entry = g_hash_table_lookup( jd->node_cache, s ); +	 +	if( entry == NULL ) +	{ +		imcb_log( ic, "Warning: Received %s-%s packet with unknown/expired ID %s!", +		              node->name, xt_find_attr( node, "type" ) ? : "(no type)", s ); +	} +	else if( entry->func ) +	{ +		return entry->func( ic, node, entry->node ); +	} +	 +	return XT_HANDLED; +} + +const struct jabber_away_state jabber_away_state_list[] = +{ +	{ "away",  "Away" }, +	{ "chat",  "Free for Chat" }, +	{ "dnd",   "Do not Disturb" }, +	{ "xa",    "Extended Away" }, +	{ "",      "Online" }, +	{ "",      NULL } +}; + +const struct jabber_away_state *jabber_away_state_by_code( char *code ) +{ +	int i; +	 +	for( i = 0; jabber_away_state_list[i].full_name; i ++ ) +		if( g_strcasecmp( jabber_away_state_list[i].code, code ) == 0 ) +			return jabber_away_state_list + i; +	 +	return NULL; +} + +const struct jabber_away_state *jabber_away_state_by_name( char *name ) +{ +	int i; +	 +	for( i = 0; jabber_away_state_list[i].full_name; i ++ ) +		if( g_strcasecmp( jabber_away_state_list[i].full_name, name ) == 0 ) +			return jabber_away_state_list + i; +	 +	return NULL; +} + +struct jabber_buddy_ask_data +{ +	struct im_connection *ic; +	char *handle; +	char *realname; +}; + +static void jabber_buddy_ask_yes( gpointer w, struct jabber_buddy_ask_data *bla ) +{ +	presence_send_request( bla->ic, bla->handle, "subscribed" ); +	 +	if( imcb_find_buddy( bla->ic, bla->handle ) == NULL ) +		imcb_ask_add( bla->ic, bla->handle, NULL ); +	 +	g_free( bla->handle ); +	g_free( bla ); +} + +static void jabber_buddy_ask_no( gpointer w, struct jabber_buddy_ask_data *bla ) +{ +	presence_send_request( bla->ic, bla->handle, "subscribed" ); +	 +	g_free( bla->handle ); +	g_free( bla ); +} + +void jabber_buddy_ask( struct im_connection *ic, char *handle ) +{ +	struct jabber_buddy_ask_data *bla = g_new0( struct jabber_buddy_ask_data, 1 ); +	char *buf; +	 +	bla->ic = ic; +	bla->handle = g_strdup( handle ); +	 +	buf = g_strdup_printf( "The user %s wants to add you to his/her buddy list.", handle ); +	imcb_ask( ic, buf, bla, jabber_buddy_ask_yes, jabber_buddy_ask_no ); +	g_free( buf ); +} + +/* Returns a new string. Don't leak it! */ +char *jabber_normalize( const char *orig ) +{ +	int len, i; +	char *new; +	 +	len = strlen( orig ); +	new = g_new( char, len + 1 ); +	for( i = 0; i < len; i ++ ) +		new[i] = tolower( orig[i] ); +	 +	new[i] = 0; +	return new; +} + +/* Adds a buddy/resource to our list. Returns NULL if full_jid is not really a +   FULL jid or if we already have this buddy/resource. XXX: No, great, actually +   buddies from transports don't (usually) have resources. So we'll really have +   to deal with that properly. Set their ->resource property to NULL. Do *NOT* +   allow to mix this stuff, though... */ +struct jabber_buddy *jabber_buddy_add( struct im_connection *ic, char *full_jid_ ) +{ +	struct jabber_data *jd = ic->proto_data; +	struct jabber_buddy *bud, *new, *bi; +	char *s, *full_jid; +	 +	full_jid = jabber_normalize( full_jid_ ); +	 +	if( ( s = strchr( full_jid, '/' ) ) ) +		*s = 0; +	 +	new = g_new0( struct jabber_buddy, 1 ); +	 +	if( ( bud = g_hash_table_lookup( jd->buddies, full_jid ) ) ) +	{ +		/* If this is a transport buddy or whatever, it can't have more +		   than one instance, so this is always wrong: */ +		if( s == NULL || bud->resource == NULL ) +		{ +			if( s ) *s = '/'; +			g_free( new ); +			g_free( full_jid ); +			return NULL; +		} +		 +		new->bare_jid = bud->bare_jid; +		 +		/* We already have another resource for this buddy, add the +		   new one to the list. */ +		for( bi = bud; bi; bi = bi->next ) +		{ +			/* Check for dupes. */ +			if( g_strcasecmp( bi->resource, s + 1 ) == 0 ) +			{ +				*s = '/'; +				g_free( new ); +				g_free( full_jid ); +				return NULL; +			} +			/* Append the new item to the list. */ +			else if( bi->next == NULL ) +			{ +				bi->next = new; +				break; +			} +		} +	} +	else +	{ +		/* Keep in mind that full_jid currently isn't really +		   a full JID... */ +		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. And it saves +		   me one g_free() call in this function. :-P */ +		new->full_jid = full_jid; +	} +	 +	return new; +} + +/* Finds a buddy from our structures. Can find both full- and bare JIDs. When +   asked for a bare JID, it uses the "resource_select" setting to see which +   resource to pick. */ +struct jabber_buddy *jabber_buddy_by_jid( struct im_connection *ic, char *jid_, get_buddy_flags_t flags ) +{ +	struct jabber_data *jd = ic->proto_data; +	struct jabber_buddy *bud; +	char *s, *jid; +	 +	jid = jabber_normalize( jid_ ); +	 +	if( ( s = strchr( jid, '/' ) ) ) +	{ +		int none_found = 0; +		 +		*s = 0; +		if( ( bud = g_hash_table_lookup( jd->buddies, jid ) ) ) +		{ +			/* Just return the first one for this bare JID. */ +			if( flags & GET_BUDDY_FIRST ) +			{ +				*s = '/'; +				g_free( jid ); +				return bud; +			} +			 +			/* Is this one of those no-resource buddies? */ +			if( bud->resource == NULL ) +			{ +				*s = '/'; +				g_free( jid ); +				return NULL; +			} +			 +			/* See if there's an exact match. */ +			for( ; bud; bud = bud->next ) +				if( g_strcasecmp( bud->resource, s + 1 ) == 0 ) +					break; +		} +		else +		{ +			/* This hack is there to make sure that O_CREAT will +			   work if there's already another resouce present +			   for this JID, even if it's an unknown buddy. This +			   is done to handle conferences properly. */ +			none_found = 1; +			/* TODO(wilmer): Find out what I was thinking when I +			   wrote this??? And then fix it. This makes me sad... */ +		} +		 +		if( bud == NULL && ( flags & GET_BUDDY_CREAT ) && ( imcb_find_buddy( ic, jid ) || !none_found ) ) +		{ +			*s = '/'; +			bud = jabber_buddy_add( ic, jid ); +		} +		 +		g_free( jid ); +		return bud; +	} +	else +	{ +		struct jabber_buddy *best_prio, *best_time; +		char *set; +		 +		bud = g_hash_table_lookup( jd->buddies, jid ); +		 +		g_free( jid ); +		 +		if( bud == NULL ) +			/* No match. Create it now? */ +			return ( ( flags & GET_BUDDY_CREAT ) && imcb_find_buddy( ic, jid_ ) ) ? +			           jabber_buddy_add( ic, jid_ ) : NULL; +		else if( bud->resource && ( flags & GET_BUDDY_EXACT ) ) +			/* We want an exact match, so in thise case there shouldn't be a /resource. */ +			return NULL; +		else if( ( bud->resource == NULL || bud->next == NULL ) ) +			/* No need for selection if there's only one option. */ +			return bud; +		else if( flags & GET_BUDDY_FIRST ) +			/* Looks like the caller doesn't care about details. */ +			return bud; +		 +		best_prio = best_time = bud; +		for( ; bud; bud = bud->next ) +		{ +			if( bud->priority > best_prio->priority ) +				best_prio = bud; +			if( bud->last_act > best_time->last_act ) +				best_time = bud; +		} +		 +		if( ( set = set_getstr( &ic->acc->set, "resource_select" ) ) == NULL ) +			return NULL; +		else if( strcmp( set, "activity" ) == 0 ) +			return best_time; +		else /* if( strcmp( set, "priority" ) == 0 ) */ +			return best_prio; +	} +} + +/* I'm keeping a separate ext_jid attribute to save a JID that makes sense +   to export to BitlBee. This is mainly for groupchats right now. It's +   a bit of a hack, but I just think having the user nickname in the hostname +   part of the hostmask doesn't look nice on IRC. Normally you can convert +   a normal JID to ext_jid by swapping the part before and after the / and +   replacing the / with a =. But there should be some stripping (@s are +   allowed in Jabber nicks...). */ +struct jabber_buddy *jabber_buddy_by_ext_jid( struct im_connection *ic, char *jid_, get_buddy_flags_t flags ) +{ +	struct jabber_buddy *bud; +	char *s, *jid; +	 +	jid = jabber_normalize( jid_ ); +	 +	if( ( s = strchr( jid, '=' ) ) == NULL ) +		return NULL; +	 +	for( bud = jabber_buddy_by_jid( ic, s + 1, GET_BUDDY_FIRST ); bud; bud = bud->next ) +	{ +		/* Hmmm, could happen if not all people in the chat are anonymized? */ +		if( bud->ext_jid == NULL ) +			continue; +		 +		if( strcmp( bud->ext_jid, jid ) == 0 ) +			break; +	} +	 +	g_free( jid ); +	 +	return bud; +} + +/* Remove one specific full JID from our list. Use this when a buddy goes +   off-line (because (s)he can still be online from a different location. +   XXX: See above, we should accept bare JIDs too... */ +int jabber_buddy_remove( struct im_connection *ic, char *full_jid_ ) +{ +	struct jabber_data *jd = ic->proto_data; +	struct jabber_buddy *bud, *prev, *bi; +	char *s, *full_jid; +	 +	full_jid = jabber_normalize( full_jid_ ); +	 +	if( ( s = strchr( full_jid, '/' ) ) ) +		*s = 0; +	 +	if( ( bud = g_hash_table_lookup( jd->buddies, full_jid ) ) ) +	{ +		/* If there's only one item in the list (and if the resource +		   matches), removing it is simple. (And the hash reference +		   should be removed too!) */ +		if( bud->next == NULL && ( ( s == NULL || bud->resource == NULL ) || g_strcasecmp( bud->resource, s + 1 ) == 0 ) ) +		{ +			g_hash_table_remove( jd->buddies, bud->bare_jid ); +			g_free( bud->bare_jid ); +			g_free( bud->ext_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->ext_jid ); +				g_free( bi->full_jid ); +				g_free( bi->away_message ); +				g_free( bi ); +				 +				return 1; +			} +			else +			{ +				return 0; +			} +		} +	} +	else +	{ +		g_free( full_jid ); +		return 0; +	} +} + +/* Remove a buddy completely; removes all resources that belong to the +   specified bare JID. Use this when removing someone from the contact +   list, for example. */ +int jabber_buddy_remove_bare( struct im_connection *ic, char *bare_jid ) +{ +	struct jabber_data *jd = ic->proto_data; +	struct jabber_buddy *bud, *next; +	 +	if( strchr( bare_jid, '/' ) ) +		return 0; +	 +	if( ( bud = jabber_buddy_by_jid( ic, bare_jid, GET_BUDDY_FIRST ) ) ) +	{ +		/* Most important: Remove the hash reference. We don't know +		   this buddy anymore. */ +		g_hash_table_remove( jd->buddies, bud->bare_jid ); +		g_free( bud->bare_jid ); +		 +		/* Deallocate the linked list of resources. */ +		while( bud ) +		{ +			/* ext_jid && anonymous means that this buddy is +			   specific to one groupchat (the one we're +			   currently cleaning up) so it can be deleted +			   completely. */ +			if( bud->ext_jid && bud->flags & JBFLAG_IS_ANONYMOUS ) +				imcb_remove_buddy( ic, bud->ext_jid, NULL ); +			 +			next = bud->next; +			g_free( bud->ext_jid ); +			g_free( bud->full_jid ); +			g_free( bud->away_message ); +			g_free( bud ); +			bud = next; +		} +		 +		return 1; +	} +	else +	{ +		return 0; +	} +} + +time_t jabber_get_timestamp( struct xt_node *xt ) +{ +	struct tm tp, utc; +	struct xt_node *c; +	time_t res, tres; +	char *s = NULL; +	 +	for( c = xt->children; ( c = xt_find_node( c, "x" ) ); c = c->next ) +	{ +		if( ( s = xt_find_attr( c, "xmlns" ) ) && strcmp( s, XMLNS_DELAY ) == 0 ) +			break; +	} +	 +	if( !c || !( s = xt_find_attr( c, "stamp" ) ) ) +		return 0; +	 +	memset( &tp, 0, sizeof( tp ) ); +	if( sscanf( s, "%4d%2d%2dT%2d:%2d:%2d", &tp.tm_year, &tp.tm_mon, &tp.tm_mday, +	                                        &tp.tm_hour, &tp.tm_min, &tp.tm_sec ) != 6 ) +		return 0; +	 +	tp.tm_year -= 1900; +	tp.tm_mon --; +	tp.tm_isdst = -1; /* GRRRRRRRRRRR */ +	 +	res = mktime( &tp ); +	/* Problem is, mktime() just gave us the GMT timestamp for the +	   given local time... While the given time WAS NOT local. So +	   we should fix this now. +	 +	   Now I could choose between messing with environment variables +	   (kludgy) or using timegm() (not portable)... Or doing the +	   following, which I actually prefer... */ +	gmtime_r( &res, &utc ); +	utc.tm_isdst = -1; /* Once more: GRRRRRRRRRRRRRRRRRR!!! */ +	if( utc.tm_hour == tp.tm_hour && utc.tm_min == tp.tm_min ) +		/* Sweet! We're in UTC right now... */ +		return res; +	 +	tres = mktime( &utc ); +	res += res - tres; +	 +	/* Yes, this is a hack. And it will go wrong around DST changes. +	   BUT this is more likely to be threadsafe than messing with +	   environment variables, and possibly more portable... */ +	 +	return res; +} + +struct jabber_error *jabber_error_parse( struct xt_node *node, char *xmlns ) +{ +	struct jabber_error *err; +	struct xt_node *c; +	char *s; +	 +	if( node == NULL ) +		return NULL; +	 +	err = g_new0( struct jabber_error, 1 ); +	err->type = xt_find_attr( node, "type" ); +	 +	for( c = node->children; c; c = c->next ) +	{ +		if( !( s = xt_find_attr( c, "xmlns" ) ) || +		    strcmp( s, xmlns ) != 0 ) +			continue; +		 +		if( strcmp( c->name, "text" ) != 0 ) +		{ +			err->code = 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 ) +		{ +			err->text = c->text; +		} +	} +	 +	return err; +} + +void jabber_error_free( struct jabber_error *err ) +{ +	g_free( err ); +} 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..fab62a91 --- /dev/null +++ b/protocols/jabber/message.c @@ -0,0 +1,118 @@ +/***************************************************************************\ +*                                                                           * +*  BitlBee - An IRC to IM gateway                                           * +*  Jabber module - Handling of message(s) (tags), etc                       * +*                                                                           * +*  Copyright 2006 Wilmer van der Gaast <wilmer@gaast.net>                   * +*                                                                           * +*  This program is free software; you can redistribute it and/or modify     * +*  it under the terms of the GNU General Public License as published by     * +*  the Free Software Foundation; either version 2 of the License, or        * +*  (at your option) any later version.                                      * +*                                                                           * +*  This program is distributed in the hope that it will be useful,          * +*  but WITHOUT ANY WARRANTY; without even the implied warranty of           * +*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            * +*  GNU General Public License for more details.                             * +*                                                                           * +*  You should have received a copy of the GNU General Public License along  * +*  with this program; if not, write to the Free Software Foundation, Inc.,  * +*  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.              * +*                                                                           * +\***************************************************************************/ + +#include "jabber.h" + +xt_status jabber_pkt_message( struct xt_node *node, gpointer data ) +{ +	struct im_connection *ic = data; +	char *from = xt_find_attr( node, "from" ); +	char *type = xt_find_attr( node, "type" ); +	struct xt_node *body = xt_find_node( node->children, "body" ), *c; +	struct jabber_buddy *bud = NULL; +	char *s; +	 +	if( !from ) +		return XT_HANDLED; /* Consider this packet corrupted. */ +	 +	bud = jabber_buddy_by_jid( ic, from, GET_BUDDY_EXACT ); +	 +	if( type && strcmp( type, "error" ) == 0 ) +	{ +		/* Handle type=error packet. */ +	} +	else if( type && from && strcmp( type, "groupchat" ) == 0 ) +	{ +		jabber_chat_pkt_message( ic, bud, node ); +	} +	else /* "chat", "normal", "headline", no-type or whatever. Should all be pretty similar. */ +	{ +		GString *fullmsg = g_string_new( "" ); +		 +		if( ( s = strchr( from, '/' ) ) ) +		{ +			if( bud ) +			{ +				bud->last_act = time( NULL ); +				from = bud->ext_jid ? : bud->bare_jid; +			} +			else +				*s = 0; /* We need to generate a bare JID now. */ +		} +		 +		if( type && strcmp( type, "headline" ) == 0 ) +		{ +			c = xt_find_node( node->children, "subject" ); +			g_string_append_printf( fullmsg, "Headline: %s\n", c && c->text_len > 0 ? c->text : "" ); +			 +			/* <x xmlns="jabber:x:oob"><url>http://....</url></x> can contain a URL, it seems. */ +			for( c = node->children; c; c = c->next ) +			{ +				struct xt_node *url; +				 +				if( ( url = xt_find_node( c->children, "url" ) ) && url->text_len > 0 ) +					g_string_append_printf( fullmsg, "URL: %s\n", url->text ); +			} +		} +		else if( ( c = xt_find_node( node->children, "subject" ) ) && c->text_len > 0 ) +		{ +			g_string_append_printf( fullmsg, "<< \002BitlBee\002 - Message with subject: %s >>\n", c->text ); +		} +		 +		if( body && body->text_len > 0 ) /* Could be just a typing notification. */ +			fullmsg = g_string_append( fullmsg, body->text ); +		 +		if( fullmsg->len > 0 ) +			imcb_buddy_msg( ic, from, fullmsg->str, +			                0, jabber_get_timestamp( node ) ); +		 +		g_string_free( fullmsg, TRUE ); +		 +		/* Handling of incoming typing notifications. */ +		if( bud == NULL ) +		{ +			/* Can't handle these for unknown buddies. */ +		} +		else if( xt_find_node( node->children, "composing" ) ) +		{ +			bud->flags |= JBFLAG_DOES_XEP85; +			imcb_buddy_typing( ic, from, OPT_TYPING ); +		} +		/* No need to send a "stopped typing" signal when there's a message. */ +		else if( xt_find_node( node->children, "active" ) && ( body == NULL ) ) +		{ +			bud->flags |= JBFLAG_DOES_XEP85; +			imcb_buddy_typing( ic, from, 0 ); +		} +		else if( xt_find_node( node->children, "paused" ) ) +		{ +			bud->flags |= JBFLAG_DOES_XEP85; +			imcb_buddy_typing( ic, from, OPT_THINKING ); +		} +		 +		if( s ) +			*s = '/'; /* And convert it back to a full JID. */ +	} +	 +	return XT_HANDLED; +} diff --git a/protocols/jabber/nametab.h b/protocols/jabber/nametab.h deleted file mode 100644 index b05e62c7..00000000 --- a/protocols/jabber/nametab.h +++ /dev/null @@ -1,150 +0,0 @@ -static const unsigned namingBitmap[] = { -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, -0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, -0x00000000, 0x04000000, 0x87FFFFFE, 0x07FFFFFE, -0x00000000, 0x00000000, 0xFF7FFFFF, 0xFF7FFFFF, -0xFFFFFFFF, 0x7FF3FFFF, 0xFFFFFDFE, 0x7FFFFFFF, -0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFE00F, 0xFC31FFFF, -0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF, -0xFFFFFFFF, 0xF80001FF, 0x00000003, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0xFFFFD740, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD, -0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF, -0xFFFF0003, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF, -0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE, -0x0000007F, 0x00000000, 0xFFFF0000, 0x000707FF, -0x00000000, 0x07FFFFFE, 0x000007FE, 0xFFFE0000, -0xFFFFFFFF, 0x7CFFFFFF, 0x002F7FFF, 0x00000060, -0xFFFFFFE0, 0x23FFFFFF, 0xFF000000, 0x00000003, -0xFFF99FE0, 0x03C5FDFF, 0xB0000000, 0x00030003, -0xFFF987E0, 0x036DFDFF, 0x5E000000, 0x001C0000, -0xFFFBAFE0, 0x23EDFDFF, 0x00000000, 0x00000001, -0xFFF99FE0, 0x23CDFDFF, 0xB0000000, 0x00000003, -0xD63DC7E0, 0x03BFC718, 0x00000000, 0x00000000, -0xFFFDDFE0, 0x03EFFDFF, 0x00000000, 0x00000003, -0xFFFDDFE0, 0x03EFFDFF, 0x40000000, 0x00000003, -0xFFFDDFE0, 0x03FFFDFF, 0x00000000, 0x00000003, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0xFFFFFFFE, 0x000D7FFF, 0x0000003F, 0x00000000, -0xFEF02596, 0x200D6CAE, 0x0000001F, 0x00000000, -0x00000000, 0x00000000, 0xFFFFFEFF, 0x000003FF, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0xFFFFFFFF, 0xFFFF003F, 0x007FFFFF, -0x0007DAED, 0x50000000, 0x82315001, 0x002C62AB, -0x40000000, 0xF580C900, 0x00000007, 0x02010800, -0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, -0x0FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x03FFFFFF, -0x3F3FFFFF, 0xFFFFFFFF, 0xAAFF3F3F, 0x3FFFFFFF, -0xFFFFFFFF, 0x5FDFFFFF, 0x0FCF1FDC, 0x1FDC1FFF, -0x00000000, 0x00004C40, 0x00000000, 0x00000000, -0x00000007, 0x00000000, 0x00000000, 0x00000000, -0x00000080, 0x000003FE, 0xFFFFFFFE, 0xFFFFFFFF, -0x001FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x07FFFFFF, -0xFFFFFFE0, 0x00001FFF, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, -0xFFFFFFFF, 0x0000003F, 0x00000000, 0x00000000, -0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, -0xFFFFFFFF, 0x0000000F, 0x00000000, 0x00000000, -0x00000000, 0x07FF6000, 0x87FFFFFE, 0x07FFFFFE, -0x00000000, 0x00800000, 0xFF7FFFFF, 0xFF7FFFFF, -0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF, -0xFFFFFFFF, 0xF80001FF, 0x00030003, 0x00000000, -0xFFFFFFFF, 0xFFFFFFFF, 0x0000003F, 0x00000003, -0xFFFFD7C0, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD, -0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF, -0xFFFF007B, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF, -0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE, -0xFFFE007F, 0xBBFFFFFB, 0xFFFF0016, 0x000707FF, -0x00000000, 0x07FFFFFE, 0x0007FFFF, 0xFFFF03FF, -0xFFFFFFFF, 0x7CFFFFFF, 0xFFEF7FFF, 0x03FF3DFF, -0xFFFFFFEE, 0xF3FFFFFF, 0xFF1E3FFF, 0x0000FFCF, -0xFFF99FEE, 0xD3C5FDFF, 0xB080399F, 0x0003FFCF, -0xFFF987E4, 0xD36DFDFF, 0x5E003987, 0x001FFFC0, -0xFFFBAFEE, 0xF3EDFDFF, 0x00003BBF, 0x0000FFC1, -0xFFF99FEE, 0xF3CDFDFF, 0xB0C0398F, 0x0000FFC3, -0xD63DC7EC, 0xC3BFC718, 0x00803DC7, 0x0000FF80, -0xFFFDDFEE, 0xC3EFFDFF, 0x00603DDF, 0x0000FFC3, -0xFFFDDFEC, 0xC3EFFDFF, 0x40603DDF, 0x0000FFC3, -0xFFFDDFEC, 0xC3FFFDFF, 0x00803DCF, 0x0000FFC3, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0xFFFFFFFE, 0x07FF7FFF, 0x03FF7FFF, 0x00000000, -0xFEF02596, 0x3BFF6CAE, 0x03FF3F5F, 0x00000000, -0x03000000, 0xC2A003FF, 0xFFFFFEFF, 0xFFFE03FF, -0xFEBF0FDF, 0x02FE3FFF, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x1FFF0000, 0x00000002, -0x000000A0, 0x003EFFFE, 0xFFFFFFFE, 0xFFFFFFFF, -0x661FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x77FFFFFF, -}; -static const unsigned char nmstrtPages[] = { -0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00, -0x00, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13, -0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x15, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; -static const unsigned char namePages[] = { -0x19, 0x03, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x00, -0x00, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, -0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13, -0x26, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x27, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; diff --git a/protocols/jabber/pool.c b/protocols/jabber/pool.c deleted file mode 100644 index 8b88d747..00000000 --- a/protocols/jabber/pool.c +++ /dev/null @@ -1,247 +0,0 @@ -/* -------------------------------------------------------------------------- - * - * License - * - * The contents of this file are subject to the Jabber Open Source License - * Version 1.0 (the "JOSL").  You may not copy or use this file, in either - * source code or executable form, except in compliance with the JOSL. You - * may obtain a copy of the JOSL at http://www.jabber.org/ or at - * http://www.opensource.org/.   - * - * Software distributed under the JOSL is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the JOSL - * for the specific language governing rights and limitations under the - * JOSL. - * - * Copyrights - *  - * Portions created by or assigned to Jabber.com, Inc. are  - * Copyright (c) 1999-2002 Jabber.com, Inc.  All Rights Reserved.  Contact - * information for Jabber.com, Inc. is available at http://www.jabber.com/. - * - * Portions Copyright (c) 1998-1999 Jeremie Miller. - *  - * Acknowledgements - *  - * Special thanks to the Jabber Open Source Contributors for their - * suggestions and support of Jabber. - *  - * Alternatively, the contents of this file may be used under the terms of the - * GNU General Public License Version 2 or later (the "GPL"), in which case - * the provisions of the GPL are applicable instead of those above.  If you - * wish to allow use of your version of this file only under the terms of the - * GPL and not to allow others to use your version of this file under the JOSL, - * indicate your decision by deleting the provisions above and replace them - * with the notice and other provisions required by the GPL.  If you do not - * delete the provisions above, a recipient may use your version of this file - * under either the JOSL or the GPL.  - *  - *  - * --------------------------------------------------------------------------*/ - -#include "jabber.h" -#include "bitlbee.h" -#include <glib.h> - - -#ifdef POOL_DEBUG -int pool__total = 0; -int pool__ltotal = 0; -HASHTABLE pool__disturbed = NULL; -void *_pool__malloc(size_t size) -{ -    pool__total++; -    return g_malloc(size); -} -void _pool__free(void *block) -{ -    pool__total--; -    g_free(block); -} -#else -#define _pool__malloc g_malloc -#define _pool__free g_free -#endif - - -/* make an empty pool */ -pool _pool_new(char *zone) -{ -    pool p; -    while((p = _pool__malloc(sizeof(_pool))) == NULL) sleep(1); -    p->cleanup = NULL; -    p->heap = NULL; -    p->size = 0; - -#ifdef POOL_DEBUG -    p->lsize = -1; -    p->zone[0] = '\0'; -    strcat(p->zone,zone); -    sprintf(p->name,"%X",p); - -    if(pool__disturbed == NULL) -    { -        pool__disturbed = 1; /* reentrancy flag! */ -        pool__disturbed = ghash_create(POOL_DEBUG,(KEYHASHFUNC)str_hash_code,(KEYCOMPAREFUNC)j_strcmp); -    } -    if(pool__disturbed != 1) -        ghash_put(pool__disturbed,p->name,p); -#endif - -    return p; -} - -/* free a heap */ -static void _pool_heap_free(void *arg) -{ -    struct pheap *h = (struct pheap *)arg; - -    _pool__free(h->block); -    _pool__free(h); -} - -/* mem should always be freed last */ -static void _pool_cleanup_append(pool p, struct pfree *pf) -{ -    struct pfree *cur; - -    if(p->cleanup == NULL) -    { -        p->cleanup = pf; -        return; -    } - -    /* fast forward to end of list */ -    for(cur = p->cleanup; cur->next != NULL; cur = cur->next); - -    cur->next = pf; -} - -/* create a cleanup tracker */ -static struct pfree *_pool_free(pool p, pool_cleaner f, void *arg) -{ -    struct pfree *ret; - -    /* make the storage for the tracker */ -    while((ret = _pool__malloc(sizeof(struct pfree))) == NULL) sleep(1); -    ret->f = f; -    ret->arg = arg; -    ret->next = NULL; - -    return ret; -} - -/* create a heap and make sure it get's cleaned up */ -static struct pheap *_pool_heap(pool p, int size) -{ -    struct pheap *ret; -    struct pfree *clean; - -    /* make the return heap */ -    while((ret = _pool__malloc(sizeof(struct pheap))) == NULL) sleep(1); -    while((ret->block = _pool__malloc(size)) == NULL) sleep(1); -    ret->size = size; -    p->size += size; -    ret->used = 0; - -    /* append to the cleanup list */ -    clean = _pool_free(p, _pool_heap_free, (void *)ret); -    clean->heap = ret; /* for future use in finding used mem for pstrdup */ -    _pool_cleanup_append(p, clean); - -    return ret; -} - -pool _pool_new_heap(int size, char *zone) -{ -    pool p; -    p = _pool_new(zone); -    p->heap = _pool_heap(p,size); -    return p; -} - -void *pmalloc(pool p, int size) -{ -    void *block; - -    if(p == NULL) -    { -        fprintf(stderr,"Memory Leak! [pmalloc received NULL pool, unable to track allocation, exiting]\n"); -        abort(); -    } - -    /* if there is no heap for this pool or it's a big request, just raw, I like how we clean this :) */ -    if(p->heap == NULL || size > (p->heap->size / 2)) -    { -        while((block = _pool__malloc(size)) == NULL) sleep(1); -        p->size += size; -        _pool_cleanup_append(p, _pool_free(p, _pool__free, block)); -        return block; -    } - -    /* we have to preserve boundaries, long story :) */ -    if(size >= 4) -        while(p->heap->used&7) p->heap->used++; - -    /* if we don't fit in the old heap, replace it */ -    if(size > (p->heap->size - p->heap->used)) -        p->heap = _pool_heap(p, p->heap->size); - -    /* the current heap has room */ -    block = (char *)p->heap->block + p->heap->used; -    p->heap->used += size; -    return block; -} - -void *pmalloc_x(pool p, int size, char c) -{ -   void* result = pmalloc(p, size); -   if (result != NULL) -           memset(result, c, size); -   return result; -}   - -/* easy safety utility (for creating blank mem for structs, etc) */ -void *pmalloco(pool p, int size) -{ -    void *block = pmalloc(p, size); -    memset(block, 0, size); -    return block; -}   - -/* XXX efficient: move this to const char * and then loop throug the existing heaps to see if src is within a block in this pool */ -char *pstrdup(pool p, const char *src) -{ -    char *ret; - -    if(src == NULL) -        return NULL; - -    ret = pmalloc(p,strlen(src) + 1); -    strcpy(ret,src); - -    return ret; -} - -void pool_free(pool p) -{ -    struct pfree *cur, *stub; - -    if(p == NULL) return; - -    cur = p->cleanup; -    while(cur != NULL) -    { -        (*cur->f)(cur->arg); -        stub = cur->next; -        _pool__free(cur); -        cur = stub; -    } - -#ifdef POOL_DEBUG -    ghash_remove(pool__disturbed,p->name); -#endif - -    _pool__free(p); - -} diff --git a/protocols/jabber/presence.c b/protocols/jabber/presence.c new file mode 100644 index 00000000..6fc360b7 --- /dev/null +++ b/protocols/jabber/presence.c @@ -0,0 +1,261 @@ +/***************************************************************************\ +*                                                                           * +*  BitlBee - An IRC to IM gateway                                           * +*  Jabber module - Handling of presence (tags), etc                         * +*                                                                           * +*  Copyright 2006 Wilmer van der Gaast <wilmer@gaast.net>                   * +*                                                                           * +*  This program is free software; you can redistribute it and/or modify     * +*  it under the terms of the GNU General Public License as published by     * +*  the Free Software Foundation; either version 2 of the License, or        * +*  (at your option) any later version.                                      * +*                                                                           * +*  This program is distributed in the hope that it will be useful,          * +*  but WITHOUT ANY WARRANTY; without even the implied warranty of           * +*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            * +*  GNU General Public License for more details.                             * +*                                                                           * +*  You should have received a copy of the GNU General Public License along  * +*  with this program; if not, write to the Free Software Foundation, Inc.,  * +*  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.              * +*                                                                           * +\***************************************************************************/ + +#include "jabber.h" + +xt_status jabber_pkt_presence( struct xt_node *node, gpointer data ) +{ +	struct im_connection *ic = data; +	char *from = xt_find_attr( node, "from" ); +	char *type = xt_find_attr( node, "type" );	/* NULL should mean the person is online. */ +	struct xt_node *c, *cap; +	struct jabber_buddy *bud, *send_presence = NULL; +	int is_chat = 0; +	char *s; +	 +	if( !from ) +		return XT_HANDLED; +	 +	if( ( s = strchr( from, '/' ) ) ) +	{ +		*s = 0; +		if( jabber_chat_by_jid( ic, from ) ) +			is_chat = 1; +		*s = '/'; +	} +	 +	if( type == NULL ) +	{ +		if( !( bud = jabber_buddy_by_jid( ic, from, GET_BUDDY_EXACT | GET_BUDDY_CREAT ) ) ) +		{ +			if( set_getbool( &ic->irc->set, "debug" ) ) +				imcb_log( ic, "Warning: Could not handle presence information from JID: %s", from ); +			return XT_HANDLED; +		} +		 +		g_free( bud->away_message ); +		if( ( c = xt_find_node( node->children, "status" ) ) && c->text_len > 0 ) +			bud->away_message = g_strdup( c->text ); +		else +			bud->away_message = NULL; +		 +		if( ( c = xt_find_node( node->children, "show" ) ) && c->text_len > 0 ) +		{ +			bud->away_state = (void*) jabber_away_state_by_code( c->text ); +		} +		else +		{ +			bud->away_state = NULL; +			/* Let's only set last_act if there's *no* away state, +			   since it could be some auto-away thingy. */ +			bud->last_act = time( NULL ); +		} +		 +		if( ( c = xt_find_node( node->children, "priority" ) ) && c->text_len > 0 ) +			bud->priority = atoi( c->text ); +		else +			bud->priority = 0; +		 +		if( bud && ( cap = xt_find_node( node->children, "c" ) ) && +		    ( s = xt_find_attr( cap, "xmlns" ) ) && strcmp( s, XMLNS_CAPS ) == 0 ) +		{ +			/* This <presence> stanza includes an XEP-0115 +			   capabilities part. Not too interesting, but we can +			   see if it has an ext= attribute. */ +			s = xt_find_attr( cap, "ext" ); +			if( s && ( strstr( s, "cstates" ) || strstr( s, "chatstate" ) ) ) +				bud->flags |= JBFLAG_DOES_XEP85; +			 +			/* This field can contain more information like xhtml +			   support, but we don't support that ourselves. +			   Officially the ext= tag was deprecated, but enough +			   clients do send it. +			    +			   (I'm aware that this is not the right way to use +			   this field.) See for an explanation of ext=: +			   http://www.xmpp.org/extensions/attic/xep-0115-1.3.html*/ +		} +		 +		if( is_chat ) +			jabber_chat_pkt_presence( ic, bud, node ); +		else +			send_presence = jabber_buddy_by_jid( ic, bud->bare_jid, 0 ); +	} +	else if( strcmp( type, "unavailable" ) == 0 ) +	{ +		if( ( bud = jabber_buddy_by_jid( ic, from, 0 ) ) == NULL ) +		{ +			if( set_getbool( &ic->irc->set, "debug" ) ) +				imcb_log( ic, "Warning: Received presence information from unknown JID: %s", from ); +			return XT_HANDLED; +		} +		 +		/* Handle this before we delete the JID. */ +		if( is_chat ) +		{ +			jabber_chat_pkt_presence( ic, bud, node ); +		} +		 +		if( strchr( from, '/' ) == NULL ) +			/* Sometimes servers send a type="unavailable" from a +			   bare JID, which should mean that suddenly all +			   resources for this JID disappeared. */ +			jabber_buddy_remove_bare( ic, from ); +		else +			jabber_buddy_remove( ic, from ); +		 +		if( is_chat ) +		{ +			/* Nothing else to do for now? */ +		} +		else if( ( s = strchr( from, '/' ) ) ) +		{ +			*s = 0; +		 +			/* If another resource is still available, send its presence +			   information. */ +			if( ( send_presence = jabber_buddy_by_jid( ic, from, 0 ) ) == NULL ) +			{ +				/* Otherwise, count him/her as offline now. */ +				imcb_buddy_status( ic, from, 0, NULL, NULL ); +			} +			 +			*s = '/'; +		} +		else +		{ +			imcb_buddy_status( ic, from, 0, NULL, NULL ); +		} +	} +	else if( strcmp( type, "subscribe" ) == 0 ) +	{ +		jabber_buddy_ask( ic, from ); +	} +	else if( strcmp( type, "subscribed" ) == 0 ) +	{ +		/* Not sure about this one, actually... */ +		imcb_log( ic, "%s just accepted your authorization request", from ); +	} +	else if( strcmp( type, "unsubscribe" ) == 0 || strcmp( type, "unsubscribed" ) == 0 ) +	{ +		/* Do nothing here. Plenty of control freaks or over-curious +		   souls get excited when they can see who still has them in +		   their buddy list and who finally removed them. Somehow I +		   got the impression that those are the people who get +		   removed from many buddy lists for "some" reason... +		    +		   If you're one of those people, this is your chance to write +		   your first line of code in C... */ +	} +	else if( strcmp( type, "error" ) == 0 ) +	{ +		return jabber_cache_handle_packet( ic, node ); +		 +		/* +		struct jabber_error *err; +		if( ( c = xt_find_node( node->children, "error" ) ) ) +		{ +			err = jabber_error_parse( c, XMLNS_STANZA_ERROR ); +			imcb_error( ic, "Stanza (%s) error: %s%s%s", node->name, +			            err->code, err->text ? ": " : "", +			            err->text ? err->text : "" ); +			jabber_error_free( err ); +		} */ +	} + +	if( send_presence ) +	{ +		int is_away = 0; + +		if( send_presence->away_state && !( *send_presence->away_state->code == 0 || +		    strcmp( send_presence->away_state->code, "chat" ) == 0 ) ) +			is_away = OPT_AWAY; + +		imcb_buddy_status( ic, send_presence->bare_jid, OPT_LOGGED_IN | is_away, +		                   ( is_away && send_presence->away_state ) ? +		                   send_presence->away_state->full_name : NULL, +		                   send_presence->away_message ); +	} +	 +	return XT_HANDLED; +} + +/* Whenever presence information is updated, call this function to inform the +   server. */ +int presence_send_update( struct im_connection *ic ) +{ +	struct jabber_data *jd = ic->proto_data; +	struct xt_node *node, *cap; +	char *show = jd->away_state->code; +	char *status = jd->away_message; +	struct groupchat *c; +	int st; +	 +	node = jabber_make_packet( "presence", NULL, NULL, NULL ); +	xt_add_child( node, xt_new_node( "priority", set_getstr( &ic->acc->set, "priority" ), NULL ) ); +	if( show && *show ) +		xt_add_child( node, xt_new_node( "show", show, NULL ) ); +	if( status ) +		xt_add_child( node, xt_new_node( "status", status, NULL ) ); +	 +	/* This makes the packet slightly bigger, but clients interested in +	   capabilities can now cache the discovery info. This reduces the +	   usual post-login iq-flood. See XEP-0115. At least libpurple and +	   Trillian seem to do this right. */ +	cap = xt_new_node( "c", NULL, NULL ); +	xt_add_attr( cap, "xmlns", XMLNS_CAPS ); +	xt_add_attr( cap, "node", "http://bitlbee.org/xmpp/caps" ); +	xt_add_attr( cap, "ver", BITLBEE_VERSION ); /* The XEP wants this hashed, but nobody's doing that. */ +	xt_add_child( node, cap ); +	 +	st = jabber_write_packet( ic, node ); +	 +	/* Have to send this update to all groupchats too, the server won't +	   do this automatically. */ +	for( c = ic->groupchats; c && st; c = c->next ) +	{ +		struct jabber_chat *jc = c->data; +		 +		xt_add_attr( node, "to", jc->my_full_jid ); +		st = jabber_write_packet( ic, node ); +	} +	 +	xt_free_node( node ); +	return st; +} + +/* Send a subscribe/unsubscribe request to a buddy. */ +int presence_send_request( struct im_connection *ic, char *handle, char *request ) +{ +	struct xt_node *node; +	int st; +	 +	node = jabber_make_packet( "presence", NULL, NULL, NULL ); +	xt_add_attr( node, "to", handle ); +	xt_add_attr( node, "type", request ); +	 +	st = jabber_write_packet( ic, node ); +	 +	xt_free_node( node ); +	return st; +} diff --git a/protocols/jabber/sasl.c b/protocols/jabber/sasl.c new file mode 100644 index 00000000..53248ef3 --- /dev/null +++ b/protocols/jabber/sasl.c @@ -0,0 +1,348 @@ +/***************************************************************************\ +*                                                                           * +*  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 <ctype.h> + +#include "jabber.h" +#include "base64.h" + +xt_status sasl_pkt_mechanisms( struct xt_node *node, gpointer data ) +{ +	struct im_connection *ic = data; +	struct jabber_data *jd = ic->proto_data; +	struct xt_node *c, *reply; +	char *s; +	int sup_plain = 0, sup_digest = 0; +	 +	if( !sasl_supported( ic ) ) +	{ +		/* Should abort this now, since we should already be doing +		   IQ authentication. Strange things happen when you try +		   to do both... */ +		imcb_log( ic, "XMPP 1.0 non-compliant server seems to support SASL, please report this as a BitlBee bug!" ); +		return XT_HANDLED; +	} +	 +	s = xt_find_attr( node, "xmlns" ); +	if( !s || strcmp( s, XMLNS_SASL ) != 0 ) +	{ +		imcb_log( ic, "Stream error while authenticating" ); +		imc_logout( ic, FALSE ); +		return XT_ABORT; +	} +	 +	c = node->children; +	while( ( c = xt_find_node( c, "mechanism" ) ) ) +	{ +		if( c->text && g_strcasecmp( c->text, "PLAIN" ) == 0 ) +			sup_plain = 1; +		if( c->text && g_strcasecmp( c->text, "DIGEST-MD5" ) == 0 ) +			sup_digest = 1; +		 +		c = c->next; +	} +	 +	if( !sup_plain && !sup_digest ) +	{ +		imcb_error( ic, "No known SASL authentication schemes supported" ); +		imc_logout( ic, FALSE ); +		return XT_ABORT; +	} +	 +	reply = xt_new_node( "auth", NULL, NULL ); +	xt_add_attr( reply, "xmlns", XMLNS_SASL ); +	 +	if( sup_digest ) +	{ +		xt_add_attr( reply, "mechanism", "DIGEST-MD5" ); +		 +		/* The rest will be done later, when we receive a <challenge/>. */ +	} +	else if( sup_plain ) +	{ +		int len; +		 +		xt_add_attr( reply, "mechanism", "PLAIN" ); +		 +		/* With SASL PLAIN in XMPP, the text should be b64(\0user\0pass) */ +		len = strlen( jd->username ) + strlen( ic->acc->pass ) + 2; +		s = g_malloc( len + 1 ); +		s[0] = 0; +		strcpy( s + 1, jd->username ); +		strcpy( s + 2 + strlen( jd->username ), ic->acc->pass ); +		reply->text = base64_encode( (unsigned char *)s, len ); +		reply->text_len = strlen( reply->text ); +		g_free( s ); +	} +	 +	if( !jabber_write_packet( ic, reply ) ) +	{ +		xt_free_node( reply ); +		return XT_ABORT; +	} +	xt_free_node( reply ); +	 +	/* To prevent classic authentication from happening. */ +	jd->flags |= JFLAG_STREAM_STARTED; +	 +	return XT_HANDLED; +} + +/* Non-static function, but not mentioned in jabber.h because it's for internal +   use, just that the unittest should be able to reach it... */ +char *sasl_get_part( char *data, char *field ) +{ +	int i, len; +	 +	len = strlen( field ); +	 +	while( isspace( *data ) || *data == ',' ) +		data ++; +	 +	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, +			   find the next key after it. */ +			if( data[i] == ',' ) +			{ +				while( isspace( data[i] ) || data[i] == ',' ) +					i ++; +				 +				if( g_strncasecmp( data + i, field, len ) == 0 && +				    data[i+len] == '=' ) +				{ +					i += len + 1; +					break; +				} +			} +		} +	} +	 +	if( data[i] == '"' ) +	{ +		int j; +		char *ret; +		 +		i ++; +		len = 0; +		while( data[i+len] != '"' || data[i+len-1] == '\\' ) +			len ++; +		 +		ret = g_strndup( data + i, len ); +		for( i = j = 0; ret[i]; i ++ ) +		{ +			if( ret[i] == '\\' ) +			{ +				ret[j++] = ret[++i]; +			} +			else +			{ +				ret[j++] = ret[i]; +			} +		} +		ret[j] = 0; +		 +		return ret; +	} +	else if( data[i] ) +	{ +		len = 0; +		while( data[i+len] && data[i+len] != ',' ) +			len ++; +		 +		return g_strndup( data + i, len ); +	} +	else +	{ +		return NULL; +	} +} + +xt_status sasl_pkt_challenge( struct xt_node *node, gpointer data ) +{ +	struct im_connection *ic = data; +	struct jabber_data *jd = ic->proto_data; +	struct xt_node *reply = NULL; +	char *nonce = NULL, *realm = NULL, *cnonce = NULL; +	unsigned char 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( cnonce_bin, sizeof( cnonce_bin ) ); +		cnonce = base64_encode( cnonce_bin, sizeof( cnonce_bin ) ); +		digest_uri = g_strdup_printf( "%s/%s", "xmpp", jd->server ); +		 +		/* Generate the MD5 hash of username:realm:password, +		   I decided to call it H. */ +		md5_init( &H ); +		s = g_strdup_printf( "%s:%s:%s", jd->username, realm, ic->acc->pass ); +		md5_append( &H, (unsigned char *) s, strlen( s ) ); +		g_free( s ); +		md5_finish( &H, Hr ); +		 +		/* Now generate the hex. MD5 hash of H:nonce:cnonce, called A1. */ +		md5_init( &A1 ); +		s = g_strdup_printf( ":%s:%s", nonce, cnonce ); +		md5_append( &A1, Hr, 16 ); +		md5_append( &A1, (unsigned char *) s, strlen( s ) ); +		g_free( s ); +		md5_finish( &A1, A1r ); +		for( i = 0; i < 16; i ++ ) +			sprintf( A1h + i * 2, "%02x", A1r[i] ); +		 +		/* A2... */ +		md5_init( &A2 ); +		s = g_strdup_printf( "%s:%s", "AUTHENTICATE", digest_uri ); +		md5_append( &A2, (unsigned char *) s, strlen( s ) ); +		g_free( s ); +		md5_finish( &A2, A2r ); +		for( i = 0; i < 16; i ++ ) +			sprintf( A2h + i * 2, "%02x", A2r[i] ); +		 +		/* Final result: A1:nonce:00000001:cnonce:auth:A2. Let's reuse H for it. */ +		md5_init( &H ); +		s = g_strdup_printf( "%s:%s:%s:%s:%s:%s", A1h, nonce, "00000001", cnonce, "auth", A2h ); +		md5_append( &H, (unsigned char *) s, strlen( s ) ); +		g_free( s ); +		md5_finish( &H, Hr ); +		for( i = 0; i < 16; i ++ ) +			sprintf( Hh + i * 2, "%02x", Hr[i] ); +		 +		/* Now build the SASL response string: */ +		g_free( dec ); +		dec = g_strdup_printf( "username=\"%s\",realm=\"%s\",nonce=\"%s\",cnonce=\"%s\"," +		                       "nc=%08x,qop=auth,digest-uri=\"%s\",response=%s,charset=%s", +		                       jd->username, realm, nonce, cnonce, 1, digest_uri, Hh, "utf-8" ); +		s = tobase64( dec ); +	} +	else +	{ +		/* We found rspauth, but don't really care... */ +		g_free( s ); +		s = NULL; +	} +	 +	reply = xt_new_node( "response", s, NULL ); +	xt_add_attr( reply, "xmlns", XMLNS_SASL ); +	 +	if( !jabber_write_packet( ic, reply ) ) +		goto silent_error; +	 +	ret = XT_HANDLED; +	goto silent_error; + +error: +	imcb_error( ic, "Incorrect SASL challenge received" ); +	imc_logout( ic, FALSE ); + +silent_error: +	g_free( digest_uri ); +	g_free( cnonce ); +	g_free( nonce ); +	g_free( realm ); +	g_free( dec ); +	g_free( s ); +	xt_free_node( reply ); +	 +	return ret; +} + +xt_status sasl_pkt_result( struct xt_node *node, gpointer data ) +{ +	struct im_connection *ic = data; +	struct jabber_data *jd = ic->proto_data; +	char *s; +	 +	s = xt_find_attr( node, "xmlns" ); +	if( !s || strcmp( s, XMLNS_SASL ) != 0 ) +	{ +		imcb_log( ic, "Stream error while authenticating" ); +		imc_logout( ic, FALSE ); +		return XT_ABORT; +	} +	 +	if( strcmp( node->name, "success" ) == 0 ) +	{ +		imcb_log( ic, "Authentication finished" ); +		jd->flags |= JFLAG_AUTHENTICATED | JFLAG_STREAM_RESTART; +	} +	else if( strcmp( node->name, "failure" ) == 0 ) +	{ +		imcb_error( ic, "Authentication failure" ); +		imc_logout( ic, FALSE ); +		return XT_ABORT; +	} +	 +	return XT_HANDLED; +} + +/* This one is needed to judge if we'll do authentication using IQ or SASL. +   It's done by checking if the <stream:stream> from the server has a +   version attribute. I don't know if this is the right way though... */ +gboolean sasl_supported( struct im_connection *ic ) +{ +	struct jabber_data *jd = ic->proto_data; +	 +	return ( jd->xt && jd->xt->root && xt_find_attr( jd->xt->root, "version" ) ) != 0; +} 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/md5.c b/protocols/md5.c deleted file mode 100644 index e6273585..00000000 --- a/protocols/md5.c +++ /dev/null @@ -1,392 +0,0 @@ -/* -  Copyright (C) 1999 Aladdin Enterprises.  All rights reserved. - -  This software is provided 'as-is', without any express or implied -  warranty.  In no event will the authors be held liable for any damages -  arising from the use of this software. - -  Permission is granted to anyone to use this software for any purpose, -  including commercial applications, and to alter it and redistribute it -  freely, subject to the following restrictions: - -  1. The origin of this software must not be misrepresented; you must not -     claim that you wrote the original software. If you use this software -     in a product, an acknowledgment in the product documentation would be -     appreciated but is not required. -  2. Altered source versions must be plainly marked as such, and must not be -     misrepresented as being the original software. -  3. This notice may not be removed or altered from any source distribution. - -  L. Peter Deutsch -  ghost@aladdin.com - - */ -/* -  Independent implementation of MD5 (RFC 1321). - -  This code implements the MD5 Algorithm defined in RFC 1321. -  It is derived directly from the text of the RFC and not from the -  reference implementation. - -  The original and principal author of md5.c is L. Peter Deutsch -  <ghost@aladdin.com>.  Other authors are noted in the change history -  that follows (in reverse chronological order): - -  1999-11-04 lpd Edited comments slightly for automatic TOC extraction. -  1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). -  1999-05-03 lpd Original version. - */ - -#include "md5.h" -#include <string.h> - -#ifdef TEST -/* - * Compile with -DTEST to create a self-contained executable test program. - * The test program should print out the same values as given in section - * A.5 of RFC 1321, reproduced below. - */ -#include <string.h> -main() -{ -    static const char *const test[7] = { -	"", /*d41d8cd98f00b204e9800998ecf8427e*/ -	"945399884.61923487334tuvga", /*0cc175b9c0f1b6a831c399e269772661*/ -	"abc", /*900150983cd24fb0d6963f7d28e17f72*/ -	"message digest", /*f96b697d7cb7938d525a2f31aaf161d0*/ -	"abcdefghijklmnopqrstuvwxyz", /*c3fcd3d76192e4007dfb496cca67e13b*/ -	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", -				/*d174ab98d277d9f5a5611c2c9f419d9f*/ -	"12345678901234567890123456789012345678901234567890123456789012345678901234567890" /*57edf4a22be3c955ac49da2e2107b67a*/ -    }; -    int i; - -    for (i = 0; i < 7; ++i) { -	md5_state_t state; -	md5_byte_t digest[16]; -	int di; - -	md5_init(&state); -	md5_append(&state, (const md5_byte_t *)test[i], strlen(test[i])); -	md5_finish(&state, digest); -	printf("MD5 (\"%s\") = ", test[i]); -	for (di = 0; di < 16; ++di) -	    printf("%02x", digest[di]); -	printf("\n"); -    } -    return 0; -} -#endif /* TEST */ - - -/* - * For reference, here is the program that computed the T values. - */ -#if 0 -#include <math.h> -main() -{ -    int i; -    for (i = 1; i <= 64; ++i) { -	unsigned long v = (unsigned long)(4294967296.0 * fabs(sin((double)i))); -	printf("#define T%d 0x%08lx\n", i, v); -    } -    return 0; -} -#endif -/* - * End of T computation program. - */ -#define T1 0xd76aa478 -#define T2 0xe8c7b756 -#define T3 0x242070db -#define T4 0xc1bdceee -#define T5 0xf57c0faf -#define T6 0x4787c62a -#define T7 0xa8304613 -#define T8 0xfd469501 -#define T9 0x698098d8 -#define T10 0x8b44f7af -#define T11 0xffff5bb1 -#define T12 0x895cd7be -#define T13 0x6b901122 -#define T14 0xfd987193 -#define T15 0xa679438e -#define T16 0x49b40821 -#define T17 0xf61e2562 -#define T18 0xc040b340 -#define T19 0x265e5a51 -#define T20 0xe9b6c7aa -#define T21 0xd62f105d -#define T22 0x02441453 -#define T23 0xd8a1e681 -#define T24 0xe7d3fbc8 -#define T25 0x21e1cde6 -#define T26 0xc33707d6 -#define T27 0xf4d50d87 -#define T28 0x455a14ed -#define T29 0xa9e3e905 -#define T30 0xfcefa3f8 -#define T31 0x676f02d9 -#define T32 0x8d2a4c8a -#define T33 0xfffa3942 -#define T34 0x8771f681 -#define T35 0x6d9d6122 -#define T36 0xfde5380c -#define T37 0xa4beea44 -#define T38 0x4bdecfa9 -#define T39 0xf6bb4b60 -#define T40 0xbebfbc70 -#define T41 0x289b7ec6 -#define T42 0xeaa127fa -#define T43 0xd4ef3085 -#define T44 0x04881d05 -#define T45 0xd9d4d039 -#define T46 0xe6db99e5 -#define T47 0x1fa27cf8 -#define T48 0xc4ac5665 -#define T49 0xf4292244 -#define T50 0x432aff97 -#define T51 0xab9423a7 -#define T52 0xfc93a039 -#define T53 0x655b59c3 -#define T54 0x8f0ccc92 -#define T55 0xffeff47d -#define T56 0x85845dd1 -#define T57 0x6fa87e4f -#define T58 0xfe2ce6e0 -#define T59 0xa3014314 -#define T60 0x4e0811a1 -#define T61 0xf7537e82 -#define T62 0xbd3af235 -#define T63 0x2ad7d2bb -#define T64 0xeb86d391 - -static void -md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) -{ -    md5_word_t -	a = pms->abcd[0], b = pms->abcd[1], -	c = pms->abcd[2], d = pms->abcd[3]; -    md5_word_t t; - -#ifndef ARCH_IS_BIG_ENDIAN -# define ARCH_IS_BIG_ENDIAN 1	/* slower, default implementation */ -#endif -#if ARCH_IS_BIG_ENDIAN - -    /* -     * On big-endian machines, we must arrange the bytes in the right -     * order.  (This also works on machines of unknown byte order.) -     */ -    md5_word_t X[16]; -    const md5_byte_t *xp = data; -    int i; - -    for (i = 0; i < 16; ++i, xp += 4) -	X[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); - -#else  /* !ARCH_IS_BIG_ENDIAN */ - -    /* -     * On little-endian machines, we can process properly aligned data -     * without copying it. -     */ -    md5_word_t xbuf[16]; -    const md5_word_t *X; - -    if (!((data - (const md5_byte_t *)0) & 3)) { -	/* data are properly aligned */ -	X = (const md5_word_t *)data; -    } else { -	/* not aligned */ -	memcpy(xbuf, data, 64); -	X = xbuf; -    } -#endif - -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) - -    /* Round 1. */ -    /* Let [abcd k s i] denote the operation -       a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ -#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) -#define SET(a, b, c, d, k, s, Ti)\ -  t = a + F(b,c,d) + X[k] + Ti;\ -  a = ROTATE_LEFT(t, s) + b -    /* Do the following 16 operations. */ -    SET(a, b, c, d,  0,  7,  T1); -    SET(d, a, b, c,  1, 12,  T2); -    SET(c, d, a, b,  2, 17,  T3); -    SET(b, c, d, a,  3, 22,  T4); -    SET(a, b, c, d,  4,  7,  T5); -    SET(d, a, b, c,  5, 12,  T6); -    SET(c, d, a, b,  6, 17,  T7); -    SET(b, c, d, a,  7, 22,  T8); -    SET(a, b, c, d,  8,  7,  T9); -    SET(d, a, b, c,  9, 12, T10); -    SET(c, d, a, b, 10, 17, T11); -    SET(b, c, d, a, 11, 22, T12); -    SET(a, b, c, d, 12,  7, T13); -    SET(d, a, b, c, 13, 12, T14); -    SET(c, d, a, b, 14, 17, T15); -    SET(b, c, d, a, 15, 22, T16); -#undef SET - -     /* Round 2. */ -     /* Let [abcd k s i] denote the operation -          a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ -#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) -#define SET(a, b, c, d, k, s, Ti)\ -  t = a + G(b,c,d) + X[k] + Ti;\ -  a = ROTATE_LEFT(t, s) + b -     /* Do the following 16 operations. */ -    SET(a, b, c, d,  1,  5, T17); -    SET(d, a, b, c,  6,  9, T18); -    SET(c, d, a, b, 11, 14, T19); -    SET(b, c, d, a,  0, 20, T20); -    SET(a, b, c, d,  5,  5, T21); -    SET(d, a, b, c, 10,  9, T22); -    SET(c, d, a, b, 15, 14, T23); -    SET(b, c, d, a,  4, 20, T24); -    SET(a, b, c, d,  9,  5, T25); -    SET(d, a, b, c, 14,  9, T26); -    SET(c, d, a, b,  3, 14, T27); -    SET(b, c, d, a,  8, 20, T28); -    SET(a, b, c, d, 13,  5, T29); -    SET(d, a, b, c,  2,  9, T30); -    SET(c, d, a, b,  7, 14, T31); -    SET(b, c, d, a, 12, 20, T32); -#undef SET - -     /* Round 3. */ -     /* Let [abcd k s t] denote the operation -          a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define SET(a, b, c, d, k, s, Ti)\ -  t = a + H(b,c,d) + X[k] + Ti;\ -  a = ROTATE_LEFT(t, s) + b -     /* Do the following 16 operations. */ -    SET(a, b, c, d,  5,  4, T33); -    SET(d, a, b, c,  8, 11, T34); -    SET(c, d, a, b, 11, 16, T35); -    SET(b, c, d, a, 14, 23, T36); -    SET(a, b, c, d,  1,  4, T37); -    SET(d, a, b, c,  4, 11, T38); -    SET(c, d, a, b,  7, 16, T39); -    SET(b, c, d, a, 10, 23, T40); -    SET(a, b, c, d, 13,  4, T41); -    SET(d, a, b, c,  0, 11, T42); -    SET(c, d, a, b,  3, 16, T43); -    SET(b, c, d, a,  6, 23, T44); -    SET(a, b, c, d,  9,  4, T45); -    SET(d, a, b, c, 12, 11, T46); -    SET(c, d, a, b, 15, 16, T47); -    SET(b, c, d, a,  2, 23, T48); -#undef SET - -     /* Round 4. */ -     /* Let [abcd k s t] denote the operation -          a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ -#define I(x, y, z) ((y) ^ ((x) | ~(z))) -#define SET(a, b, c, d, k, s, Ti)\ -  t = a + I(b,c,d) + X[k] + Ti;\ -  a = ROTATE_LEFT(t, s) + b -     /* Do the following 16 operations. */ -    SET(a, b, c, d,  0,  6, T49); -    SET(d, a, b, c,  7, 10, T50); -    SET(c, d, a, b, 14, 15, T51); -    SET(b, c, d, a,  5, 21, T52); -    SET(a, b, c, d, 12,  6, T53); -    SET(d, a, b, c,  3, 10, T54); -    SET(c, d, a, b, 10, 15, T55); -    SET(b, c, d, a,  1, 21, T56); -    SET(a, b, c, d,  8,  6, T57); -    SET(d, a, b, c, 15, 10, T58); -    SET(c, d, a, b,  6, 15, T59); -    SET(b, c, d, a, 13, 21, T60); -    SET(a, b, c, d,  4,  6, T61); -    SET(d, a, b, c, 11, 10, T62); -    SET(c, d, a, b,  2, 15, T63); -    SET(b, c, d, a,  9, 21, T64); -#undef SET - -     /* Then perform the following additions. (That is increment each -        of the four registers by the value it had before this block -        was started.) */ -    pms->abcd[0] += a; -    pms->abcd[1] += b; -    pms->abcd[2] += c; -    pms->abcd[3] += d; -} - -void -md5_init(md5_state_t *pms) -{ -    pms->count[0] = pms->count[1] = 0; -    pms->abcd[0] = 0x67452301; -    pms->abcd[1] = 0xefcdab89; -    pms->abcd[2] = 0x98badcfe; -    pms->abcd[3] = 0x10325476; -} - -void -md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) -{ -    const md5_byte_t *p = data; -    int left = nbytes; -    int offset = (pms->count[0] >> 3) & 63; -    md5_word_t nbits = (md5_word_t)(nbytes << 3); - -    if (nbytes <= 0) -	return; - -    /* Update the message length. */ -    pms->count[1] += nbytes >> 29; -    pms->count[0] += nbits; -    if (pms->count[0] < nbits) -	pms->count[1]++; - -    /* Process an initial partial block. */ -    if (offset) { -	int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); - -	memcpy(pms->buf + offset, p, copy); -	if (offset + copy < 64) -	    return; -	p += copy; -	left -= copy; -	md5_process(pms, pms->buf); -    } - -    /* Process full blocks. */ -    for (; left >= 64; p += 64, left -= 64) -	md5_process(pms, p); - -    /* Process a final partial block. */ -    if (left) -	memcpy(pms->buf, p, left); -} - -void -md5_finish(md5_state_t *pms, md5_byte_t digest[16]) -{ -    static const md5_byte_t pad[64] = { -	0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -    }; -    md5_byte_t data[8]; -    int i; - -    /* Save the length before padding. */ -    for (i = 0; i < 8; ++i) -	data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); -    /* Pad to 56 bytes mod 64. */ -    md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); -    /* Append the length. */ -    md5_append(pms, data, 8); -    for (i = 0; i < 16; ++i) -	digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); -} diff --git a/protocols/md5.h b/protocols/md5.h deleted file mode 100644 index f24f2ff1..00000000 --- a/protocols/md5.h +++ /dev/null @@ -1,85 +0,0 @@ -/* -  Copyright (C) 1999 Aladdin Enterprises.  All rights reserved. -   -  This software is provided 'as-is', without any express or implied -  warranty.  In no event will the authors be held liable for any damages -  arising from the use of this software. - -  Permission is granted to anyone to use this software for any purpose, -  including commercial applications, and to alter it and redistribute it -  freely, subject to the following restrictions: - -  1. The origin of this software must not be misrepresented; you must not -     claim that you wrote the original software. If you use this software -     in a product, an acknowledgment in the product documentation would be -     appreciated but is not required. -  2. Altered source versions must be plainly marked as such, and must not be -     misrepresented as being the original software. -  3. This notice may not be removed or altered from any source distribution. - -  L. Peter Deutsch -  ghost@aladdin.com - - */ -/* -  Independent implementation of MD5 (RFC 1321). - -  This code implements the MD5 Algorithm defined in RFC 1321. -  It is derived directly from the text of the RFC and not from the -  reference implementation. - -  The original and principal author of md5.h is L. Peter Deutsch -  <ghost@aladdin.com>.  Other authors are noted in the change history -  that follows (in reverse chronological order): - -  2004-03-09 Jelmer Vernooij add G_MODULE_EXPORT for Bitlbee -  1999-11-04 lpd Edited comments slightly for automatic TOC extraction. -  1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); -	added conditionalization for C++ compilation from Martin -	Purschke <purschke@bnl.gov>. -  1999-05-03 lpd Original version. - */ - -#ifndef md5_INCLUDED -#  define md5_INCLUDED - -#include <glib.h> -#include <gmodule.h> - -/* - * This code has some adaptations for the Ghostscript environment, but it - * will compile and run correctly in any environment with 8-bit chars and - * 32-bit ints.  Specifically, it assumes that if the following are - * defined, they have the same meaning as in Ghostscript: P1, P2, P3, - * ARCH_IS_BIG_ENDIAN. - */ - -typedef unsigned char md5_byte_t; /* 8-bit byte */ -typedef unsigned int md5_word_t; /* 32-bit word */ - -/* Define the state of the MD5 Algorithm. */ -typedef struct md5_state_s { -    md5_word_t count[2];	/* message length in bits, lsw first */ -    md5_word_t abcd[4];		/* digest buffer */ -    md5_byte_t buf[64];		/* accumulate block */ -} md5_state_t; - -#ifdef __cplusplus -extern "C"  -{ -#endif - -/* Initialize the algorithm. */ -G_MODULE_EXPORT void md5_init(md5_state_t *pms); - -/* Append a string to the message. */ -G_MODULE_EXPORT void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); - -/* Finish the message and return the digest. */ -G_MODULE_EXPORT void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); - -#ifdef __cplusplus -}  /* end extern "C" */ -#endif - -#endif /* md5_INCLUDED */ diff --git a/protocols/msn/Makefile b/protocols/msn/Makefile index 873c831c..6a588613 100644 --- a/protocols/msn/Makefile +++ b/protocols/msn/Makefile @@ -16,6 +16,10 @@ LFLAGS += -r  # [SH] Phony targets  all: msn_mod.o +check: all +lcov: check +gcov:  +	gcov *.c  .PHONY: all clean distclean diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c index 3c7064f8..a2e8519a 100644 --- a/protocols/msn/msn.c +++ b/protocols/msn/msn.c @@ -26,91 +26,95 @@  #include "nogaim.h"  #include "msn.h" -static void msn_login( struct aim_user *acct ) +static char *msn_set_display_name( set_t *set, char *value ); + +static void msn_init( account_t *acc )  { -	struct gaim_connection *gc = new_gaim_conn( acct ); -	struct msn_data *md = g_new0( struct msn_data, 1 ); +	set_t *s; -	set_login_progress( gc, 1, "Connecting" ); +	s = set_add( &acc->set, "display_name", NULL, msn_set_display_name, acc ); +	s->flags |= ACC_SET_NOSAVE | ACC_SET_ONLINE_ONLY; + +	s = set_add( &acc->set, "mail_notifications", "false", set_eval_bool, acc ); +} + +static void msn_login( account_t *acc ) +{ +	struct im_connection *ic = imcb_new( acc ); +	struct msn_data *md = g_new0( struct msn_data, 1 ); -	gc->proto_data = md; +	ic->proto_data = md;  	md->fd = -1; -	if( strchr( acct->username, '@' ) == NULL ) +	if( strchr( acc->user, '@' ) == NULL )  	{ -		hide_login_progress( gc, "Invalid account name" ); -		signoff( gc ); +		imcb_error( ic, "Invalid account name" ); +		imc_logout( ic, FALSE );  		return;  	} -	md->fd = proxy_connect( "messenger.hotmail.com", 1863, msn_ns_connected, gc ); +	imcb_log( ic, "Connecting" ); +	 +	md->fd = proxy_connect( "messenger.hotmail.com", 1863, msn_ns_connected, ic );  	if( md->fd < 0 )  	{ -		hide_login_progress( gc, "Could not connect to server" ); -		signoff( gc ); -	} -	else -	{ -		md->gc = gc; -		md->away_state = msn_away_state_list; -		 -		msn_connections = g_slist_append( msn_connections, gc ); +		imcb_error( ic, "Could not connect to server" ); +		imc_logout( ic, TRUE ); +		return;  	} +	 +	md->ic = ic; +	md->away_state = msn_away_state_list; +	 +	msn_connections = g_slist_append( msn_connections, ic );  } -static void msn_close( struct gaim_connection *gc ) +static void msn_logout( struct im_connection *ic )  { -	struct msn_data *md = gc->proto_data; +	struct msn_data *md = ic->proto_data;  	GSList *l; -	if( md->fd >= 0 ) -		closesocket( md->fd ); -	 -	if( md->handler ) -	{ -		if( md->handler->rxq ) g_free( md->handler->rxq ); -		if( md->handler->cmd_text ) g_free( md->handler->cmd_text ); -		g_free( md->handler ); -	} -	 -	while( md->switchboards ) -		msn_sb_destroy( md->switchboards->data ); -	 -	if( md->msgq ) +	if( md )  	{ -		struct msn_message *m; +		if( md->fd >= 0 ) +			closesocket( md->fd ); -		for( l = md->msgq; l; l = l->next ) +		if( md->handler )  		{ -			m = l->data; -		 -			serv_got_crap( gc, "Warning: Closing down MSN connection with unsent message to %s, you'll have to resend it.", m->who ); -			g_free( m->who ); -			g_free( m->text ); -			g_free( m ); +			if( md->handler->rxq ) g_free( md->handler->rxq ); +			if( md->handler->cmd_text ) g_free( md->handler->cmd_text ); +			g_free( md->handler );  		} -		g_slist_free( md->msgq ); +		 +		while( md->switchboards ) +			msn_sb_destroy( md->switchboards->data ); +		 +		msn_msgq_purge( ic, &md->msgq ); +		 +		while( md->groupcount > 0 ) +			g_free( md->grouplist[--md->groupcount] ); +		g_free( md->grouplist ); +		 +		g_free( md );  	} -	for( l = gc->permit; l; l = l->next ) +	for( l = ic->permit; l; l = l->next )  		g_free( l->data ); -	g_slist_free( gc->permit ); +	g_slist_free( ic->permit ); -	for( l = gc->deny; l; l = l->next ) +	for( l = ic->deny; l; l = l->next )  		g_free( l->data ); -	g_slist_free( gc->deny ); -	 -	g_free( md ); +	g_slist_free( ic->deny ); -	msn_connections = g_slist_remove( msn_connections, gc ); +	msn_connections = g_slist_remove( msn_connections, ic );  } -static int msn_send_im( struct gaim_connection *gc, char *who, char *message, int len, int away ) +static int msn_buddy_msg( struct im_connection *ic, char *who, char *message, int away )  {  	struct msn_switchboard *sb; -	struct msn_data *md = gc->proto_data; +	struct msn_data *md = ic->proto_data; -	if( ( sb = msn_sb_by_handle( gc, who ) ) ) +	if( ( sb = msn_sb_by_handle( ic, who ) ) )  	{  		return( msn_sb_sendmessage( sb, message ) );  	} @@ -125,7 +129,7 @@ static int msn_send_im( struct gaim_connection *gc, char *who, char *message, in  		m->text = g_strdup( message );  		/* FIXME: *CHECK* the reliability of using spare sb's! */ -		if( ( sb = msn_sb_spare( gc ) ) ) +		if( ( sb = msn_sb_spare( ic ) ) )  		{  			debug( "Trying to use a spare switchboard to message %s", who ); @@ -143,7 +147,7 @@ static int msn_send_im( struct gaim_connection *gc, char *who, char *message, in  		/* If we reach this line, there was no spare switchboard, so let's make one. */  		g_snprintf( buf, sizeof( buf ), "XFR %d SB\r\n", ++md->trId ); -		if( !msn_write( gc, buf, strlen( buf ) ) ) +		if( !msn_write( ic, buf, strlen( buf ) ) )  		{  			g_free( m->who );  			g_free( m->text ); @@ -163,31 +167,22 @@ static int msn_send_im( struct gaim_connection *gc, char *who, char *message, in  	return( 0 );  } -static GList *msn_away_states( struct gaim_connection *gc ) +static GList *msn_away_states( struct im_connection *ic )  { -	GList *l = NULL; +	static GList *l = NULL;  	int i; -	for( i = 0; msn_away_state_list[i].number > -1; i ++ ) -		l = g_list_append( l, (void*) msn_away_state_list[i].name ); -	 -	return( l ); -} - -static char *msn_get_status_string( struct gaim_connection *gc, int number ) -{ -	const struct msn_away_state *st = msn_away_state_by_number( number ); +	if( 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 ); -	if( st ) -		return( (char*) st->name ); -	else -		return( "" ); +	return l;  } -static void msn_set_away( struct gaim_connection *gc, char *state, char *message ) +static void msn_set_away( struct im_connection *ic, char *state, char *message )  {  	char buf[1024]; -	struct msn_data *md = gc->proto_data; +	struct msn_data *md = ic->proto_data;  	const struct msn_away_state *st;  	if( strcmp( state, GAIM_AWAY_CUSTOM ) == 0 ) @@ -199,72 +194,43 @@ static void msn_set_away( struct gaim_connection *gc, char *state, char *message  	md->away_state = st;  	g_snprintf( buf, sizeof( buf ), "CHG %d %s\r\n", ++md->trId, st->code ); -	msn_write( gc, buf, strlen( buf ) ); +	msn_write( ic, buf, strlen( buf ) );  } -static void msn_set_info( struct gaim_connection *gc, char *info ) +static void msn_set_my_name( struct im_connection *ic, char *info )  { -	int i; -	char buf[1024], *fn, *s; -	struct msn_data *md = gc->proto_data; -	 -	if( strlen( info ) > 129 ) -	{ -		do_error_dialog( gc, "Maximum name length exceeded", "MSN" ); -		return; -	} -	 -	/* Of course we could use http_encode() here, but when we encode -	   every character, the server is less likely to complain about the -	   chosen name. However, the MSN server doesn't seem to like escaped -	   non-ASCII chars, so we keep those unescaped. */ -	s = fn = g_new0( char, strlen( info ) * 3 + 1 ); -	for( i = 0; info[i]; i ++ ) -		if( info[i] & 128 ) -		{ -			*s = info[i]; -			s ++; -		} -		else -		{ -			g_snprintf( s, 4, "%%%02X", info[i] ); -			s += 3; -		} -	 -	g_snprintf( buf, sizeof( buf ), "REA %d %s %s\r\n", ++md->trId, gc->username, fn ); -	msn_write( gc, buf, strlen( buf ) ); -	g_free( fn ); +	msn_set_display_name( set_find( &ic->acc->set, "display_name" ), info );  } -static void msn_get_info(struct gaim_connection *gc, char *who)  +static void msn_get_info(struct im_connection *ic, char *who)   {  	/* Just make an URL and let the user fetch the info */ -	serv_got_crap( gc, "%s\n%s: %s%s", _("User Info"), _("For now, fetch yourself"), PROFILE_URL, who ); +	imcb_log( ic, "%s\n%s: %s%s", _("User Info"), _("For now, fetch yourself"), PROFILE_URL, who );  } -static void msn_add_buddy( struct gaim_connection *gc, char *who ) +static void msn_add_buddy( struct im_connection *ic, char *who, char *group )  { -	msn_buddy_list_add( gc, "FL", who, who ); +	msn_buddy_list_add( ic, "FL", who, who );  } -static void msn_remove_buddy( struct gaim_connection *gc, char *who, char *group ) +static void msn_remove_buddy( struct im_connection *ic, char *who, char *group )  { -	msn_buddy_list_remove( gc, "FL", who ); +	msn_buddy_list_remove( ic, "FL", who );  } -static int msn_chat_send( struct gaim_connection *gc, int id, char *message ) +static void msn_chat_msg( struct groupchat *c, char *message, int flags )  { -	struct msn_switchboard *sb = msn_sb_by_id( gc, id ); +	struct msn_switchboard *sb = msn_sb_by_chat( c );  	if( sb ) -		return( msn_sb_sendmessage( sb, message ) ); -	else -		return( 0 ); +		msn_sb_sendmessage( sb, message ); +	/* FIXME: Error handling (although this can't happen unless something's +	   already severely broken) disappeared here! */  } -static void msn_chat_invite( struct gaim_connection *gc, int id, char *msg, char *who ) +static void msn_chat_invite( struct groupchat *c, char *who, char *message )  { -	struct msn_switchboard *sb = msn_sb_by_id( gc, id ); +	struct msn_switchboard *sb = msn_sb_by_chat( c );  	char buf[1024];  	if( sb ) @@ -274,39 +240,35 @@ static void msn_chat_invite( struct gaim_connection *gc, int id, char *msg, char  	}  } -static void msn_chat_leave( struct gaim_connection *gc, int id ) +static void msn_chat_leave( struct groupchat *c )  { -	struct msn_switchboard *sb = msn_sb_by_id( gc, id ); +	struct msn_switchboard *sb = msn_sb_by_chat( c );  	if( sb )  		msn_sb_write( sb, "OUT\r\n", 5 );  } -static int msn_chat_open( struct gaim_connection *gc, char *who ) +static struct groupchat *msn_chat_with( struct im_connection *ic, char *who )  {  	struct msn_switchboard *sb; -	struct msn_data *md = gc->proto_data; +	struct msn_data *md = ic->proto_data;  	char buf[1024]; -	if( ( sb = msn_sb_by_handle( gc, who ) ) ) +	if( ( sb = msn_sb_by_handle( ic, who ) ) )  	{  		debug( "Converting existing switchboard to %s to a groupchat", who ); -		msn_sb_to_chat( sb ); -		return( 1 ); +		return msn_sb_to_chat( sb );  	}  	else  	{  		struct msn_message *m; -		if( ( sb = msn_sb_spare( gc ) ) ) +		if( ( sb = msn_sb_spare( ic ) ) )  		{  			debug( "Trying to reuse an existing switchboard as a groupchat with %s", who );  			g_snprintf( buf, sizeof( buf ), "CAL %d %s\r\n", ++sb->trId, who );  			if( msn_sb_write( sb, buf, strlen( buf ) ) ) -			{ -				msn_sb_to_chat( sb ); -				return( 1 ); -			} +				return msn_sb_to_chat( sb );  		}  		/* If the stuff above failed for some reason: */ @@ -314,7 +276,7 @@ static int msn_chat_open( struct gaim_connection *gc, char *who )  		/* Request a new switchboard. */  		g_snprintf( buf, sizeof( buf ), "XFR %d SB\r\n", ++md->trId ); -		if( !msn_write( gc, buf, strlen( buf ) ) ) +		if( !msn_write( ic, buf, strlen( buf ) ) )  			return( 0 );  		/* Create a magic message. This is quite hackish, but who cares? :-P */ @@ -325,78 +287,111 @@ static int msn_chat_open( struct gaim_connection *gc, char *who )  		/* Queue the magic message and cross your fingers. */  		md->msgq = g_slist_append( md->msgq, m ); -		return( 1 ); +		/* FIXME: Can I try to return something here already? */ +		return NULL;  	} -	return( 0 ); +	return NULL;  } -static void msn_keepalive( struct gaim_connection *gc ) +static void msn_keepalive( struct im_connection *ic )  { -	msn_write( gc, "PNG\r\n", strlen( "PNG\r\n" ) ); +	msn_write( ic, "PNG\r\n", strlen( "PNG\r\n" ) );  } -static void msn_add_permit( struct gaim_connection *gc, char *who ) +static void msn_add_permit( struct im_connection *ic, char *who )  { -	msn_buddy_list_add( gc, "AL", who, who ); +	msn_buddy_list_add( ic, "AL", who, who );  } -static void msn_rem_permit( struct gaim_connection *gc, char *who ) +static void msn_rem_permit( struct im_connection *ic, char *who )  { -	msn_buddy_list_remove( gc, "AL", who ); +	msn_buddy_list_remove( ic, "AL", who );  } -static void msn_add_deny( struct gaim_connection *gc, char *who ) +static void msn_add_deny( struct im_connection *ic, char *who )  {  	struct msn_switchboard *sb; -	msn_buddy_list_add( gc, "BL", who, who ); +	msn_buddy_list_add( ic, "BL", who, who );  	/* If there's still a conversation with this person, close it. */ -	if( ( sb = msn_sb_by_handle( gc, who ) ) ) +	if( ( sb = msn_sb_by_handle( ic, who ) ) )  	{  		msn_sb_destroy( sb );  	}  } -static void msn_rem_deny( struct gaim_connection *gc, char *who ) +static void msn_rem_deny( struct im_connection *ic, char *who )  { -	msn_buddy_list_remove( gc, "BL", who ); +	msn_buddy_list_remove( ic, "BL", who );  } -static int msn_send_typing( struct gaim_connection *gc, char *who, int typing ) +static int msn_send_typing( struct im_connection *ic, char *who, int typing )  { -	if( typing ) -		return( msn_send_im( gc, who, TYPING_NOTIFICATION_MESSAGE, strlen( TYPING_NOTIFICATION_MESSAGE ), 0 ) ); +	if( typing & OPT_TYPING ) +		return( msn_buddy_msg( ic, who, TYPING_NOTIFICATION_MESSAGE, 0 ) );  	else  		return( 1 );  } -void msn_init() +static char *msn_set_display_name( set_t *set, char *value ) +{ +	account_t *acc = set->data; +	struct im_connection *ic = acc->ic; +	struct msn_data *md; +	char buf[1024], *fn; +	 +	/* Double-check. */ +	if( ic == NULL ) +		return NULL; +	 +	md = ic->proto_data; +	 +	if( strlen( value ) > 129 ) +	{ +		imcb_log( ic, "Maximum name length exceeded" ); +		return NULL; +	} +	 +	fn = msn_http_encode( value ); +	 +	g_snprintf( buf, sizeof( buf ), "REA %d %s %s\r\n", ++md->trId, ic->acc->user, fn ); +	msn_write( ic, buf, strlen( buf ) ); +	g_free( fn ); +	 +	/* Returning NULL would be better, because the server still has to +	   confirm the name change. However, it looks a bit confusing to the +	   user. */ +	return value; +} + +void msn_initmodule()  {  	struct prpl *ret = g_new0(struct prpl, 1); +	  	ret->name = "msn";  	ret->login = msn_login; -	ret->close = msn_close; -	ret->send_im = msn_send_im; +	ret->init = msn_init; +	ret->logout = msn_logout; +	ret->buddy_msg = msn_buddy_msg;  	ret->away_states = msn_away_states; -	ret->get_status_string = msn_get_status_string;  	ret->set_away = msn_set_away; -	ret->set_info = msn_set_info;  	ret->get_info = msn_get_info; +	ret->set_my_name = msn_set_my_name;  	ret->add_buddy = msn_add_buddy;  	ret->remove_buddy = msn_remove_buddy; -	ret->chat_send = msn_chat_send; +	ret->chat_msg = msn_chat_msg;  	ret->chat_invite = msn_chat_invite;  	ret->chat_leave = msn_chat_leave; -	ret->chat_open = msn_chat_open; +	ret->chat_with = msn_chat_with;  	ret->keepalive = msn_keepalive;  	ret->add_permit = msn_add_permit;  	ret->rem_permit = msn_rem_permit;  	ret->add_deny = msn_add_deny;  	ret->rem_deny = msn_rem_deny;  	ret->send_typing = msn_send_typing; -	ret->cmp_buddynames = g_strcasecmp; +	ret->handle_cmp = g_strcasecmp;  	register_protocol(ret);  } diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h index 0cd174f2..c8f4f4c6 100644 --- a/protocols/msn/msn.h +++ b/protocols/msn/msn.h @@ -28,11 +28,9 @@  #define TYPING_NOTIFICATION_MESSAGE "\r\r\rBEWARE, ME R TYPINK MESSAGE!!!!\r\r\r"  #define GROUPCHAT_SWITCHBOARD_MESSAGE "\r\r\rME WANT TALK TO MANY PEOPLE\r\r\r" -#ifdef _WIN32 -#define debug  +#ifdef DEBUG +#define debug( text... ) imcb_log( ic, text );  #else -#define debug( text... ) irc_usermsg( IRC, text ); -#undef debug  #define debug( text... )  #endif @@ -56,7 +54,7 @@  struct msn_data  { -	struct gaim_connection *gc; +	struct im_connection *ic;  	int fd;  	struct msn_handler_data *handler; @@ -65,8 +63,10 @@ struct msn_data  	GSList *msgq;  	GSList *switchboards; -	const struct msn_away_state *away_state; +	int sb_failures; +	time_t first_sb_failure; +	const struct msn_away_state *away_state;  	int buddycount;  	int groupcount;  	char **grouplist; @@ -74,7 +74,7 @@ struct msn_data  struct msn_switchboard  { -	struct gaim_connection *gc; +	struct im_connection *ic;  	int fd;  	gint inp; @@ -88,7 +88,7 @@ struct msn_switchboard  	GSList *msgq;  	char *who; -	struct conversation *chat; +	struct groupchat *chat;  };  struct msn_away_state @@ -145,17 +145,19 @@ GSList *msn_connections;  GSList *msn_switchboards;  /* ns.c */ -void msn_ns_connected( gpointer data, gint source, GaimInputCondition cond ); +gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond );  /* msn_util.c */ -int msn_write( struct gaim_connection *gc, char *s, int len ); -int msn_logged_in( struct gaim_connection *gc ); -int msn_buddy_list_add( struct gaim_connection *gc, char *list, char *who, char *realname ); -int msn_buddy_list_remove( struct gaim_connection *gc, char *list, char *who ); -void msn_buddy_ask( struct gaim_connection *gc, char *handle, char *realname ); +int msn_write( struct im_connection *ic, char *s, int len ); +int msn_logged_in( struct im_connection *ic ); +int msn_buddy_list_add( struct im_connection *ic, char *list, char *who, char *realname ); +int msn_buddy_list_remove( struct im_connection *ic, char *list, char *who ); +void msn_buddy_ask( struct im_connection *ic, char *handle, char *realname );  char *msn_findheader( char *text, char *header, int len );  char **msn_linesplit( char *line );  int msn_handler( struct msn_handler_data *h ); +char *msn_http_encode( const char *input ); +void msn_msgq_purge( struct im_connection *ic, GSList **list );  /* tables.c */  const struct msn_away_state *msn_away_state_by_number( int number ); @@ -165,11 +167,11 @@ const struct msn_status_code *msn_status_by_number( int number );  /* sb.c */  int msn_sb_write( struct msn_switchboard *sb, char *s, int len ); -struct msn_switchboard *msn_sb_create( struct gaim_connection *gc, char *host, int port, char *key, int session ); -struct msn_switchboard *msn_sb_by_handle( struct gaim_connection *gc, char *handle ); -struct msn_switchboard *msn_sb_by_id( struct gaim_connection *gc, int id ); -struct msn_switchboard *msn_sb_spare( struct gaim_connection *gc ); +struct msn_switchboard *msn_sb_create( struct im_connection *ic, char *host, int port, char *key, int session ); +struct msn_switchboard *msn_sb_by_handle( struct im_connection *ic, char *handle ); +struct msn_switchboard *msn_sb_by_chat( struct groupchat *c ); +struct msn_switchboard *msn_sb_spare( struct im_connection *ic );  int msn_sb_sendmessage( struct msn_switchboard *sb, char *text ); -void msn_sb_to_chat( struct msn_switchboard *sb ); +struct groupchat *msn_sb_to_chat( struct msn_switchboard *sb );  void msn_sb_destroy( struct msn_switchboard *sb ); -void msn_sb_connected( gpointer data, gint source, GaimInputCondition cond ); +gboolean msn_sb_connected( gpointer data, gint source, b_input_condition cond ); diff --git a/protocols/msn/msn_util.c b/protocols/msn/msn_util.c index c3bd73cc..fae2877d 100644 --- a/protocols/msn/msn_util.c +++ b/protocols/msn/msn_util.c @@ -27,57 +27,41 @@  #include "msn.h"  #include <ctype.h> -int msn_write( struct gaim_connection *gc, char *s, int len ) +int msn_write( struct im_connection *ic, char *s, int len )  { -	struct msn_data *md = gc->proto_data; +	struct msn_data *md = ic->proto_data;  	int st;  	st = write( md->fd, s, len );  	if( st != len )  	{ -		hide_login_progress_error( gc, "Short write() to main server" ); -		signoff( gc ); +		imcb_error( ic, "Short write() to main server" ); +		imc_logout( ic, TRUE );  		return( 0 );  	}  	return( 1 );  } -int msn_logged_in( struct gaim_connection *gc ) +int msn_logged_in( struct im_connection *ic )  { -	account_online( gc ); +	imcb_connected( ic );  	return( 0 );  } -int msn_buddy_list_add( struct gaim_connection *gc, char *list, char *who, char *realname_ ) +int msn_buddy_list_add( struct im_connection *ic, char *list, char *who, char *realname_ )  { -	struct msn_data *md = gc->proto_data; -	GSList *l, **lp = NULL; +	struct msn_data *md = ic->proto_data;  	char buf[1024], *realname; -	if( strcmp( list, "AL" ) == 0 ) -		lp = &gc->permit; -	else if( strcmp( list, "BL" ) == 0 ) -		lp = &gc->deny; -	 -	if( lp ) -		for( l = *lp; l; l = l->next ) -			if( g_strcasecmp( l->data, who ) == 0 ) -				return( 1 ); -	 -	realname = g_new0( char, strlen( realname_ ) * 3 + 1 ); -	strcpy( realname, realname_ ); -	http_encode( realname ); +	realname = msn_http_encode( realname_ );  	g_snprintf( buf, sizeof( buf ), "ADD %d %s %s %s\r\n", ++md->trId, list, who, realname ); -	if( msn_write( gc, buf, strlen( buf ) ) ) +	if( msn_write( ic, buf, strlen( buf ) ) )  	{  		g_free( realname ); -		if( lp ) -			*lp = g_slist_append( *lp, g_strdup( who ) ); -		  		return( 1 );  	} @@ -86,52 +70,31 @@ int msn_buddy_list_add( struct gaim_connection *gc, char *list, char *who, char  	return( 0 );  } -int msn_buddy_list_remove( struct gaim_connection *gc, char *list, char *who ) +int msn_buddy_list_remove( struct im_connection *ic, char *list, char *who )  { -	struct msn_data *md = gc->proto_data; -	GSList *l = NULL, **lp = NULL; +	struct msn_data *md = ic->proto_data;  	char buf[1024]; -	if( strcmp( list, "AL" ) == 0 ) -		lp = &gc->permit; -	else if( strcmp( list, "BL" ) == 0 ) -		lp = &gc->deny; -	 -	if( lp ) -	{ -		for( l = *lp; l; l = l->next ) -			if( g_strcasecmp( l->data, who ) == 0 ) -				break; -		 -		if( !l ) -			return( 1 ); -	} -	  	g_snprintf( buf, sizeof( buf ), "REM %d %s %s\r\n", ++md->trId, list, who ); -	if( msn_write( gc, buf, strlen( buf ) ) ) -	{ -		if( lp ) -			*lp = g_slist_remove( *lp, l->data ); -		 +	if( msn_write( ic, buf, strlen( buf ) ) )  		return( 1 ); -	}  	return( 0 );  }  struct msn_buddy_ask_data  { -	struct gaim_connection *gc; +	struct im_connection *ic;  	char *handle;  	char *realname;  };  static void msn_buddy_ask_yes( gpointer w, struct msn_buddy_ask_data *bla )  { -	msn_buddy_list_add( bla->gc, "AL", bla->handle, bla->realname ); +	msn_buddy_list_add( bla->ic, "AL", bla->handle, bla->realname ); -	if( find_buddy( bla->gc, bla->handle ) == NULL ) -		show_got_added( bla->gc, bla->handle, NULL ); +	if( imcb_find_buddy( bla->ic, bla->handle ) == NULL ) +		imcb_ask_add( bla->ic, bla->handle, NULL );  	g_free( bla->handle );  	g_free( bla->realname ); @@ -140,26 +103,26 @@ static void msn_buddy_ask_yes( gpointer w, struct msn_buddy_ask_data *bla )  static void msn_buddy_ask_no( gpointer w, struct msn_buddy_ask_data *bla )  { -	msn_buddy_list_add( bla->gc, "BL", bla->handle, bla->realname ); +	msn_buddy_list_add( bla->ic, "BL", bla->handle, bla->realname );  	g_free( bla->handle );  	g_free( bla->realname );  	g_free( bla );  } -void msn_buddy_ask( struct gaim_connection *gc, char *handle, char *realname ) +void msn_buddy_ask( struct im_connection *ic, char *handle, char *realname )  {  	struct msn_buddy_ask_data *bla = g_new0( struct msn_buddy_ask_data, 1 );  	char buf[1024]; -	bla->gc = gc; +	bla->ic = ic;  	bla->handle = g_strdup( handle );  	bla->realname = g_strdup( realname );  	g_snprintf( buf, sizeof( buf ),  	            "The user %s (%s) wants to add you to his/her buddy list.",  	            handle, realname ); -	do_ask_dialog( gc, buf, bla, msn_buddy_ask_yes, msn_buddy_ask_no ); +	imcb_ask( ic, buf, bla, msn_buddy_ask_yes, msn_buddy_ask_no );  }  char *msn_findheader( char *text, char *header, int len ) @@ -349,3 +312,63 @@ int msn_handler( struct msn_handler_data *h )  	return( 1 );  } + +/* The difference between this function and the normal http_encode() function +   is that this one escapes every 7-bit ASCII character because this is said +   to avoid some lame server-side checks when setting a real-name. Also, +   non-ASCII characters are not escaped because MSN servers don't seem to +   appreciate that! */ +char *msn_http_encode( const char *input ) +{ +	char *ret, *s; +	int i; +	 +	ret = s = g_new0( char, strlen( input ) * 3 + 1 ); +	for( i = 0; input[i]; i ++ ) +		if( input[i] & 128 ) +		{ +			*s = input[i]; +			s ++; +		} +		else +		{ +			g_snprintf( s, 4, "%%%02X", input[i] ); +			s += 3; +		} +	 +	return ret; +} + +void msn_msgq_purge( struct im_connection *ic, GSList **list ) +{ +	struct msn_message *m; +	GString *ret; +	GSList *l; +	 +	l = *list; +	if( l == NULL ) +		return; +	 +	m = l->data; +	ret = g_string_sized_new( 1024 ); +	g_string_printf( ret, "Warning: Cleaning up MSN (switchboard) connection with unsent " +	                      "messages to %s:", m->who ? m->who : "unknown recipient" ); +	 +	while( l ) +	{ +		m = l->data; +		 +		g_string_append_printf( ret, "\n%s", m->text ); +		 +		g_free( m->who ); +		g_free( m->text ); +		g_free( m ); +		 +		l = l->next; +	} +	g_slist_free( *list ); +	*list = NULL; +	 +	imcb_log( ic, ret->str ); +	g_string_free( ret, TRUE ); +} diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index 90d525ef..ff7da6ed 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -29,34 +29,34 @@  #include "passport.h"  #include "md5.h" -static void msn_ns_callback( gpointer data, gint source, GaimInputCondition cond ); +static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition cond );  static int msn_ns_command( gpointer data, char **cmd, int num_parts );  static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts ); -static void msn_auth_got_passport_id( struct passport_reply *rep ); +static void msn_auth_got_passport_token( struct msn_auth_data *mad ); -void msn_ns_connected( gpointer data, gint source, GaimInputCondition cond ) +gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond )  { -	struct gaim_connection *gc = data; +	struct im_connection *ic = data;  	struct msn_data *md;  	char s[1024]; -	if( !g_slist_find( msn_connections, gc ) ) -		return; +	if( !g_slist_find( msn_connections, ic ) ) +		return FALSE;  	if( source == -1 )  	{ -		hide_login_progress( gc, "Could not connect to server" ); -		signoff( gc ); -		return; +		imcb_error( ic, "Could not connect to server" ); +		imc_logout( ic, TRUE ); +		return FALSE;  	} -	md = gc->proto_data; +	md = ic->proto_data;  	if( !md->handler )  	{  		md->handler = g_new0( struct msn_handler_data, 1 ); -		md->handler->data = gc; +		md->handler->data = ic;  		md->handler->exec_command = msn_ns_command;  		md->handler->exec_message = msn_ns_message;  	} @@ -72,29 +72,35 @@ void msn_ns_connected( gpointer data, gint source, GaimInputCondition cond )  	md->handler->rxq = g_new0( char, 1 );  	g_snprintf( s, sizeof( s ), "VER %d MSNP8 CVR0\r\n", ++md->trId ); -	if( msn_write( gc, s, strlen( s ) ) ) +	if( msn_write( ic, s, strlen( s ) ) )  	{ -		gc->inpa = gaim_input_add( md->fd, GAIM_INPUT_READ, msn_ns_callback, gc ); -		set_login_progress( gc, 1, "Connected to server, waiting for reply" ); +		ic->inpa = b_input_add( md->fd, GAIM_INPUT_READ, msn_ns_callback, ic ); +		imcb_log( ic, "Connected to server, waiting for reply" );  	} +	 +	return FALSE;  } -void msn_ns_callback( gpointer data, gint source, GaimInputCondition cond ) +static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition cond )  { -	struct gaim_connection *gc = data; -	struct msn_data *md = gc->proto_data; +	struct im_connection *ic = data; +	struct msn_data *md = ic->proto_data;  	if( msn_handler( md->handler ) == -1 ) /* Don't do this on ret == 0, it's already done then. */  	{ -		hide_login_progress( gc, "Error while reading from server" ); -		signoff( gc ); +		imcb_error( ic, "Error while reading from server" ); +		imc_logout( ic, TRUE ); +		 +		return FALSE;  	} +	else +		return TRUE;  }  static int msn_ns_command( gpointer data, char **cmd, int num_parts )  { -	struct gaim_connection *gc = data; -	struct msn_data *md = gc->proto_data; +	struct im_connection *ic = data; +	struct msn_data *md = ic->proto_data;  	char buf[1024];  	if( num_parts == 0 ) @@ -107,20 +113,20 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )  	{  		if( cmd[2] && strncmp( cmd[2], "MSNP8", 5 ) != 0 )  		{ -			hide_login_progress( gc, "Unsupported protocol" ); -			signoff( gc ); +			imcb_error( ic, "Unsupported protocol" ); +			imc_logout( ic, FALSE );  			return( 0 );  		}  		g_snprintf( buf, sizeof( buf ), "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s\r\n", -		                                ++md->trId, gc->username ); -		return( msn_write( gc, buf, strlen( buf ) ) ); +		                                ++md->trId, ic->acc->user ); +		return( msn_write( ic, buf, strlen( buf ) ) );  	}  	else if( strcmp( cmd[0], "CVR" ) == 0 )  	{  		/* We don't give a damn about the information we just received */ -		g_snprintf( buf, sizeof( buf ), "USR %d TWN I %s\r\n", ++md->trId, gc->username ); -		return( msn_write( gc, buf, strlen( buf ) ) ); +		g_snprintf( buf, sizeof( buf ), "USR %d TWN I %s\r\n", ++md->trId, ic->acc->user ); +		return( msn_write( ic, buf, strlen( buf ) ) );  	}  	else if( strcmp( cmd[0], "XFR" ) == 0 )  	{ @@ -129,24 +135,24 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )  		if( num_parts == 6 && strcmp( cmd[2], "NS" ) == 0 )  		{ -			gaim_input_remove( gc->inpa ); -			gc->inpa = 0; +			b_event_remove( ic->inpa ); +			ic->inpa = 0;  			closesocket( md->fd );  			server = strchr( cmd[3], ':' );  			if( !server )  			{ -				hide_login_progress_error( gc, "Syntax error" ); -				signoff( gc ); +				imcb_error( ic, "Syntax error" ); +				imc_logout( ic, TRUE );  				return( 0 );  			}  			*server = 0;  			port = atoi( server + 1 );  			server = cmd[3]; -			set_login_progress( gc, 1, "Transferring to other server" ); +			imcb_log( ic, "Transferring to other server" ); -			md->fd = proxy_connect( server, port, msn_ns_connected, gc ); +			md->fd = proxy_connect( server, port, msn_ns_connected, ic );  		}  		else if( num_parts == 6 && strcmp( cmd[2], "SB" ) == 0 )  		{ @@ -155,8 +161,8 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )  			server = strchr( cmd[3], ':' );  			if( !server )  			{ -				hide_login_progress_error( gc, "Syntax error" ); -				signoff( gc ); +				imcb_error( ic, "Syntax error" ); +				imc_logout( ic, TRUE );  				return( 0 );  			}  			*server = 0; @@ -165,13 +171,13 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )  			if( strcmp( cmd[4], "CKI" ) != 0 )  			{ -				hide_login_progress_error( gc, "Unknown authentication method for switchboard" ); -				signoff( gc ); +				imcb_error( ic, "Unknown authentication method for switchboard" ); +				imc_logout( ic, TRUE );  				return( 0 );  			}  			debug( "Connecting to a new switchboard with key %s", cmd[5] ); -			sb = msn_sb_create( gc, server, port, cmd[5], MSN_SB_NEW ); +			sb = msn_sb_create( ic, server, port, cmd[5], MSN_SB_NEW );  			if( md->msgq )  			{ @@ -197,8 +203,8 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )  		}  		else  		{ -			hide_login_progress_error( gc, "Syntax error" ); -			signoff( gc ); +			imcb_error( ic, "Syntax error" ); +			imc_logout( ic, TRUE );  			return( 0 );  		}  	} @@ -207,29 +213,37 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )  		if( num_parts == 5 && strcmp( cmd[2], "TWN" ) == 0 && strcmp( cmd[3], "S" ) == 0 )  		{  			/* Time for some Passport black magic... */ -			if( !passport_get_id( msn_auth_got_passport_id, gc, gc->username, gc->password, cmd[4] ) ) +			if( !passport_get_token( msn_auth_got_passport_token, ic, ic->acc->user, ic->acc->pass, cmd[4] ) )  			{ -				hide_login_progress_error( gc, "Error while contacting Passport server" ); -				signoff( gc ); +				imcb_error( ic, "Error while contacting Passport server" ); +				imc_logout( ic, TRUE );  				return( 0 );  			}  		}  		else if( num_parts == 7 && strcmp( cmd[2], "OK" ) == 0 )  		{ +			set_t *s; +			  			http_decode( cmd[4] ); -			strncpy( gc->displayname, cmd[4], sizeof( gc->displayname ) ); -			gc->displayname[sizeof(gc->displayname)-1] = 0; +			strncpy( ic->displayname, cmd[4], sizeof( ic->displayname ) ); +			ic->displayname[sizeof(ic->displayname)-1] = 0; -			set_login_progress( gc, 1, "Authenticated, getting buddy list" ); +			if( ( s = set_find( &ic->acc->set, "display_name" ) ) ) +			{ +				g_free( s->value ); +				s->value = g_strdup( cmd[4] ); +			} +			 +			imcb_log( ic, "Authenticated, getting buddy list" );  			g_snprintf( buf, sizeof( buf ), "SYN %d 0\r\n", ++md->trId ); -			return( msn_write( gc, buf, strlen( buf ) ) ); +			return( msn_write( ic, buf, strlen( buf ) ) );  		}  		else  		{ -			hide_login_progress( gc, "Unknown authentication type" ); -			signoff( gc ); +			imcb_error( ic, "Unknown authentication type" ); +			imc_logout( ic, FALSE );  			return( 0 );  		}  	} @@ -237,8 +251,8 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )  	{  		if( num_parts != 4 )  		{ -			hide_login_progress_error( gc, "Syntax error" ); -			signoff( gc ); +			imcb_error( ic, "Syntax error" ); +			imc_logout( ic, TRUE );  			return( 0 );  		} @@ -246,8 +260,8 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )  		if( md->handler->msglen <= 0 )  		{ -			hide_login_progress_error( gc, "Syntax error" ); -			signoff( gc ); +			imcb_error( ic, "Syntax error" ); +			imc_logout( ic, TRUE );  			return( 0 );  		}  	} @@ -261,14 +275,14 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )  				md->grouplist = g_new0( char *, md->groupcount );  			if( !*cmd[3] || md->buddycount == 0 ) -				msn_logged_in( gc ); +				msn_logged_in( ic );  		}  		else  		{  			/* Hrrm... This SYN reply doesn't really look like something we expected.  			   Let's assume everything is okay. */ -			msn_logged_in( gc ); +			msn_logged_in( ic );  		}  	}  	else if( strcmp( cmd[0], "LST" ) == 0 ) @@ -277,8 +291,8 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )  		if( num_parts != 4 && num_parts != 5 )  		{ -			hide_login_progress( gc, "Syntax error" ); -			signoff( gc ); +			imcb_error( ic, "Syntax error" ); +			imc_logout( ic, TRUE );  			return( 0 );  		} @@ -290,36 +304,37 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )  			char *group = NULL;  			int num; -			if( cmd[4] != NULL && sscanf( cmd[4], "%d", &num ) == 1 ) +			if( cmd[4] != NULL && sscanf( cmd[4], "%d", &num ) == 1 && num < md->groupcount )  				group = md->grouplist[num]; -			add_buddy( gc, group, cmd[1], cmd[2] ); +			imcb_add_buddy( ic, cmd[1], group ); +			imcb_rename_buddy( ic, cmd[1], cmd[2] );  		}  		if( list & 2 ) /* AL */  		{ -			gc->permit = g_slist_append( gc->permit, g_strdup( cmd[1] ) ); +			ic->permit = g_slist_append( ic->permit, g_strdup( cmd[1] ) );  		}  		if( list & 4 ) /* BL */  		{ -			gc->deny = g_slist_append( gc->deny, g_strdup( cmd[1] ) ); +			ic->deny = g_slist_append( ic->deny, g_strdup( cmd[1] ) );  		}  		if( list & 8 ) /* RL */  		{  			if( ( list & 6 ) == 0 ) -				msn_buddy_ask( gc, cmd[1], cmd[2] ); +				msn_buddy_ask( ic, cmd[1], cmd[2] );  		}  		if( --md->buddycount == 0 )  		{ -			if( gc->flags & OPT_LOGGED_IN ) +			if( ic->flags & OPT_LOGGED_IN )  			{ -				serv_got_crap( gc, "Successfully transferred to different server" ); +				imcb_log( ic, "Successfully transferred to different server" );  				g_snprintf( buf, sizeof( buf ), "CHG %d %s %d\r\n", ++md->trId, md->away_state->code, 0 ); -				return( msn_write( gc, buf, strlen( buf ) ) ); +				return( msn_write( ic, buf, strlen( buf ) ) );  			}  			else  			{ -				msn_logged_in( gc ); +				msn_logged_in( ic );  			}  		}  	} @@ -329,8 +344,8 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )  		if( num_parts != 4 )  		{ -			hide_login_progress_error( gc, "Syntax error" ); -			signoff( gc ); +			imcb_error( ic, "Syntax error" ); +			imc_logout( ic, TRUE );  			return( 0 );  		} @@ -348,8 +363,8 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )  		if( num_parts != 3 )  		{ -			hide_login_progress_error( gc, "Syntax error" ); -			signoff( gc ); +			imcb_error( ic, "Syntax error" ); +			imc_logout( ic, TRUE );  			return( 0 );  		} @@ -362,7 +377,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )  		for( i = 0; i < 16; i ++ )  			g_snprintf( buf + strlen( buf ), 3, "%02x", digest[i] ); -		return( msn_write( gc, buf, strlen( buf ) ) ); +		return( msn_write( ic, buf, strlen( buf ) ) );  	}  	else if( strcmp( cmd[0], "ILN" ) == 0 )  	{ @@ -370,13 +385,13 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )  		if( num_parts != 6 )  		{ -			hide_login_progress_error( gc, "Syntax error" ); -			signoff( gc ); +			imcb_error( ic, "Syntax error" ); +			imc_logout( ic, TRUE );  			return( 0 );  		}  		http_decode( cmd[4] ); -		serv_buddy_rename( gc, cmd[3], cmd[4] ); +		imcb_rename_buddy( ic, cmd[3], cmd[4] );  		st = msn_away_state_by_code( cmd[2] );  		if( !st ) @@ -385,12 +400,13 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )  			st = msn_away_state_list;  		} -		serv_got_update( gc, cmd[3], 1, 0, 0, 0, st->number, 0 ); +		imcb_buddy_status( ic, cmd[3], OPT_LOGGED_IN | +		                   ( st->number ? OPT_AWAY : 0 ), st->name, NULL );  	}  	else if( strcmp( cmd[0], "FLN" ) == 0 )  	{  		if( cmd[1] ) -			serv_got_update( gc, cmd[1], 0, 0, 0, 0, 0, 0 ); +			imcb_buddy_status( ic, cmd[1], 0, NULL, NULL );  	}  	else if( strcmp( cmd[0], "NLN" ) == 0 )  	{ @@ -398,13 +414,13 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )  		if( num_parts != 5 )  		{ -			hide_login_progress_error( gc, "Syntax error" ); -			signoff( gc ); +			imcb_error( ic, "Syntax error" ); +			imc_logout( ic, TRUE );  			return( 0 );  		}  		http_decode( cmd[3] ); -		serv_buddy_rename( gc, cmd[2], cmd[3] ); +		imcb_rename_buddy( ic, cmd[2], cmd[3] );  		st = msn_away_state_by_code( cmd[1] );  		if( !st ) @@ -413,7 +429,8 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )  			st = msn_away_state_list;  		} -		serv_got_update( gc, cmd[2], 1, 0, 0, 0, st->number, 0 ); +		imcb_buddy_status( ic, cmd[2], OPT_LOGGED_IN | +		                   ( st->number ? OPT_AWAY : 0 ), st->name, NULL );  	}  	else if( strcmp( cmd[0], "RNG" ) == 0 )  	{ @@ -423,8 +440,8 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )  		if( num_parts != 7 )  		{ -			hide_login_progress_error( gc, "Syntax error" ); -			signoff( gc ); +			imcb_error( ic, "Syntax error" ); +			imc_logout( ic, TRUE );  			return( 0 );  		} @@ -433,8 +450,8 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )  		server = strchr( cmd[2], ':' );  		if( !server )  		{ -			hide_login_progress_error( gc, "Syntax error" ); -			signoff( gc ); +			imcb_error( ic, "Syntax error" ); +			imc_logout( ic, TRUE );  			return( 0 );  		}  		*server = 0; @@ -443,14 +460,14 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )  		if( strcmp( cmd[3], "CKI" ) != 0 )  		{ -			hide_login_progress_error( gc, "Unknown authentication method for switchboard" ); -			signoff( gc ); +			imcb_error( ic, "Unknown authentication method for switchboard" ); +			imc_logout( ic, TRUE );  			return( 0 );  		}  		debug( "Got a call from %s (session %d). Key = %s", cmd[5], session, cmd[4] ); -		sb = msn_sb_create( gc, server, port, cmd[4], session ); +		sb = msn_sb_create( ic, server, port, cmd[4], session );  		sb->who = g_strdup( cmd[5] );  	}  	else if( strcmp( cmd[0], "ADD" ) == 0 ) @@ -463,74 +480,91 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )  			if( strchr( cmd[4], '@' ) == NULL )  			{ -				hide_login_progress_error( gc, "Syntax error" ); -				signoff( gc ); -				return( 0 ); +				imcb_error( ic, "Syntax error" ); +				imc_logout( ic, TRUE ); +				return 0;  			} -			/* We got added by someone. If we don't have this person in permit/deny yet, inform the user. */ -			for( l = gc->permit; l; l = l->next ) +			/* We got added by someone. If we don't have this +			   person in permit/deny yet, inform the user. */ +			for( l = ic->permit; l; l = l->next )  				if( g_strcasecmp( l->data, cmd[4] ) == 0 ) -					return( 1 ); +					return 1; -			for( l = gc->deny; l; l = l->next ) +			for( l = ic->deny; l; l = l->next )  				if( g_strcasecmp( l->data, cmd[4] ) == 0 ) -					return( 1 ); +					return 1; -			msn_buddy_ask( gc, cmd[4], cmd[5] ); +			msn_buddy_ask( ic, cmd[4], cmd[5] ); +		} +		else if( num_parts >= 6 && strcmp( cmd[2], "FL" ) == 0 ) +		{ +			http_decode( cmd[5] ); +			imcb_add_buddy( ic, cmd[4], NULL ); +			imcb_rename_buddy( ic, cmd[4], cmd[5] );  		}  	}  	else if( strcmp( cmd[0], "OUT" ) == 0 )  	{ +		int allow_reconnect = TRUE; +		  		if( cmd[1] && strcmp( cmd[1], "OTH" ) == 0 )  		{ -			hide_login_progress_error( gc, "Someone else logged in with your account" ); -			gc->wants_to_die = 1; +			imcb_error( ic, "Someone else logged in with your account" ); +			allow_reconnect = FALSE;  		}  		else if( cmd[1] && strcmp( cmd[1], "SSD" ) == 0 )  		{ -			hide_login_progress_error( gc, "Terminating session because of server shutdown" ); +			imcb_error( ic, "Terminating session because of server shutdown" );  		}  		else  		{ -			hide_login_progress_error( gc, "Session terminated by remote server (reason unknown)" ); +			imcb_error( ic, "Session terminated by remote server (reason unknown)" );  		} -		signoff( gc ); +		imc_logout( ic, allow_reconnect );  		return( 0 );  	}  	else if( strcmp( cmd[0], "REA" ) == 0 )  	{  		if( num_parts != 5 )  		{ -			hide_login_progress_error( gc, "Syntax error" ); -			signoff( gc ); +			imcb_error( ic, "Syntax error" ); +			imc_logout( ic, TRUE );  			return( 0 );  		} -		if( g_strcasecmp( cmd[3], gc->username ) == 0 ) +		if( g_strcasecmp( cmd[3], ic->acc->user ) == 0 )  		{ +			set_t *s; +			  			http_decode( cmd[4] ); -			strncpy( gc->displayname, cmd[4], sizeof( gc->displayname ) ); -			gc->displayname[sizeof(gc->displayname)-1] = 0; +			strncpy( ic->displayname, cmd[4], sizeof( ic->displayname ) ); +			ic->displayname[sizeof(ic->displayname)-1] = 0; +			 +			if( ( s = set_find( &ic->acc->set, "display_name" ) ) ) +			{ +				g_free( s->value ); +				s->value = g_strdup( cmd[4] ); +			}  		}  		else  		{  			/* This is not supposed to happen, but let's handle it anyway... */  			http_decode( cmd[4] ); -			serv_buddy_rename( gc, cmd[3], cmd[4] ); +			imcb_rename_buddy( ic, cmd[3], cmd[4] );  		}  	}  	else if( strcmp( cmd[0], "IPG" ) == 0 )  	{ -		do_error_dialog( gc, "Received IPG command, we don't handle them yet.", "MSN" ); +		imcb_error( ic, "Received IPG command, we don't handle them yet." );  		md->handler->msglen = atoi( cmd[1] );  		if( md->handler->msglen <= 0 )  		{ -			hide_login_progress_error( gc, "Syntax error" ); -			signoff( gc ); +			imcb_error( ic, "Syntax error" ); +			imc_logout( ic, TRUE );  			return( 0 );  		}  	} @@ -539,18 +573,17 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )  		int num = atoi( cmd[0] );  		const struct msn_status_code *err = msn_status_by_number( num ); -		g_snprintf( buf, sizeof( buf ), "Error reported by MSN server: %s", err->text ); -		do_error_dialog( gc, buf, "MSN" ); +		imcb_error( ic, "Error reported by MSN server: %s", err->text );  		if( err->flags & STATUS_FATAL )  		{ -			signoff( gc ); +			imc_logout( ic, TRUE );  			return( 0 );  		}  	}  	else  	{ -		debug( "Received unknown command from main server: %s", cmd[0] ); +		/* debug( "Received unknown command from main server: %s", cmd[0] ); */  	}  	return( 1 ); @@ -558,7 +591,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )  static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts )  { -	struct gaim_connection *gc = data; +	struct im_connection *ic = data;  	char *body;  	int blen = 0; @@ -594,7 +627,7 @@ static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int  				if( mtype && strcmp( mtype, "1" ) == 0 )  				{  					if( arg1 ) -						serv_got_crap( gc, "The server is going down for maintenance in %s minutes.", arg1 ); +						imcb_log( ic, "The server is going down for maintenance in %s minutes.", arg1 );  				}  				if( arg1 ) g_free( arg1 ); @@ -609,9 +642,9 @@ static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int  				char *inbox = msn_findheader( body, "Inbox-Unread:", blen );  				char *folders = msn_findheader( body, "Folders-Unread:", blen ); -				if( inbox && folders ) +				if( inbox && folders && set_getbool( &ic->acc->set, "mail_notifications" ) )  				{ -					serv_got_crap( gc, "INBOX contains %s new messages, plus %s messages in other folders.", inbox, folders ); +					imcb_log( ic, "INBOX contains %s new messages, plus %s messages in other folders.", inbox, folders );  				}  			}  			else if( g_strncasecmp( ct, "text/x-msmsgsemailnotification", 30 ) == 0 ) @@ -619,9 +652,9 @@ static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int  				char *from = msn_findheader( body, "From-Addr:", blen );  				char *fromname = msn_findheader( body, "From:", blen ); -				if( from && fromname ) +				if( from && fromname && set_getbool( &ic->acc->set, "mail_notifications" ) )  				{ -					serv_got_crap( gc, "Received an e-mail message from %s <%s>.", fromname, from ); +					imcb_log( ic, "Received an e-mail message from %s <%s>.", fromname, from );  				}  			}  			else if( g_strncasecmp( ct, "text/x-msmsgsactivemailnotification", 35 ) == 0 ) @@ -640,21 +673,26 @@ static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int  	return( 1 );  } -static void msn_auth_got_passport_id( struct passport_reply *rep ) +static void msn_auth_got_passport_token( struct msn_auth_data *mad )  { -	struct gaim_connection *gc = rep->data; -	struct msn_data *md = gc->proto_data; -	char *key = rep->result; -	char buf[1024]; +	struct im_connection *ic = mad->data; +	struct msn_data *md; -	if( key == NULL ) +	/* Dead connection? */ +	if( g_slist_find( msn_connections, ic ) == NULL ) +		return; +	 +	md = ic->proto_data; +	if( mad->token )  	{ -		hide_login_progress( gc, "Error during Passport authentication" ); -		signoff( gc ); +		char buf[1024]; +		 +		g_snprintf( buf, sizeof( buf ), "USR %d TWN S %s\r\n", ++md->trId, mad->token ); +		msn_write( ic, buf, strlen( buf ) );  	}  	else  	{ -		g_snprintf( buf, sizeof( buf ), "USR %d TWN S %s\r\n", ++md->trId, key ); -		msn_write( gc, buf, strlen( buf ) ); +		imcb_error( ic, "Error during Passport authentication: %s", mad->error ); +		imc_logout( ic, TRUE );  	}  } diff --git a/protocols/msn/passport.c b/protocols/msn/passport.c index 34703432..565d15f3 100644 --- a/protocols/msn/passport.c +++ b/protocols/msn/passport.c @@ -1,8 +1,7 @@ -/* passport.c +/** passport.c   * - * Functions to login to microsoft passport service for Messenger - * Copyright (C) 2004 Wouter Paesen <wouter@blue-gate.be> - * Copyright (C) 2004 Wilmer van der Gaast <wilmer@gaast.net> + * Functions to login to Microsoft Passport service for Messenger + * Copyright (C) 2004-2008 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 version 2                    @@ -23,189 +22,149 @@  #include "passport.h"  #include "msn.h"  #include "bitlbee.h" +#include "url.h" +#include "misc.h" +#include "xmltree.h"  #include <ctype.h>  #include <errno.h> -#define MSN_BUF_LEN 8192 +static int passport_get_token_real( struct msn_auth_data *mad ); +static void passport_get_token_ready( struct http_request *req ); -static char *prd_cached = NULL; - -static int passport_get_id_real( gpointer func, gpointer data, char *header ); -static void passport_get_id_ready( struct http_request *req ); - -static int passport_retrieve_dalogin( gpointer data, gpointer func, char *header ); -static void passport_retrieve_dalogin_ready( struct http_request *req ); - -static char *passport_create_header( char *cookie, char *email, char *pwd ); -static void destroy_reply( struct passport_reply *rep ); - -int passport_get_id( gpointer func, gpointer data, char *username, char *password, char *cookie ) +int passport_get_token( gpointer func, gpointer data, char *username, char *password, char *cookie )  { -	char *header = passport_create_header( cookie, username, password ); +	struct msn_auth_data *mad = g_new0( struct msn_auth_data, 1 ); +	int i; -	if( prd_cached == NULL ) -		return passport_retrieve_dalogin( func, data, header ); -	else -		return passport_get_id_real( func, data, header ); +	mad->username = g_strdup( username ); +	mad->password = g_strdup( password ); +	mad->cookie = g_strdup( cookie ); +	 +	mad->callback = func; +	mad->data = data; +	 +	mad->url = g_strdup( SOAP_AUTHENTICATION_URL ); +	mad->ttl = 3; /* Max. # of redirects. */ +	 +	/* HTTP-escape stuff and s/,/&/ */ +	http_decode( mad->cookie ); +	for( i = 0; mad->cookie[i]; i ++ ) +		if( mad->cookie[i] == ',' ) +			mad->cookie[i] = '&'; +	 +	/* Microsoft doesn't allow password longer than 16 chars and silently +	   fails authentication if you give the "full version" of your passwd. */ +	if( strlen( mad->password ) > MAX_PASSPORT_PWLEN ) +		mad->password[MAX_PASSPORT_PWLEN] = 0; +	 +	return passport_get_token_real( mad );  } -static int passport_get_id_real( gpointer func, gpointer data, char *header ) +static int passport_get_token_real( struct msn_auth_data *mad )  { -	struct passport_reply *rep; -	char *server, *dummy, *reqs; +	char *post_payload, *post_request;  	struct http_request *req; +	url_t url; -	rep = g_new0( struct passport_reply, 1 ); -	rep->data = data; -	rep->func = func; -	 -	server = g_strdup( prd_cached ); -	dummy = strchr( server, '/' ); -	 -	if( dummy == NULL ) -	{ -		destroy_reply( rep ); -		return( 0 ); -	} +	url_set( &url, mad->url ); -	reqs = g_malloc( strlen( header ) + strlen( dummy ) + 128 ); -	sprintf( reqs, "GET %s HTTP/1.0\r\n%s\r\n\r\n", dummy, header ); +	post_payload = g_markup_printf_escaped( SOAP_AUTHENTICATION_PAYLOAD, +	                                        mad->username, +	                                        mad->password, +	                                        mad->cookie ); -	*dummy = 0; -	req = http_dorequest( server, 443, 1, reqs, passport_get_id_ready, rep ); +	post_request = g_strdup_printf( SOAP_AUTHENTICATION_REQUEST, +	                                url.file, url.host, +	                                (int) strlen( post_payload ), +	                                post_payload ); +	                                 +	req = http_dorequest( url.host, url.port, 1, post_request, +	                      passport_get_token_ready, mad ); -	g_free( server ); -	g_free( reqs ); +	g_free( post_request ); +	g_free( post_payload ); -	if( req == NULL ) -		destroy_reply( rep ); -	 -	return( req != NULL ); +	return req != NULL;  } -static void passport_get_id_ready( struct http_request *req ) +static xt_status passport_xt_extract_token( struct xt_node *node, gpointer data ); +static xt_status passport_xt_handle_fault( struct xt_node *node, gpointer data ); + +static const struct xt_handler_entry passport_xt_handlers[] = { +	{ "wsse:BinarySecurityToken", "wst:RequestedSecurityToken", passport_xt_extract_token }, +	{ "S:Fault",                  "S:Envelope",                 passport_xt_handle_fault  }, +	{ NULL,                       NULL,                         NULL                      } +}; + +static void passport_get_token_ready( struct http_request *req )  { -	struct passport_reply *rep = req->data; +	struct msn_auth_data *mad = req->data; +	struct xt_parser *parser; -	if( !g_slist_find( msn_connections, rep->data ) || !req->finished || !req->reply_headers ) -	{ -		destroy_reply( rep ); -		return; -	} +	g_free( mad->url ); +	g_free( mad->error ); +	mad->url = mad->error = NULL;  	if( req->status_code == 200 )  	{ -		char *dummy; -		 -		if( ( dummy = strstr( req->reply_headers, "from-PP='" ) ) ) -		{ -			char *responseend; -			 -			dummy += strlen( "from-PP='" ); -			responseend = strchr( dummy, '\'' ); -			if( responseend ) -				*responseend = 0; -			 -			rep->result = g_strdup( dummy ); -		} +		parser = xt_new( passport_xt_handlers, mad ); +		xt_feed( parser, req->reply_body, req->body_size ); +		xt_handle( parser, NULL, -1 ); +		xt_free( parser ); +	} +	else +	{ +		mad->error = g_strdup_printf( "HTTP error %d (%s)", req->status_code, +		                              req->status_string ? req->status_string : "unknown" );  	} -	rep->func( rep ); -	destroy_reply( rep ); -} - -static char *passport_create_header( char *cookie, char *email, char *pwd ) -{ -	char *buffer = g_new0( char, 2048 ); -	char *currenttoken; -	char *email_enc, *pwd_enc; -	 -	email_enc = g_new0( char, strlen( email ) * 3 + 1 ); -	strcpy( email_enc, email ); -	http_encode( email_enc ); -	 -	pwd_enc = g_new0( char, strlen( pwd ) * 3 + 1 ); -	strcpy( pwd_enc, pwd ); -	http_encode( pwd_enc ); -	 -	currenttoken = strstr( cookie, "lc=" ); -	if( currenttoken == NULL ) -		return( NULL ); -	 -	g_snprintf( buffer, 2048, -	            "Authorization: Passport1.4 OrgVerb=GET," -	            "OrgURL=http%%3A%%2F%%2Fmessenger%%2Emsn%%2Ecom," -	            "sign-in=%s,pwd=%s,%s", email_enc, pwd_enc, -	            currenttoken ); -	 -	g_free( email_enc ); -	g_free( pwd_enc ); +	if( mad->error == NULL && mad->token == NULL ) +		mad->error = g_strdup( "Could not parse Passport server response" ); -	return( buffer ); +	if( mad->url && mad->token == NULL ) +	{ +		passport_get_token_real( mad ); +	} +	else +	{ +		mad->callback( mad ); +		 +		g_free( mad->url ); +		g_free( mad->username ); +		g_free( mad->password ); +		g_free( mad->cookie ); +		g_free( mad->token ); +		g_free( mad->error ); +		g_free( mad ); +	}  } -#define PPR_REQUEST "GET /rdr/pprdr.asp HTTP/1.0\r\n\r\n" -static int passport_retrieve_dalogin( gpointer func, gpointer data, char *header ) +static xt_status passport_xt_extract_token( struct xt_node *node, gpointer data )  { -	struct passport_reply *rep = g_new0( struct passport_reply, 1 ); -	struct http_request *req; -	 -	rep->data = data; -	rep->func = func; -	rep->header = header; -	 -	req = http_dorequest( "nexus.passport.com", 443, 1, PPR_REQUEST, passport_retrieve_dalogin_ready, rep ); +	struct msn_auth_data *mad = data; +	char *s; -	if( !req ) -		destroy_reply( rep ); +	if( ( s = xt_find_attr( node, "Id" ) ) && strcmp( s, "PPToken1" ) == 0 ) +		mad->token = g_memdup( node->text, node->text_len + 1 ); -	return( req != NULL ); +	return XT_HANDLED;  } -static void passport_retrieve_dalogin_ready( struct http_request *req ) +static xt_status passport_xt_handle_fault( struct xt_node *node, gpointer data )  { -	struct passport_reply *rep = req->data; -	char *dalogin; -	char *urlend; +	struct msn_auth_data *mad = data; +	struct xt_node *code = xt_find_node( node->children, "faultcode" ); +	struct xt_node *string = xt_find_node( node->children, "faultstring" ); +	struct xt_node *redirect = xt_find_node( node->children, "psf:redirectUrl" ); -	if( !g_slist_find( msn_connections, rep->data ) || !req->finished || !req->reply_headers ) -	{ -		destroy_reply( rep ); -		return; -	} -	 -	dalogin = strstr( req->reply_headers, "DALogin=" );	 -	 -	if( !dalogin ) -		goto failure; -	 -	dalogin += strlen( "DALogin=" ); -	urlend = strchr( dalogin, ',' ); -	if( urlend ) -		*urlend = 0; -	 -	/* strip the http(s):// part from the url */ -	urlend = strstr( urlend, "://" ); -	if( urlend ) -		dalogin = urlend + strlen( "://" ); -	 -	if( prd_cached == NULL ) -		prd_cached = g_strdup( dalogin ); +	if( redirect && redirect->text_len && mad->ttl-- > 0 ) +		mad->url = g_memdup( redirect->text, redirect->text_len + 1 ); -	if( passport_get_id_real( rep->func, rep->data, rep->header ) ) -	{ -		destroy_reply( rep ); -		return; -	} +	if( code == NULL || code->text_len == 0 ) +		mad->error = g_strdup( "Unknown error" ); +	else +		mad->error = g_strdup_printf( "%s (%s)", code->text, string && string->text_len ? +		                              string->text : "no description available" ); -failure:	 -	rep->func( rep ); -	destroy_reply( rep ); -} - -static void destroy_reply( struct passport_reply *rep ) -{ -	g_free( rep->result ); -	g_free( rep->header ); -	g_free( rep ); +	return XT_HANDLED;  } diff --git a/protocols/msn/passport.h b/protocols/msn/passport.h index f7e6ebb6..517d2e91 100644 --- a/protocols/msn/passport.h +++ b/protocols/msn/passport.h @@ -1,10 +1,7 @@ -#ifndef __PASSPORT_H__ -#define __PASSPORT_H__  /* passport.h   * - * Functions to login to Microsoft Passport Service for Messenger - * Copyright (C) 2004 Wouter Paesen <wouter@blue-gate.be>, - *                    Wilmer van der Gaast <wilmer@gaast.net> + * Functions to login to Microsoft Passport service for Messenger + * Copyright (C) 2004-2008 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 version 2                    @@ -17,9 +14,15 @@   *                                                                                      * 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           + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA             */ +/* Thanks to http://msnpiki.msnfanatic.com/index.php/MSNP13:SOAPTweener +   for the specs! */ + +#ifndef __PASSPORT_H__ +#define __PASSPORT_H__ +  #include <stdio.h>  #include <stdlib.h>  #include <string.h> @@ -32,14 +35,79 @@  #endif  #include "nogaim.h" -struct passport_reply +#define MAX_PASSPORT_PWLEN 16 + +struct msn_auth_data  { -	void (*func)( struct passport_reply * ); -	void *data; -	char *result; -	char *header; +	char *url; +	int ttl; +	 +	char *username; +	char *password; +	char *cookie; +	 +	/* The end result, the only thing we'll really be interested in +	   once finished. */ +	char *token; +	char *error; /* Yeah, or that... */ +	 +	void (*callback)( struct msn_auth_data *mad ); +	gpointer data;  }; -int passport_get_id( gpointer func, gpointer data, char *username, char *password, char *cookie ); +#define SOAP_AUTHENTICATION_URL "https://loginnet.passport.com/RST.srf" + +#define SOAP_AUTHENTICATION_REQUEST \ +"POST %s HTTP/1.0\r\n" \ +"Accept: text/*\r\n" \ +"User-Agent: BitlBee " BITLBEE_VERSION "\r\n" \ +"Host: %s\r\n" \ +"Content-Length: %d\r\n" \ +"Cache-Control: no-cache\r\n" \ +"\r\n" \ +"%s" + +#define SOAP_AUTHENTICATION_PAYLOAD \ +"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" \ +"<Envelope xmlns=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:wsse=\"http://schemas.xmlsoap.org/ws/2003/06/secext\" xmlns:saml=\"urn:oasis:names:tc:SAML:1.0:assertion\" xmlns:wsp=\"http://schemas.xmlsoap.org/ws/2002/12/policy\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\" xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/03/addressing\" xmlns:wssc=\"http://schemas.xmlsoap.org/ws/2004/04/sc\" xmlns:wst=\"http://schemas.xmlsoap.org/ws/2004/04/trust\">" \ +  "<Header>" \ +    "<ps:AuthInfo xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\" Id=\"PPAuthInfo\">" \ +      "<ps:HostingApp>{7108E71A-9926-4FCB-BCC9-9A9D3F32E423}</ps:HostingApp>" \ +      "<ps:BinaryVersion>4</ps:BinaryVersion>" \ +      "<ps:UIVersion>1</ps:UIVersion>" \ +      "<ps:Cookies></ps:Cookies>" \ +      "<ps:RequestParams>AQAAAAIAAABsYwQAAAAzMDg0</ps:RequestParams>" \ +    "</ps:AuthInfo>" \ +    "<wsse:Security>" \ +       "<wsse:UsernameToken Id=\"user\">" \ +         "<wsse:Username>%s</wsse:Username>" \ +         "<wsse:Password>%s</wsse:Password>" \ +       "</wsse:UsernameToken>" \ +    "</wsse:Security>" \ +  "</Header>" \ +  "<Body>" \ +    "<ps:RequestMultipleSecurityTokens xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\" Id=\"RSTS\">" \ +      "<wst:RequestSecurityToken Id=\"RST0\">" \ +        "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>" \ +        "<wsp:AppliesTo>" \ +          "<wsa:EndpointReference>" \ +            "<wsa:Address>http://Passport.NET/tb</wsa:Address>" \ +          "</wsa:EndpointReference>" \ +        "</wsp:AppliesTo>" \ +      "</wst:RequestSecurityToken>" \ +      "<wst:RequestSecurityToken Id=\"RST1\">" \ +       "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>" \ +        "<wsp:AppliesTo>" \ +          "<wsa:EndpointReference>" \ +            "<wsa:Address>messenger.msn.com</wsa:Address>" \ +          "</wsa:EndpointReference>" \ +        "</wsp:AppliesTo>" \ +        "<wsse:PolicyReference URI=\"?%s\"></wsse:PolicyReference>" \ +      "</wst:RequestSecurityToken>" \ +    "</ps:RequestMultipleSecurityTokens>" \ +  "</Body>" \ +"</Envelope>" + +int passport_get_token( gpointer func, gpointer data, char *username, char *password, char *cookie );  #endif /* __PASSPORT_H__ */ diff --git a/protocols/msn/sb.c b/protocols/msn/sb.c index 34b0a30a..18c41ef5 100644 --- a/protocols/msn/sb.c +++ b/protocols/msn/sb.c @@ -29,7 +29,7 @@  #include "passport.h"  #include "md5.h" -static void msn_sb_callback( gpointer data, gint source, GaimInputCondition cond ); +static gboolean msn_sb_callback( gpointer data, gint source, b_input_condition cond );  static int msn_sb_command( gpointer data, char **cmd, int num_parts );  static int msn_sb_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts ); @@ -47,9 +47,9 @@ int msn_sb_write( struct msn_switchboard *sb, char *s, int len )  	return( 1 );  } -struct msn_switchboard *msn_sb_create( struct gaim_connection *gc, char *host, int port, char *key, int session ) +struct msn_switchboard *msn_sb_create( struct im_connection *ic, char *host, int port, char *key, int session )  { -	struct msn_data *md = gc->proto_data; +	struct msn_data *md = ic->proto_data;  	struct msn_switchboard *sb = g_new0( struct msn_switchboard, 1 );  	sb->fd = proxy_connect( host, port, msn_sb_connected, sb ); @@ -59,7 +59,7 @@ struct msn_switchboard *msn_sb_create( struct gaim_connection *gc, char *host, i  		return( NULL );  	} -	sb->gc = gc; +	sb->ic = ic;  	sb->key = g_strdup( key );  	sb->session = session; @@ -69,9 +69,9 @@ struct msn_switchboard *msn_sb_create( struct gaim_connection *gc, char *host, i  	return( sb );  } -struct msn_switchboard *msn_sb_by_handle( struct gaim_connection *gc, char *handle ) +struct msn_switchboard *msn_sb_by_handle( struct im_connection *ic, char *handle )  { -	struct msn_data *md = gc->proto_data; +	struct msn_data *md = ic->proto_data;  	struct msn_switchboard *sb;  	GSList *l; @@ -85,25 +85,25 @@ struct msn_switchboard *msn_sb_by_handle( struct gaim_connection *gc, char *hand  	return( NULL );  } -struct msn_switchboard *msn_sb_by_id( struct gaim_connection *gc, int id ) +struct msn_switchboard *msn_sb_by_chat( struct groupchat *c )  { -	struct msn_data *md = gc->proto_data; +	struct msn_data *md = c->ic->proto_data;  	struct msn_switchboard *sb;  	GSList *l;  	for( l = md->switchboards; l; l = l->next )  	{  		sb = l->data; -		if( sb->chat && sb->chat->id == id ) +		if( sb->chat == c )  			return( sb );  	}  	return( NULL );  } -struct msn_switchboard *msn_sb_spare( struct gaim_connection *gc ) +struct msn_switchboard *msn_sb_spare( struct im_connection *ic )  { -	struct msn_data *md = gc->proto_data; +	struct msn_data *md = ic->proto_data;  	struct msn_switchboard *sb;  	GSList *l; @@ -121,12 +121,13 @@ int msn_sb_sendmessage( struct msn_switchboard *sb, char *text )  {  	if( sb->ready )  	{ -		char cmd[1024], *buf; +		char *packet, *buf;  		int i, j; +		/* Build the message. Convert LF to CR-LF for normal messages. */  		if( strcmp( text, TYPING_NOTIFICATION_MESSAGE ) != 0 )  		{ -			buf = g_new0( char, sizeof( MSN_MESSAGE_HEADERS ) + strlen( text ) * 2 ); +			buf = g_new0( char, sizeof( MSN_MESSAGE_HEADERS ) + strlen( text ) * 2 + 1 );  			i = strlen( MSN_MESSAGE_HEADERS );  			strcpy( buf, MSN_MESSAGE_HEADERS ); @@ -140,20 +141,22 @@ int msn_sb_sendmessage( struct msn_switchboard *sb, char *text )  		}  		else  		{ -			i = strlen( MSN_TYPING_HEADERS ) + strlen( sb->gc->username ); -			buf = g_new0( char, strlen( MSN_TYPING_HEADERS ) + strlen( sb->gc->username ) ); -			i = g_snprintf( buf, i, MSN_TYPING_HEADERS, sb->gc->username ); +			i = strlen( MSN_TYPING_HEADERS ) + strlen( sb->ic->acc->user ); +			buf = g_new0( char, i ); +			i = g_snprintf( buf, i, MSN_TYPING_HEADERS, sb->ic->acc->user );  		} -		g_snprintf( cmd, sizeof( cmd ), "MSG %d N %d\r\n", ++sb->trId, i ); -		if( msn_sb_write( sb, cmd, strlen( cmd ) ) && msn_sb_write( sb, buf, i ) ) +		/* Build the final packet (MSG command + the message). */ +		packet = g_strdup_printf( "MSG %d N %d\r\n%s", ++sb->trId, i, buf ); +		g_free( buf ); +		if( msn_sb_write( sb, packet, strlen( packet ) ) )  		{ -			g_free( buf ); +			g_free( packet );  			return( 1 );  		}  		else  		{ -			g_free( buf ); +			g_free( packet );  			return( 0 );  		}  	} @@ -173,18 +176,18 @@ int msn_sb_sendmessage( struct msn_switchboard *sb, char *text )  	}  } -void msn_sb_to_chat( struct msn_switchboard *sb ) +struct groupchat *msn_sb_to_chat( struct msn_switchboard *sb )  { -	struct gaim_connection *gc = sb->gc; +	struct im_connection *ic = sb->ic;  	char buf[1024];  	/* Create the groupchat structure. */  	g_snprintf( buf, sizeof( buf ), "MSN groupchat session %d", sb->session ); -	sb->chat = serv_got_joined_chat( gc, ++msn_chat_id, buf ); +	sb->chat = imcb_chat_new( ic, buf );  	/* Populate the channel. */ -	if( sb->who ) add_chat_buddy( sb->chat, sb->who ); -	add_chat_buddy( sb->chat, gc->username ); +	if( sb->who ) imcb_chat_add_buddy( sb->chat, sb->who ); +	imcb_chat_add_buddy( sb->chat, ic->acc->user );  	/* And make sure the switchboard doesn't look like a regular chat anymore. */  	if( sb->who ) @@ -192,41 +195,25 @@ void msn_sb_to_chat( struct msn_switchboard *sb )  		g_free( sb->who );  		sb->who = NULL;  	} +	 +	return sb->chat;  }  void msn_sb_destroy( struct msn_switchboard *sb )  { -	struct gaim_connection *gc = sb->gc; -	struct msn_data *md = gc->proto_data; +	struct im_connection *ic = sb->ic; +	struct msn_data *md = ic->proto_data;  	debug( "Destroying switchboard: %s", sb->who ? sb->who : sb->key ? sb->key : "" ); -	if( sb->msgq ) -	{ -		struct msn_message *m; -		GSList *l; -		 -		for( l = sb->msgq; l; l = l->next ) -		{ -			m = l->data; - -			g_free( m->who ); -			g_free( m->text ); -			g_free( m ); -		} -		g_slist_free( sb->msgq ); -		 -		serv_got_crap( gc, "Warning: Closing down MSN switchboard connection with " -		                   "unsent message to %s, you'll have to resend it.", -		                   sb->who ? sb->who : "(unknown)" ); -	} +	msn_msgq_purge( ic, &sb->msgq );  	if( sb->key ) g_free( sb->key );  	if( sb->who ) g_free( sb->who );  	if( sb->chat )  	{ -		serv_got_chat_left( gc, sb->chat->id ); +		imcb_chat_free( sb->chat );  	}  	if( sb->handler ) @@ -236,7 +223,7 @@ void msn_sb_destroy( struct msn_switchboard *sb )  		g_free( sb->handler );  	} -	if( sb->inp ) gaim_input_remove( sb->inp ); +	if( sb->inp ) b_event_remove( sb->inp );  	closesocket( sb->fd );  	msn_switchboards = g_slist_remove( msn_switchboards, sb ); @@ -244,25 +231,25 @@ void msn_sb_destroy( struct msn_switchboard *sb )  	g_free( sb );  } -void msn_sb_connected( gpointer data, gint source, GaimInputCondition cond ) +gboolean msn_sb_connected( gpointer data, gint source, b_input_condition cond )  {  	struct msn_switchboard *sb = data; -	struct gaim_connection *gc; +	struct im_connection *ic;  	struct msn_data *md;  	char buf[1024];  	/* Are we still alive? */  	if( !g_slist_find( msn_switchboards, sb ) ) -		return; +		return FALSE; -	gc = sb->gc; -	md = gc->proto_data; +	ic = sb->ic; +	md = ic->proto_data;  	if( source != sb->fd )  	{ -		debug( "ERROR %d while connecting to switchboard server", 1 ); +		debug( "Error %d while connecting to switchboard server", 1 );  		msn_sb_destroy( sb ); -		return; +		return FALSE;  	}  	/* Prepare the callback */ @@ -274,31 +261,80 @@ void msn_sb_connected( gpointer data, gint source, GaimInputCondition cond )  	sb->handler->exec_message = msn_sb_message;  	if( sb->session == MSN_SB_NEW ) -		g_snprintf( buf, sizeof( buf ), "USR %d %s %s\r\n", ++sb->trId, gc->username, sb->key ); +		g_snprintf( buf, sizeof( buf ), "USR %d %s %s\r\n", ++sb->trId, ic->acc->user, sb->key );  	else -		g_snprintf( buf, sizeof( buf ), "ANS %d %s %s %d\r\n", ++sb->trId, gc->username, sb->key, sb->session ); +		g_snprintf( buf, sizeof( buf ), "ANS %d %s %s %d\r\n", ++sb->trId, ic->acc->user, sb->key, sb->session );  	if( msn_sb_write( sb, buf, strlen( buf ) ) ) -		sb->inp = gaim_input_add( sb->fd, GAIM_INPUT_READ, msn_sb_callback, sb ); +		sb->inp = b_input_add( sb->fd, GAIM_INPUT_READ, msn_sb_callback, sb );  	else -		debug( "ERROR %d while connecting to switchboard server", 2 ); +		debug( "Error %d while connecting to switchboard server", 2 ); +	 +	return FALSE;  } -static void msn_sb_callback( gpointer data, gint source, GaimInputCondition cond ) +static gboolean msn_sb_callback( gpointer data, gint source, b_input_condition cond )  {  	struct msn_switchboard *sb = data; +	struct im_connection *ic = sb->ic; +	struct msn_data *md = ic->proto_data;  	if( msn_handler( sb->handler ) == -1 )  	{ -		debug( "ERROR: Switchboard died" ); +		time_t now = time( NULL ); +		 +		if( now - md->first_sb_failure > 600 ) +		{ +			/* It's not really the first one, but the start of this "series". +			   With this, the warning below will be shown only if this happens +			   at least three times in ten minutes. This algorithm isn't +			   perfect, but for this purpose it will do. */ +			md->first_sb_failure = now; +			md->sb_failures = 0; +		} +		 +		debug( "Error: Switchboard died" ); +		if( ++ md->sb_failures >= 3 ) +			imcb_log( ic, "Warning: Many switchboard failures on MSN connection. " +			              "There might be problems delivering your messages." ); +		 +		if( sb->msgq != NULL ) +		{ +			char buf[1024]; +			 +			if( md->msgq == NULL ) +			{ +				md->msgq = sb->msgq; +			} +			else +			{ +				GSList *l; +				 +				for( l = md->msgq; l->next; l = l->next ); +				l->next = sb->msgq; +			} +			sb->msgq = NULL; +			 +			debug( "Moved queued messages back to the main queue, creating a new switchboard to retry." ); +			g_snprintf( buf, sizeof( buf ), "XFR %d SB\r\n", ++md->trId ); +			if( !msn_write( ic, buf, strlen( buf ) ) ) +				return FALSE; +		} +		  		msn_sb_destroy( sb ); +		 +		return FALSE; +	} +	else +	{ +		return TRUE;  	}  }  static int msn_sb_command( gpointer data, char **cmd, int num_parts )  {  	struct msn_switchboard *sb = data; -	struct gaim_connection *gc = sb->gc; +	struct im_connection *ic = sb->ic;  	char buf[1024];  	if( !num_parts ) @@ -309,8 +345,8 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts )  	if( strcmp( cmd[0], "XFR" ) == 0 )  	{ -		hide_login_progress_error( gc, "Received an XFR from a switchboard server, unable to comply! This is likely to be a bug, please report it!" ); -		signoff( gc ); +		imcb_error( ic, "Received an XFR from a switchboard server, unable to comply! This is likely to be a bug, please report it!" ); +		imc_logout( ic, TRUE );  		return( 0 );  	}  	else if( strcmp( cmd[0], "USR" ) == 0 ) @@ -362,17 +398,17 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts )  			if( num == 1 )  			{  				g_snprintf( buf, sizeof( buf ), "MSN groupchat session %d", sb->session ); -				sb->chat = serv_got_joined_chat( gc, ++msn_chat_id, buf ); +				sb->chat = imcb_chat_new( ic, buf );  				g_free( sb->who );  				sb->who = NULL;  			} -			add_chat_buddy( sb->chat, cmd[4] ); +			imcb_chat_add_buddy( sb->chat, cmd[4] );  			if( num == tot )  			{ -				add_chat_buddy( sb->chat, gc->username ); +				imcb_chat_add_buddy( sb->chat, ic->acc->user );  			}  		}  	} @@ -450,11 +486,11 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts )  			/* This SB is a one-to-one chat right now, but someone else is joining. */  			msn_sb_to_chat( sb ); -			add_chat_buddy( sb->chat, cmd[1] ); +			imcb_chat_add_buddy( sb->chat, cmd[1] );  		}  		else if( sb->chat )  		{ -			add_chat_buddy( sb->chat, cmd[1] ); +			imcb_chat_add_buddy( sb->chat, cmd[1] );  			sb->ready = 1;  		}  		else @@ -479,6 +515,17 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts )  			return( 0 );  		}  	} +	else if( strcmp( cmd[0], "NAK" ) == 0 ) +	{ +		if( sb->who ) +		{ +			imcb_log( ic, "The MSN servers could not deliver one of your messages to %s.", sb->who ); +		} +		else +		{ +			imcb_log( ic, "The MSN servers could not deliver one of your groupchat messages to all participants." ); +		} +	}  	else if( strcmp( cmd[0], "BYE" ) == 0 )  	{  		if( num_parts < 2 ) @@ -504,7 +551,7 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts )  		}  		else if( sb->chat )  		{ -			remove_chat_buddy( sb->chat, cmd[1], "" ); +			imcb_chat_remove_buddy( sb->chat, cmd[1], "" );  		}  		else  		{ @@ -516,8 +563,7 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts )  		int num = atoi( cmd[0] );  		const struct msn_status_code *err = msn_status_by_number( num ); -		g_snprintf( buf, sizeof( buf ), "Error reported by switchboard server: %s", err->text ); -		do_error_dialog( gc, buf, "MSN" ); +		imcb_error( ic, "Error reported by switchboard server: %s", err->text );  		if( err->flags & STATUS_SB_FATAL )  		{ @@ -526,31 +572,20 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts )  		}  		else if( err->flags & STATUS_FATAL )  		{ -			signoff( gc ); +			imc_logout( ic, TRUE );  			return 0;  		}  		else if( err->flags & STATUS_SB_IM_SPARE )  		{  			if( sb->who )  			{ -				struct msn_message *m; -				GSList *l; -				  				/* Apparently some invitation failed. We might want to use this  				   board later, so keep it as a spare. */  				g_free( sb->who );  				sb->who = NULL;  				/* Also clear the msgq, otherwise someone else might get them. */ -				for( l = sb->msgq; l; l = l->next ) -				{ -					m = l->data; -					g_free( m->who ); -					g_free( m->text ); -					g_free( m ); -				} -				g_slist_free( sb->msgq ); -				sb->msgq = NULL; +				msn_msgq_purge( ic, &sb->msgq );  			}  			/* Do NOT return 0 here, we want to keep this sb. */ @@ -558,7 +593,7 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts )  	}  	else  	{ -		debug( "Received unknown command from switchboard server: %s", cmd[0] ); +		/* debug( "Received unknown command from switchboard server: %s", cmd[0] ); */  	}  	return( 1 ); @@ -567,7 +602,7 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts )  static int msn_sb_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts )  {  	struct msn_switchboard *sb = data; -	struct gaim_connection *gc = sb->gc; +	struct im_connection *ic = sb->ic;  	char *body;  	int blen = 0; @@ -596,11 +631,11 @@ static int msn_sb_message( gpointer data, char *msg, int msglen, char **cmd, int  			if( sb->who )  			{ -				serv_got_im( gc, cmd[1], body, 0, 0, blen ); +				imcb_buddy_msg( ic, cmd[1], body, 0, 0 );  			}  			else if( sb->chat )  			{ -				serv_got_chat_in( gc, sb->chat->id, cmd[1], 0, body, 0 ); +				imcb_chat_msg( sb->chat, cmd[1], body, 0, 0 );  			}  			else  			{ @@ -655,11 +690,11 @@ static int msn_sb_message( gpointer data, char *msg, int msglen, char **cmd, int  			if( sb->who )  			{ -				serv_got_im( gc, cmd[1], buf, 0, 0, strlen( buf ) ); +				imcb_buddy_msg( ic, cmd[1], buf, 0, 0 );  			}  			else if( sb->chat )  			{ -				serv_got_chat_in( gc, sb->chat->id, cmd[1], 0, buf, 0 ); +				imcb_chat_msg( sb->chat, cmd[1], buf, 0, 0 );  			}  			else  			{ @@ -672,7 +707,7 @@ static int msn_sb_message( gpointer data, char *msg, int msglen, char **cmd, int  			if( who )  			{ -				serv_got_typing( gc, who, 5, 1 ); +				imcb_buddy_typing( ic, who, OPT_TYPING );  				g_free( who );  			} diff --git a/protocols/nogaim.c b/protocols/nogaim.c index 04d48236..3ce15166 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -1,7 +1,7 @@    /********************************************************************\    * BitlBee -- An IRC to other IM-networks gateway                     *    *                                                                    * -  * Copyright 2002-2004 Wilmer van der Gaast and others                * +  * Copyright 2002-2006 Wilmer van der Gaast and others                *    \********************************************************************/  /* @@ -12,8 +12,6 @@   * This file contains functions called by the Gaim IM-modules. It's written   * from scratch for BitlBee and doesn't contain any code from Gaim anymore   * (except for the function names). - * - * Copyright 2002-2006 Wilmer van der Gaast <wilmer@gaast.net> and others   */  /* @@ -37,7 +35,7 @@  #include "nogaim.h"  #include <ctype.h> -static int remove_chat_buddy_silent( struct conversation *b, char *handle ); +static int remove_chat_buddy_silent( struct groupchat *b, const char *handle );  GSList *connections; @@ -49,7 +47,7 @@ gboolean load_plugin(char *path)  	GModule *mod = g_module_open(path, G_MODULE_BIND_LAZY);  	if(!mod) { -		log_message(LOGLVL_ERROR, "Can't find `%s', not loading", path); +		log_message(LOGLVL_ERROR, "Can't find `%s', not loading (%s)\n", path, g_module_error());  		return FALSE;  	} @@ -100,7 +98,6 @@ void register_protocol (struct prpl *p)  	protocols = g_list_append(protocols, p);  } -   struct prpl *find_protocol(const char *name)  {  	GList *gl; @@ -116,25 +113,25 @@ struct prpl *find_protocol(const char *name)  /* nogaim.c */  void nogaim_init()  { -	extern void msn_init(); -	extern void oscar_init(); -	extern void byahoo_init(); -	extern void jabber_init(); +	extern void msn_initmodule(); +	extern void oscar_initmodule(); +	extern void byahoo_initmodule(); +	extern void jabber_initmodule();  #ifdef WITH_MSN -	msn_init(); +	msn_initmodule();  #endif  #ifdef WITH_OSCAR -	oscar_init(); +	oscar_initmodule();  #endif  #ifdef WITH_YAHOO -	byahoo_init(); +	byahoo_initmodule();  #endif  #ifdef WITH_JABBER -	jabber_init(); +	jabber_initmodule();  #endif  #ifdef WITH_PLUGINS @@ -146,72 +143,38 @@ GSList *get_connections() { return connections; }  /* multi.c */ -struct gaim_connection *new_gaim_conn( struct aim_user *user ) +struct im_connection *imcb_new( account_t *acc )  { -	struct gaim_connection *gc; -	account_t *a; -	 -	gc = g_new0( struct gaim_connection, 1 ); +	struct im_connection *ic; -	gc->prpl = user->prpl; -	g_snprintf( gc->username, sizeof( gc->username ), "%s", user->username ); -	g_snprintf( gc->password, sizeof( gc->password ), "%s", user->password ); -	/* [MD]	BUGFIX: don't set gc->irc to the global IRC, but use the one from the struct aim_user. -	 * This fixes daemon mode breakage where IRC doesn't point to the currently active connection. -	 */ -	gc->irc=user->irc; +	ic = g_new0( struct im_connection, 1 ); -	connections = g_slist_append( connections, gc ); +	ic->irc = acc->irc; +	ic->acc = acc; +	acc->ic = ic; -	user->gc = gc; -	gc->user = user; +	connections = g_slist_append( connections, ic ); -	// Find the account_t so we can set its gc pointer -	for( a = gc->irc->accounts; a; a = a->next ) -		if( ( struct aim_user * ) a->gc == user ) -		{ -			a->gc = gc; -			break; -		} -	 -	return( gc ); +	return( ic );  } -void destroy_gaim_conn( struct gaim_connection *gc ) +void imc_free( struct im_connection *ic )  {  	account_t *a;  	/* Destroy the pointer to this connection from the account list */ -	for( a = gc->irc->accounts; a; a = a->next ) -		if( a->gc == gc ) +	for( a = ic->irc->accounts; a; a = a->next ) +		if( a->ic == ic )  		{ -			a->gc = NULL; +			a->ic = NULL;  			break;  		} -	connections = g_slist_remove( connections, gc ); -	g_free( gc->user ); -	g_free( gc ); -} - -void set_login_progress( struct gaim_connection *gc, int step, char *msg ) -{ -	serv_got_crap( gc, "Logging in: %s", msg ); -} - -/* Errors *while* logging in */ -void hide_login_progress( struct gaim_connection *gc, char *msg ) -{ -	serv_got_crap( gc, "Login error: %s", msg ); -} - -/* Errors *after* logging in */ -void hide_login_progress_error( struct gaim_connection *gc, char *msg ) -{ -	serv_got_crap( gc, "Logged out: %s", msg ); +	connections = g_slist_remove( connections, ic ); +	g_free( ic );  } -void serv_got_crap( struct gaim_connection *gc, char *format, ... ) +static void serv_got_crap( struct im_connection *ic, char *format, ... )  {  	va_list params;  	char *text; @@ -221,57 +184,91 @@ void serv_got_crap( struct gaim_connection *gc, char *format, ... )  	text = g_strdup_vprintf( format, params );  	va_end( params ); -	if( ( g_strcasecmp( set_getstr( gc->irc, "strip_html" ), "always" ) == 0 ) || -	    ( ( gc->flags & OPT_CONN_HTML ) && set_getint( gc->irc, "strip_html" ) ) ) +	if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) || +	    ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )  		strip_html( text );  	/* Try to find a different connection on the same protocol. */ -	for( a = gc->irc->accounts; a; a = a->next ) -		if( a->prpl == gc->prpl && a->gc != gc ) +	for( a = ic->irc->accounts; a; a = a->next ) +		if( a->prpl == ic->acc->prpl && a->ic != ic )  			break;  	/* If we found one, include the screenname in the message. */  	if( a ) -		irc_usermsg( gc->irc, "%s(%s) - %s", gc->prpl->name, gc->username, text ); +		irc_usermsg( ic->irc, "%s(%s) - %s", ic->acc->prpl->name, ic->acc->user, text ); +	else +		irc_usermsg( ic->irc, "%s - %s", ic->acc->prpl->name, text ); +	 +	g_free( text ); +} + +void imcb_log( struct im_connection *ic, char *format, ... ) +{ +	va_list params; +	char *text; +	 +	va_start( params, format ); +	text = g_strdup_vprintf( format, params ); +	va_end( params ); +	 +	if( ic->flags & OPT_LOGGED_IN ) +		serv_got_crap( ic, "%s", text ); +	else +		serv_got_crap( ic, "Logging in: %s", text ); +	 +	g_free( text ); +} + +void imcb_error( struct im_connection *ic, char *format, ... ) +{ +	va_list params; +	char *text; +	 +	va_start( params, format ); +	text = g_strdup_vprintf( format, params ); +	va_end( params ); +	 +	if( ic->flags & OPT_LOGGED_IN ) +		serv_got_crap( ic, "Error: %s", text );  	else -		irc_usermsg( gc->irc, "%s - %s", gc->prpl->name, text ); +		serv_got_crap( ic, "Couldn't log in: %s", text );  	g_free( text );  } -static gboolean send_keepalive( gpointer d ) +static gboolean send_keepalive( gpointer d, gint fd, b_input_condition cond )  { -	struct gaim_connection *gc = d; +	struct im_connection *ic = d; -	if( gc->prpl && gc->prpl->keepalive ) -		gc->prpl->keepalive( gc ); +	if( ic->acc->prpl->keepalive ) +		ic->acc->prpl->keepalive( ic );  	return TRUE;  } -void account_online( struct gaim_connection *gc ) +void imcb_connected( struct im_connection *ic )  {  	user_t *u;  	/* MSN servers sometimes redirect you to a different server and do  	   the whole login sequence again, so these "late" calls to this  	   function should be handled correctly. (IOW, ignored) */ -	if( gc->flags & OPT_LOGGED_IN ) +	if( ic->flags & OPT_LOGGED_IN )  		return; -	u = user_find( gc->irc, gc->irc->nick ); +	u = user_find( ic->irc, ic->irc->nick ); -	serv_got_crap( gc, "Logged in" ); +	imcb_log( ic, "Logged in" ); -	gc->keepalive = g_timeout_add( 60000, send_keepalive, gc ); -	gc->flags |= OPT_LOGGED_IN; +	ic->keepalive = b_timeout_add( 60000, send_keepalive, ic ); +	ic->flags |= OPT_LOGGED_IN;  	/* Also necessary when we're not away, at least for some of the  	   protocols. */ -	bim_set_away( gc, u->away ); +	imc_set_away( ic, u->away );  } -gboolean auto_reconnect( gpointer data ) +gboolean auto_reconnect( gpointer data, gint fd, b_input_condition cond )  {  	account_t *a = data; @@ -283,26 +280,34 @@ gboolean auto_reconnect( gpointer data )  void cancel_auto_reconnect( account_t *a )  { -	while( g_source_remove_by_user_data( (gpointer) a ) ); +	b_event_remove( a->reconnect );  	a->reconnect = 0;  } -void signoff( struct gaim_connection *gc ) +void imc_logout( struct im_connection *ic, int allow_reconnect )  { -	irc_t *irc = gc->irc; -	user_t *t, *u = irc->users; +	irc_t *irc = ic->irc; +	user_t *t, *u;  	account_t *a; -	serv_got_crap( gc, "Signing off.." ); - -	gaim_input_remove( gc->keepalive ); -	gc->keepalive = 0; -	gc->prpl->close( gc ); -	gaim_input_remove( gc->inpa ); +	/* Nested calls might happen sometimes, this is probably the best +	   place to catch them. */ +	if( ic->flags & OPT_LOGGING_OUT ) +		return; +	else +		ic->flags |= OPT_LOGGING_OUT; +	 +	imcb_log( ic, "Signing off.." ); +	 +	b_event_remove( ic->keepalive ); +	ic->keepalive = 0; +	ic->acc->prpl->logout( ic ); +	b_event_remove( ic->inpa ); +	u = irc->users;  	while( u )  	{ -		if( u->gc == gc ) +		if( u->ic == ic )  		{  			t = u->next;  			user_del( irc, u->nick ); @@ -312,94 +317,74 @@ void signoff( struct gaim_connection *gc )  			u = u->next;  	} -	query_del_by_gc( gc->irc, gc ); +	query_del_by_conn( ic->irc, ic );  	for( a = irc->accounts; a; a = a->next ) -		if( a->gc == gc ) +		if( a->ic == ic )  			break;  	if( !a )  	{  		/* Uhm... This is very sick. */  	} -	else if( !gc->wants_to_die && set_getint( irc, "auto_reconnect" ) ) +	else if( allow_reconnect && set_getbool( &irc->set, "auto_reconnect" ) && +	         set_getbool( &a->set, "auto_reconnect" ) )  	{ -		int delay = set_getint( irc, "auto_reconnect_delay" ); -		serv_got_crap( gc, "Reconnecting in %d seconds..", delay ); +		int delay = set_getint( &irc->set, "auto_reconnect_delay" ); -		a->reconnect = 1; -		g_timeout_add( delay * 1000, auto_reconnect, a ); +		imcb_log( ic, "Reconnecting in %d seconds..", delay ); +		a->reconnect = b_timeout_add( delay * 1000, auto_reconnect, a );  	} -	destroy_gaim_conn( gc ); +	imc_free( ic );  }  /* dialogs.c */ -void do_error_dialog( struct gaim_connection *gc, char *msg, char *title ) +void imcb_ask( struct im_connection *ic, char *msg, void *data, void *doit, void *dont )  { -	if( msg && title ) -		serv_got_crap( gc, "Error: %s: %s", title, msg ); -	else if( msg ) -		serv_got_crap( gc, "Error: %s", msg ); -	else if( title ) -		serv_got_crap( gc, "Error: %s", title ); -	else -		serv_got_crap( gc, "Error" ); -} - -void do_ask_dialog( struct gaim_connection *gc, char *msg, void *data, void *doit, void *dont ) -{ -	query_add( gc->irc, gc, msg, doit, dont, data ); +	query_add( ic->irc, ic, msg, doit, dont, data );  }  /* list.c */ -void add_buddy( struct gaim_connection *gc, char *group, char *handle, char *realname ) +void imcb_add_buddy( struct im_connection *ic, char *handle, char *group )  {  	user_t *u; -	char nick[MAX_NICK_LENGTH+1]; -	char *s; -	irc_t *irc = gc->irc; -	 -	if( set_getint( irc, "debug" ) && 0 ) /* This message is too useless */ -		serv_got_crap( gc, "Receiving user add from handle: %s", handle ); +	char nick[MAX_NICK_LENGTH+1], *s; +	irc_t *irc = ic->irc; -	if( user_findhandle( gc, handle ) ) +	if( user_findhandle( ic, handle ) )  	{ -		if( set_getint( irc, "debug" ) ) -			serv_got_crap( gc, "User already exists, ignoring add request: %s", handle ); +		if( set_getbool( &irc->set, "debug" ) ) +			imcb_log( ic, "User already exists, ignoring add request: %s", handle );  		return; -		/* Buddy seems to exist already. Let's ignore this request then... */ +		/* Buddy seems to exist already. Let's ignore this request then... +		   Eventually subsequent calls to this function *should* be possible +		   when a buddy is in multiple groups. But for now BitlBee doesn't +		   even support groups so let's silently ignore this for now. */  	}  	memset( nick, 0, MAX_NICK_LENGTH + 1 ); -	strcpy( nick, nick_get( gc->irc, handle, gc->prpl, realname ) ); +	strcpy( nick, nick_get( ic->acc, handle ) ); -	u = user_add( gc->irc, nick ); +	u = user_add( ic->irc, nick ); -	if( !realname || !*realname ) realname = nick; -	u->realname = g_strdup( realname ); +//	if( !realname || !*realname ) realname = nick; +//	u->realname = g_strdup( realname );  	if( ( s = strchr( handle, '@' ) ) )  	{  		u->host = g_strdup( s + 1 );  		u->user = g_strndup( handle, s - handle );  	} -	else if( gc->user->proto_opt[0] && *gc->user->proto_opt[0] ) +	else if( ic->acc->server )  	{ -		char *colon; -		 -		if( ( colon = strchr( gc->user->proto_opt[0], ':' ) ) ) -			u->host = g_strndup( gc->user->proto_opt[0], -			                     colon - gc->user->proto_opt[0] ); -		else -			u->host = g_strdup( gc->user->proto_opt[0] ); -		 +		u->host = g_strdup( ic->acc->server );  		u->user = g_strdup( handle );  		/* s/ /_/ ... important for AOL screennames */ @@ -409,47 +394,41 @@ void add_buddy( struct gaim_connection *gc, char *group, char *handle, char *rea  	}  	else  	{ -		u->host = g_strdup( gc->user->prpl->name ); +		u->host = g_strdup( ic->acc->prpl->name );  		u->user = g_strdup( handle );  	} -	u->gc = gc; +	u->ic = ic;  	u->handle = g_strdup( handle );  	if( group ) u->group = g_strdup( group );  	u->send_handler = buddy_send_handler;  	u->last_typing_notice = 0;  } -struct buddy *find_buddy( struct gaim_connection *gc, char *handle ) +struct buddy *imcb_find_buddy( struct im_connection *ic, char *handle )  {  	static struct buddy b[1];  	user_t *u; -	u = user_findhandle( gc, handle ); +	u = user_findhandle( ic, handle );  	if( !u )  		return( NULL ); - +	  	memset( b, 0, sizeof( b ) );  	strncpy( b->name, handle, 80 );  	strncpy( b->show, u->realname, BUDDY_ALIAS_MAXLEN );  	b->present = u->online; -	b->gc = u->gc; +	b->ic = u->ic;  	return( b );  } -void signoff_blocked( struct gaim_connection *gc ) +void imcb_rename_buddy( struct im_connection *ic, char *handle, char *realname )  { -	return; /* Make all blocked users look invisible (TODO?) */ -} - - -void serv_buddy_rename( struct gaim_connection *gc, char *handle, char *realname ) -{ -	user_t *u = user_findhandle( gc, handle ); +	user_t *u = user_findhandle( ic, handle ); -	if( !u ) return; +	if( !u || !realname ) return;  	if( g_strcasecmp( u->realname, realname ) != 0 )  	{ @@ -457,17 +436,61 @@ void serv_buddy_rename( struct gaim_connection *gc, char *handle, char *realname  		u->realname = g_strdup( realname ); -		if( ( gc->flags & OPT_LOGGED_IN ) && set_getint( gc->irc, "display_namechanges" ) ) -			serv_got_crap( gc, "User `%s' changed name to `%s'", u->nick, u->realname ); +		if( ( ic->flags & OPT_LOGGED_IN ) && set_getbool( &ic->irc->set, "display_namechanges" ) ) +			imcb_log( ic, "User `%s' changed name to `%s'", u->nick, u->realname );  	}  } +void imcb_remove_buddy( struct im_connection *ic, char *handle, char *group ) +{ +	user_t *u; +	 +	if( ( u = user_findhandle( ic, handle ) ) ) +		user_del( ic->irc, u->nick ); +} + +/* Mainly meant for ICQ (and now also for Jabber conferences) to allow IM +   modules to suggest a nickname for a handle. */ +void imcb_buddy_nick_hint( struct im_connection *ic, char *handle, char *nick ) +{ +	user_t *u = user_findhandle( ic, handle ); +	char newnick[MAX_NICK_LENGTH+1], *orig_nick; +	 +	if( u && !u->online && !nick_saved( ic->acc, handle ) ) +	{ +		/* Only do this if the person isn't online yet (which should +		   be the case if we just added it) and if the user hasn't +		   assigned a nickname to this buddy already. */ +		 +		strncpy( newnick, nick, MAX_NICK_LENGTH ); +		newnick[MAX_NICK_LENGTH] = 0; +		 +		/* Some processing to make sure this string is a valid IRC nickname. */ +		nick_strip( newnick ); +		if( set_getbool( &ic->irc->set, "lcnicks" ) ) +			nick_lc( newnick ); +		 +		if( strcmp( u->nick, newnick ) != 0 ) +		{ +			/* Only do this if newnick is different from the current one. +			   If rejoining a channel, maybe we got this nick already +			   (and dedupe would only add an underscore. */ +			nick_dedupe( ic->acc, handle, newnick ); +			 +			/* u->nick will be freed halfway the process, so it can't be +			   passed as an argument. */ +			orig_nick = g_strdup( u->nick ); +			user_rename( ic->irc, orig_nick, newnick ); +			g_free( orig_nick ); +		} +	} +}  /* prpl.c */  struct show_got_added_data  { -	struct gaim_connection *gc; +	struct im_connection *ic;  	char *handle;  }; @@ -479,57 +502,56 @@ void show_got_added_no( gpointer w, struct show_got_added_data *data )  void show_got_added_yes( gpointer w, struct show_got_added_data *data )  { -	data->gc->prpl->add_buddy( data->gc, data->handle ); -	add_buddy( data->gc, NULL, data->handle, data->handle ); +	data->ic->acc->prpl->add_buddy( data->ic, data->handle, NULL ); +	/* imcb_add_buddy( data->ic, NULL, data->handle, data->handle ); */  	return show_got_added_no( w, data );  } -void show_got_added( struct gaim_connection *gc, char *handle, const char *realname ) +void imcb_ask_add( struct im_connection *ic, char *handle, const char *realname )  {  	struct show_got_added_data *data = g_new0( struct show_got_added_data, 1 );  	char *s;  	/* TODO: Make a setting for this! */ -	if( user_findhandle( gc, handle ) != NULL ) +	if( user_findhandle( ic, handle ) != NULL )  		return;  	s = g_strdup_printf( "The user %s is not in your buddy list yet. Do you want to add him/her now?", handle ); -	data->gc = gc; +	data->ic = ic;  	data->handle = g_strdup( handle ); -	query_add( gc->irc, gc, s, show_got_added_yes, show_got_added_no, data ); +	query_add( ic->irc, ic, s, show_got_added_yes, show_got_added_no, data );  }  /* server.c */                     -void serv_got_update( struct gaim_connection *gc, char *handle, int loggedin, int evil, time_t signon, time_t idle, int type, guint caps ) +void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, const char *state, const char *message )  {  	user_t *u;  	int oa, oo; -	u = user_findhandle( gc, handle ); +	u = user_findhandle( ic, (char*) handle );  	if( !u )  	{ -		if( g_strcasecmp( set_getstr( gc->irc, "handle_unknown" ), "add" ) == 0 ) +		if( g_strcasecmp( set_getstr( &ic->irc->set, "handle_unknown" ), "add" ) == 0 )  		{ -			add_buddy( gc, NULL, handle, NULL ); -			u = user_findhandle( gc, handle ); +			imcb_add_buddy( ic, (char*) handle, NULL ); +			u = user_findhandle( ic, (char*) handle );  		}  		else  		{ -			if( set_getint( gc->irc, "debug" ) || g_strcasecmp( set_getstr( gc->irc, "handle_unknown" ), "ignore" ) != 0 ) +			if( set_getbool( &ic->irc->set, "debug" ) || g_strcasecmp( set_getstr( &ic->irc->set, "handle_unknown" ), "ignore" ) != 0 )  			{ -				serv_got_crap( gc, "serv_got_update() for handle %s:", handle ); -				serv_got_crap( gc, "loggedin = %d, type = %d", loggedin, type ); +				imcb_log( ic, "imcb_buddy_status() for unknown handle %s:", handle ); +				imcb_log( ic, "flags = %d, state = %s, message = %s", flags, +				          state ? state : "NULL", message ? message : "NULL" );  			}  			return;  		} -		/* Why did we have this here.... -		return; */  	}  	oa = u->away != NULL; @@ -541,75 +563,89 @@ void serv_got_update( struct gaim_connection *gc, char *handle, int loggedin, in  		u->away = NULL;  	} -	if( loggedin && !u->online ) +	if( ( flags & OPT_LOGGED_IN ) && !u->online )  	{ -		irc_spawn( gc->irc, u ); +		irc_spawn( ic->irc, u );  		u->online = 1;  	} -	else if( !loggedin && u->online ) +	else if( !( flags & OPT_LOGGED_IN ) && u->online )  	{ -		struct conversation *c; +		struct groupchat *c; -		irc_kill( gc->irc, u ); +		irc_kill( ic->irc, u );  		u->online = 0; -		/* Remove him/her from the conversations to prevent PART messages after he/she QUIT already */ -		for( c = gc->conversations; c; c = c->next ) +		/* Remove him/her from the groupchats to prevent PART messages after he/she QUIT already */ +		for( c = ic->groupchats; c; c = c->next )  			remove_chat_buddy_silent( c, handle );  	} -	if( ( type & UC_UNAVAILABLE ) && ( !strcmp(gc->prpl->name, "oscar") || !strcmp(gc->prpl->name, "icq")) ) -	{ -		u->away = g_strdup( "Away" ); -	} -	else if( ( type & UC_UNAVAILABLE ) && ( !strcmp(gc->prpl->name, "jabber") ) ) +	if( flags & OPT_AWAY )  	{ -		if( type & UC_DND ) -			u->away = g_strdup( "Do Not Disturb" ); -		else if( type & UC_XA ) -			u->away = g_strdup( "Extended Away" ); -		else // if( type & UC_AWAY ) +		if( state && message ) +		{ +			u->away = g_strdup_printf( "%s (%s)", state, message ); +		} +		else if( state ) +		{ +			u->away = g_strdup( state ); +		} +		else if( message ) +		{ +			u->away = g_strdup( message ); +		} +		else +		{  			u->away = g_strdup( "Away" ); +		}  	} -	else if( ( type & UC_UNAVAILABLE ) && gc->prpl->get_status_string ) -	{ -		u->away = g_strdup( gc->prpl->get_status_string( gc, type ) ); -	} -	else -		u->away = NULL; +	/* else waste_any_state_information_for_now(); */  	/* LISPy... */ -	if( ( set_getint( gc->irc, "away_devoice" ) ) &&		/* Don't do a thing when user doesn't want it */ +	if( ( set_getbool( &ic->irc->set, "away_devoice" ) ) &&		/* Don't do a thing when user doesn't want it */  	    ( u->online ) &&						/* Don't touch offline people */  	    ( ( ( u->online != oo ) && !u->away ) ||			/* Voice joining people */  	      ( ( u->online == oo ) && ( oa == !u->away ) ) ) )		/* (De)voice people changing state */  	{ -		irc_write( gc->irc, ":%s!%s@%s MODE %s %cv %s", gc->irc->mynick, gc->irc->mynick, gc->irc->myhost, -		                                                gc->irc->channel, u->away?'-':'+', u->nick ); +		char *from; +		 +		if( set_getbool( &ic->irc->set, "simulate_netsplit" ) ) +		{ +			from = g_strdup( ic->irc->myhost ); +		} +		else +		{ +			from = g_strdup_printf( "%s!%s@%s", ic->irc->mynick, ic->irc->mynick, +			                                    ic->irc->myhost ); +		} +		irc_write( ic->irc, ":%s MODE %s %cv %s", from, ic->irc->channel, +		                                          u->away?'-':'+', u->nick ); +		g_free( from );  	}  } -void serv_got_im( struct gaim_connection *gc, char *handle, char *msg, guint32 flags, time_t mtime, gint len ) +void imcb_buddy_msg( struct im_connection *ic, char *handle, char *msg, uint32_t flags, time_t sent_at )  { -	irc_t *irc = gc->irc; +	irc_t *irc = ic->irc; +	char *wrapped;  	user_t *u; -	u = user_findhandle( gc, handle ); +	u = user_findhandle( ic, handle );  	if( !u )  	{ -		char *h = set_getstr( irc, "handle_unknown" ); +		char *h = set_getstr( &irc->set, "handle_unknown" );  		if( g_strcasecmp( h, "ignore" ) == 0 )  		{ -			if( set_getint( irc, "debug" ) ) -				serv_got_crap( gc, "Ignoring message from unknown handle %s", handle ); +			if( set_getbool( &irc->set, "debug" ) ) +				imcb_log( ic, "Ignoring message from unknown handle %s", handle );  			return;  		}  		else if( g_strncasecmp( h, "add", 3 ) == 0 )  		{ -			int private = set_getint( irc, "private" ); +			int private = set_getbool( &irc->set, "private" );  			if( h[3] )  			{ @@ -619,84 +655,75 @@ void serv_got_im( struct gaim_connection *gc, char *handle, char *msg, guint32 f  					private = 0;  			} -			add_buddy( gc, NULL, handle, NULL ); -			u = user_findhandle( gc, handle ); +			imcb_add_buddy( ic, handle, NULL ); +			u = user_findhandle( ic, handle );  			u->is_private = private;  		}  		else  		{ -			serv_got_crap( gc, "Message from unknown handle %s:", handle ); +			imcb_log( ic, "Message from unknown handle %s:", handle );  			u = user_find( irc, irc->mynick );  		}  	} -	if( ( g_strcasecmp( set_getstr( gc->irc, "strip_html" ), "always" ) == 0 ) || -	    ( ( gc->flags & OPT_CONN_HTML ) && set_getint( gc->irc, "strip_html" ) ) ) +	if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) || +	    ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )  		strip_html( msg ); -	while( strlen( msg ) > 425 ) +	wrapped = word_wrap( msg, 425 ); +	irc_msgfrom( irc, u->nick, wrapped ); +	g_free( wrapped ); +} + +void imcb_buddy_typing( struct im_connection *ic, char *handle, uint32_t flags ) +{ +	user_t *u; +	 +	if( !set_getbool( &ic->irc->set, "typing_notice" ) ) +		return; +	 +	if( ( u = user_findhandle( ic, handle ) ) )  	{ -		char tmp, *nl; -		 -		tmp = msg[425]; -		msg[425] = 0; -		 -		/* If there's a newline/space in this string, split up there, -		   looks a bit prettier. */ -		if( ( nl = strrchr( msg, '\n' ) ) || ( nl = strrchr( msg, ' ' ) ) ) -		{ -			msg[425] = tmp; -			tmp = *nl; -			*nl = 0; -		} +		char buf[256];  -		irc_msgfrom( irc, u->nick, msg ); -		 -		/* Move on. */ -		if( nl ) -		{ -			*nl = tmp; -			msg = nl + 1; -		} -		else -		{ -			msg[425] = tmp; -			msg += 425; -		} +		g_snprintf( buf, 256, "\1TYPING %d\1", ( flags >> 8 ) & 3 ); +		irc_privmsg( ic->irc, u, "PRIVMSG", ic->irc->nick, NULL, buf );  	} -	irc_msgfrom( irc, u->nick, msg );  } -void serv_got_typing( struct gaim_connection *gc, char *handle, int timeout, int type ) +struct groupchat *imcb_chat_new( struct im_connection *ic, char *handle )  { -	user_t *u; +	struct groupchat *c; -	if( !set_getint( gc->irc, "typing_notice" ) ) -		return; +	/* This one just creates the conversation structure, user won't see anything yet */ -	if( ( u = user_findhandle( gc, handle ) ) ) { -		/* If type is: -		 * 0: user has stopped typing -		 * 1: user is actively typing -		 * 2: user has entered text, but is not actively typing -		 */ -		if (type == 0 || type == 1 || type == 2) { -			char buf[256];  -			g_snprintf(buf, 256, "\1TYPING %d\1", type);  -			irc_privmsg( gc->irc, u, "PRIVMSG", gc->irc->nick, NULL, buf ); -		} +	if( ic->groupchats ) +	{ +		for( c = ic->groupchats; c->next; c = c->next ); +		c = c->next = g_new0( struct groupchat, 1 );  	} +	else +		ic->groupchats = c = g_new0( struct groupchat, 1 ); +	 +	c->ic = ic; +	c->title = g_strdup( handle ); +	c->channel = g_strdup_printf( "&chat_%03d", ic->irc->c_id++ ); +	c->topic = g_strdup_printf( "BitlBee groupchat: \"%s\". Please keep in mind that root-commands won't work here. Have fun!", c->title ); +	 +	if( set_getbool( &ic->irc->set, "debug" ) ) +		imcb_log( ic, "Creating new conversation: (id=%p,handle=%s)", c, handle ); +	 +	return c;  } -void serv_got_chat_left( struct gaim_connection *gc, int id ) +void imcb_chat_free( struct groupchat *c )  { -	struct conversation *c, *l = NULL; +	struct im_connection *ic = c->ic; +	struct groupchat *l;  	GList *ir; -	if( set_getint( gc->irc, "debug" ) ) -		serv_got_crap( gc, "You were removed from conversation %d", (int) id ); -	 -	for( c = gc->conversations; c && c->id != id; c = (l=c)->next ); +	if( set_getbool( &ic->irc->set, "debug" ) ) +		imcb_log( ic, "You were removed from conversation %p", c );  	if( c )  	{ @@ -704,97 +731,118 @@ void serv_got_chat_left( struct gaim_connection *gc, int id )  		{  			user_t *u, *r; -			r = user_find( gc->irc, gc->irc->mynick ); -			irc_privmsg( gc->irc, r, "PRIVMSG", c->channel, "", "Cleaning up channel, bye!" ); +			r = user_find( ic->irc, ic->irc->mynick ); +			irc_privmsg( ic->irc, r, "PRIVMSG", c->channel, "", "Cleaning up channel, bye!" ); -			u = user_find( gc->irc, gc->irc->nick ); -			irc_kick( gc->irc, u, c->channel, r ); -			/* irc_part( gc->irc, u, c->channel ); */ +			u = user_find( ic->irc, ic->irc->nick ); +			irc_kick( ic->irc, u, c->channel, r ); +			/* irc_part( ic->irc, u, c->channel ); */  		} +		/* Find the previous chat in the linked list. */ +		for( l = ic->groupchats; l && l->next != c; l = l->next ); +		  		if( l )  			l->next = c->next;  		else -			gc->conversations = c->next; +			ic->groupchats = c->next;  		for( ir = c->in_room; ir; ir = ir->next )  			g_free( ir->data );  		g_list_free( c->in_room );  		g_free( c->channel );  		g_free( c->title ); +		g_free( c->topic );  		g_free( c );  	}  } -void serv_got_chat_in( struct gaim_connection *gc, int id, char *who, int whisper, char *msg, time_t mtime ) +void imcb_chat_msg( struct groupchat *c, char *who, char *msg, uint32_t flags, time_t sent_at )  { -	struct conversation *c; +	struct im_connection *ic = c->ic; +	char *wrapped;  	user_t *u;  	/* Gaim sends own messages through this too. IRC doesn't want this, so kill them */ -	if( g_strcasecmp( who, gc->user->username ) == 0 ) +	if( g_strcasecmp( who, ic->acc->user ) == 0 )  		return; -	u = user_findhandle( gc, who ); -	for( c = gc->conversations; c && c->id != id; c = c->next ); +	u = user_findhandle( ic, who ); -	if( ( g_strcasecmp( set_getstr( gc->irc, "strip_html" ), "always" ) == 0 ) || -	    ( ( gc->flags & OPT_CONN_HTML ) && set_getint( gc->irc, "strip_html" ) ) ) +	if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) || +	    ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )  		strip_html( msg ); +	wrapped = word_wrap( msg, 425 );  	if( c && u ) -		irc_privmsg( gc->irc, u, "PRIVMSG", c->channel, "", msg ); +	{ +		irc_privmsg( ic->irc, u, "PRIVMSG", c->channel, "", wrapped ); +	}  	else -		serv_got_crap( gc, "Message from/to conversation %s@%d (unknown conv/user): %s", who, id, msg ); +	{ +		imcb_log( ic, "Message from/to conversation %s@%p (unknown conv/user): %s", who, c, wrapped ); +	} +	g_free( wrapped );  } -struct conversation *serv_got_joined_chat( struct gaim_connection *gc, int id, char *handle ) +void imcb_chat_log( struct groupchat *c, char *format, ... )  { -	struct conversation *c; -	char *s; +	irc_t *irc = c->ic->irc; +	va_list params; +	char *text; +	user_t *u; -	/* This one just creates the conversation structure, user won't see anything yet */ +	va_start( params, format ); +	text = g_strdup_vprintf( format, params ); +	va_end( params ); -	if( gc->conversations ) -	{ -		for( c = gc->conversations; c->next; c = c->next ); -		c = c->next = g_new0( struct conversation, 1 ); -	} -	else -		gc->conversations = c = g_new0( struct conversation, 1); +	u = user_find( irc, irc->mynick ); -	c->id = id; -	c->gc = gc; -	c->title = g_strdup( handle ); +	irc_privmsg( irc, u, "PRIVMSG", c->channel, "System message: ", text ); -	s = g_new( char, 16 ); -	sprintf( s, "&chat_%03d", gc->irc->c_id++ ); -	c->channel = g_strdup( s ); -	g_free( s ); +	g_free( text ); +} + +void imcb_chat_topic( struct groupchat *c, char *who, char *topic, time_t set_at ) +{ +	struct im_connection *ic = c->ic; +	user_t *u = NULL; -	if( set_getint( gc->irc, "debug" ) ) -		serv_got_crap( gc, "Creating new conversation: (id=%d,handle=%s)", id, handle ); +	if( who == NULL) +		u = user_find( ic->irc, ic->irc->mynick ); +	else if( g_strcasecmp( who, ic->acc->user ) == 0 ) +		u = user_find( ic->irc, ic->irc->nick ); +	else +		u = user_findhandle( ic, who ); -	return( c ); +	if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) || +	    ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) ) +		strip_html( topic ); +	 +	g_free( c->topic ); +	c->topic = g_strdup( topic ); +	 +	if( c->joined && u ) +		irc_write( ic->irc, ":%s!%s@%s TOPIC %s :%s", u->nick, u->user, u->host, c->channel, topic );  }  /* buddy_chat.c */ -void add_chat_buddy( struct conversation *b, char *handle ) +void imcb_chat_add_buddy( struct groupchat *b, char *handle )  { -	user_t *u = user_findhandle( b->gc, handle ); +	user_t *u = user_findhandle( b->ic, handle );  	int me = 0; -	if( set_getint( b->gc->irc, "debug" ) ) -		serv_got_crap( b->gc, "User %s added to conversation %d", handle, b->id ); +	if( set_getbool( &b->ic->irc->set, "debug" ) ) +		imcb_log( b->ic, "User %s added to conversation %p", handle, b );  	/* It might be yourself! */ -	if( b->gc->prpl->cmp_buddynames( handle, b->gc->user->username ) == 0 ) +	if( b->ic->acc->prpl->handle_cmp( handle, b->ic->acc->user ) == 0 )  	{ -		u = user_find( b->gc->irc, b->gc->irc->nick ); +		u = user_find( b->ic->irc, b->ic->irc->nick );  		if( !b->joined ) -			irc_join( b->gc->irc, u, b->channel ); +			irc_join( b->ic->irc, u, b->channel );  		b->joined = me = 1;  	} @@ -802,45 +850,48 @@ void add_chat_buddy( struct conversation *b, char *handle )  	   your contact list. Try to handle that here */  	if( !u )  	{ -		add_buddy( b->gc, NULL, handle, NULL ); -		u = user_findhandle( b->gc, handle ); +		imcb_add_buddy( b->ic, handle, NULL ); +		u = user_findhandle( b->ic, handle );  	}  	/* Add the handle to the room userlist, if it's not 'me' */  	if( !me )  	{  		if( b->joined ) -			irc_join( b->gc->irc, u, b->channel ); +			irc_join( b->ic->irc, u, b->channel );  		b->in_room = g_list_append( b->in_room, g_strdup( handle ) );  	}  } -void remove_chat_buddy( struct conversation *b, char *handle, char *reason ) +/* This function is one BIG hack... :-( EREWRITE */ +void imcb_chat_remove_buddy( struct groupchat *b, char *handle, char *reason )  {  	user_t *u;  	int me = 0; -	if( set_getint( b->gc->irc, "debug" ) ) -		serv_got_crap( b->gc, "User %s removed from conversation %d (%s)", handle, b->id, reason ? reason : "" ); +	if( set_getbool( &b->ic->irc->set, "debug" ) ) +		imcb_log( b->ic, "User %s removed from conversation %p (%s)", handle, b, reason ? reason : "" );  	/* It might be yourself! */ -	if( g_strcasecmp( handle, b->gc->user->username ) == 0 ) +	if( g_strcasecmp( handle, b->ic->acc->user ) == 0 )  	{ -		u = user_find( b->gc->irc, b->gc->irc->nick ); +		if( b->joined == 0 ) +			return; +		 +		u = user_find( b->ic->irc, b->ic->irc->nick );  		b->joined = 0;  		me = 1;  	}  	else  	{ -		u = user_findhandle( b->gc, handle ); +		u = user_findhandle( b->ic, handle );  	} -	if( remove_chat_buddy_silent( b, handle ) ) -		if( ( b->joined || me ) && u ) -			irc_part( b->gc->irc, u, b->channel ); +	if( me || ( remove_chat_buddy_silent( b, handle ) && b->joined && u ) ) +		irc_part( b->ic->irc, u, b->channel );  } -static int remove_chat_buddy_silent( struct conversation *b, char *handle ) +static int remove_chat_buddy_silent( struct groupchat *b, const char *handle )  {  	GList *i; @@ -864,26 +915,9 @@ static int remove_chat_buddy_silent( struct conversation *b, char *handle )  /* Misc. BitlBee stuff which shouldn't really be here */ -struct conversation *conv_findchannel( char *channel ) -{ -	struct gaim_connection *gc; -	struct conversation *c; -	GSList *l; -	 -	/* This finds the connection which has a conversation which belongs to this channel */ -	for( l = connections; l; l = l->next ) -	{ -		gc = l->data; -		for( c = gc->conversations; c && g_strcasecmp( c->channel, channel ) != 0; c = c->next ); -		if( c ) -			return( c ); -	} -	 -	return( NULL ); -} - -char *set_eval_away_devoice( irc_t *irc, set_t *set, char *value ) +char *set_eval_away_devoice( set_t *set, char *value )  { +	irc_t *irc = set->data;  	int st;  	if( ( g_strcasecmp( value, "true" ) == 0 ) || ( g_strcasecmp( value, "yes" ) == 0 ) || ( g_strcasecmp( value, "on" ) == 0 ) ) @@ -897,7 +931,7 @@ char *set_eval_away_devoice( irc_t *irc, set_t *set, char *value )  	/* Horror.... */ -	if( st != set_getint( irc, "away_devoice" ) ) +	if( st != set_getbool( &irc->set, "away_devoice" ) )  	{  		char list[80] = "";  		user_t *u = irc->users; @@ -912,13 +946,13 @@ char *set_eval_away_devoice( irc_t *irc, set_t *set, char *value )  		while( u )  		{ -			if( u->gc && u->online && !u->away ) +			if( u->ic && u->online && !u->away )  			{  				if( ( strlen( list ) + strlen( u->nick ) ) >= 79 )  				{  					for( i = 0; i < count; v[i++] = 'v' ); v[i] = 0; -					irc_write( irc, ":%s!%s@%s MODE %s %c%s%s", -					           irc->mynick, irc->mynick, irc->myhost, +					irc_write( irc, ":%s MODE %s %c%s%s", +					           irc->myhost,  		        			   irc->channel, pm, v, list );  					*list = 0; @@ -933,11 +967,11 @@ char *set_eval_away_devoice( irc_t *irc, set_t *set, char *value )  		/* $v = 'v' x $i */  		for( i = 0; i < count; v[i++] = 'v' ); v[i] = 0; -		irc_write( irc, ":%s!%s@%s MODE %s %c%s%s", irc->mynick, irc->mynick, irc->myhost, +		irc_write( irc, ":%s MODE %s %c%s%s", irc->myhost,  		                                            irc->channel, pm, v, list );  	} -	return( set_eval_bool( irc, set, value ) ); +	return( set_eval_bool( set, value ) );  } @@ -946,49 +980,48 @@ char *set_eval_away_devoice( irc_t *irc, set_t *set, char *value )  /* The plan is to not allow straight calls to prpl functions anymore, but do     them all from some wrappers. We'll start to define some down here: */ -int bim_buddy_msg( struct gaim_connection *gc, char *handle, char *msg, int flags ) +int imc_buddy_msg( struct im_connection *ic, char *handle, char *msg, int flags )  {  	char *buf = NULL;  	int st; -	if( ( gc->flags & OPT_CONN_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) ) +	if( ( ic->flags & OPT_DOES_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) )  	{  		buf = escape_html( msg );  		msg = buf;  	} -	st = gc->prpl->send_im( gc, handle, msg, strlen( msg ), flags ); +	st = ic->acc->prpl->buddy_msg( ic, handle, msg, flags );  	g_free( buf );  	return st;  } -int bim_chat_msg( struct gaim_connection *gc, int id, char *msg ) +int imc_chat_msg( struct groupchat *c, char *msg, int flags )  {  	char *buf = NULL; -	int st; -	if( ( gc->flags & OPT_CONN_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) ) +	if( ( c->ic->flags & OPT_DOES_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) )  	{  		buf = escape_html( msg );  		msg = buf;  	} -	st = gc->prpl->chat_send( gc, id, msg ); +	c->ic->acc->prpl->chat_msg( c, msg, flags );  	g_free( buf ); -	return st; +	return 1;  } -static char *bim_away_alias_find( GList *gcm, char *away ); +static char *imc_away_alias_find( GList *gcm, char *away ); -int bim_set_away( struct gaim_connection *gc, char *away ) +int imc_set_away( struct im_connection *ic, char *away )  {  	GList *m, *ms;  	char *s;  	if( !away ) away = ""; -	ms = m = gc->prpl->away_states( gc ); +	ms = m = ic->acc->prpl->away_states( ic );  	while( m )  	{ @@ -1009,27 +1042,25 @@ int bim_set_away( struct gaim_connection *gc, char *away )  	if( m )  	{ -		gc->prpl->set_away( gc, m->data, *away ? away : NULL ); +		ic->acc->prpl->set_away( ic, m->data, *away ? away : NULL );  	}  	else  	{ -		s = bim_away_alias_find( ms, away ); +		s = imc_away_alias_find( ms, away );  		if( s )  		{ -			gc->prpl->set_away( gc, s, away ); -			if( set_getint( gc->irc, "debug" ) ) -				serv_got_crap( gc, "Setting away state to %s", s ); +			ic->acc->prpl->set_away( ic, s, away ); +			if( set_getbool( &ic->irc->set, "debug" ) ) +				imcb_log( ic, "Setting away state to %s", s );  		}  		else -			gc->prpl->set_away( gc, GAIM_AWAY_CUSTOM, away ); +			ic->acc->prpl->set_away( ic, GAIM_AWAY_CUSTOM, away );  	} -	g_list_free( ms ); -	  	return( 1 );  } -static char *bim_away_alias_list[8][5] = +static char *imc_away_alias_list[8][5] =  {  	{ "Away from computer", "Away", "Extended away", NULL },  	{ "NA", "N/A", "Not available", NULL }, @@ -1041,28 +1072,28 @@ static char *bim_away_alias_list[8][5] =  	{ NULL }  }; -static char *bim_away_alias_find( GList *gcm, char *away ) +static char *imc_away_alias_find( GList *gcm, char *away )  {  	GList *m;  	int i, j; -	for( i = 0; *bim_away_alias_list[i]; i ++ ) +	for( i = 0; *imc_away_alias_list[i]; i ++ )  	{ -		for( j = 0; bim_away_alias_list[i][j]; j ++ ) -			if( g_strncasecmp( away, bim_away_alias_list[i][j], strlen( bim_away_alias_list[i][j] ) ) == 0 ) +		for( j = 0; imc_away_alias_list[i][j]; j ++ ) +			if( g_strncasecmp( away, imc_away_alias_list[i][j], strlen( imc_away_alias_list[i][j] ) ) == 0 )  				break; -		if( !bim_away_alias_list[i][j] )	/* If we reach the end, this row */ +		if( !imc_away_alias_list[i][j] )	/* If we reach the end, this row */  			continue;			/* is not what we want. Next!    */  		/* Now find an entry in this row which exists in gcm */ -		for( j = 0; bim_away_alias_list[i][j]; j ++ ) +		for( j = 0; imc_away_alias_list[i][j]; j ++ )  		{  			m = gcm;  			while( m )  			{ -				if( g_strcasecmp( bim_away_alias_list[i][j], m->data ) == 0 ) -					return( bim_away_alias_list[i][j] ); +				if( g_strcasecmp( imc_away_alias_list[i][j], m->data ) == 0 ) +					return( imc_away_alias_list[i][j] );  				m = m->next;  			}  		} @@ -1071,48 +1102,80 @@ static char *bim_away_alias_find( GList *gcm, char *away )  	return( NULL );  } -void bim_add_allow( struct gaim_connection *gc, char *handle ) +void imc_add_allow( struct im_connection *ic, char *handle )  { -	if( g_slist_find_custom( gc->permit, handle, (GCompareFunc) gc->prpl->cmp_buddynames ) == NULL ) +	if( g_slist_find_custom( ic->permit, handle, (GCompareFunc) ic->acc->prpl->handle_cmp ) == NULL )  	{ -		gc->permit = g_slist_prepend( gc->permit, g_strdup( handle ) ); +		ic->permit = g_slist_prepend( ic->permit, g_strdup( handle ) );  	} -	gc->prpl->add_permit( gc, handle ); +	ic->acc->prpl->add_permit( ic, handle );  } -void bim_rem_allow( struct gaim_connection *gc, char *handle ) +void imc_rem_allow( struct im_connection *ic, char *handle )  {  	GSList *l; -	if( ( l = g_slist_find_custom( gc->permit, handle, (GCompareFunc) gc->prpl->cmp_buddynames ) ) ) +	if( ( l = g_slist_find_custom( ic->permit, handle, (GCompareFunc) ic->acc->prpl->handle_cmp ) ) )  	{  		g_free( l->data ); -		gc->permit = g_slist_delete_link( gc->permit, l ); +		ic->permit = g_slist_delete_link( ic->permit, l );  	} -	gc->prpl->rem_permit( gc, handle ); +	ic->acc->prpl->rem_permit( ic, handle );  } -void bim_add_block( struct gaim_connection *gc, char *handle ) +void imc_add_block( struct im_connection *ic, char *handle )  { -	if( g_slist_find_custom( gc->deny, handle, (GCompareFunc) gc->prpl->cmp_buddynames ) == NULL ) +	if( g_slist_find_custom( ic->deny, handle, (GCompareFunc) ic->acc->prpl->handle_cmp ) == NULL )  	{ -		gc->deny = g_slist_prepend( gc->deny, g_strdup( handle ) ); +		ic->deny = g_slist_prepend( ic->deny, g_strdup( handle ) );  	} -	gc->prpl->add_deny( gc, handle ); +	ic->acc->prpl->add_deny( ic, handle );  } -void bim_rem_block( struct gaim_connection *gc, char *handle ) +void imc_rem_block( struct im_connection *ic, char *handle )  {  	GSList *l; -	if( ( l = g_slist_find_custom( gc->deny, handle, (GCompareFunc) gc->prpl->cmp_buddynames ) ) ) +	if( ( l = g_slist_find_custom( ic->deny, handle, (GCompareFunc) ic->acc->prpl->handle_cmp ) ) )  	{  		g_free( l->data ); -		gc->deny = g_slist_delete_link( gc->deny, l ); +		ic->deny = g_slist_delete_link( ic->deny, l ); +	} +	 +	ic->acc->prpl->rem_deny( ic, handle ); +} + +void imcb_clean_handle( struct im_connection *ic, char *handle ) +{ +	/* Accepts a handle and does whatever is necessary to make it +	   BitlBee-friendly. Currently this means removing everything +	   outside 33-127 (ASCII printable excl spaces), @ (only one +	   is allowed) and ! and : */ +	char out[strlen(handle)+1]; +	int s, d; +	 +	s = d = 0; +	while( handle[s] ) +	{ +		if( handle[s] > ' ' && handle[s] != '!' && handle[s] != ':' && +		    ( handle[s] & 0x80 ) == 0 ) +		{ +			if( handle[s] == '@' ) +			{ +				/* See if we got an @ already? */ +				out[d] = 0; +				if( strchr( out, '@' ) ) +					continue; +			} +			 +			out[d++] = handle[s]; +		} +		s ++;  	} +	out[d] = handle[s]; -	gc->prpl->rem_deny( gc, handle ); +	strcpy( handle, out );  } diff --git a/protocols/nogaim.h b/protocols/nogaim.h index e109beb8..dde0dd2f 100644 --- a/protocols/nogaim.h +++ b/protocols/nogaim.h @@ -5,7 +5,8 @@    \********************************************************************/  /* - * nogaim + * nogaim, soon to be known as im_api. Not a separate product (unless + * someone would be interested in such a thing), just a new name.   *   * Gaim without gaim - for BitlBee   * @@ -14,7 +15,7 @@   *   * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net>   *                          (and possibly other members of the Gaim team) - * Copyright 2002-2004 Wilmer van der Gaast <wilmer@gaast.net> + * Copyright 2002-2007 Wilmer van der Gaast <wilmer@gaast.net>   */  /* @@ -38,30 +39,35 @@  #define _NOGAIM_H  #include "bitlbee.h" +#include "account.h"  #include "proxy.h"  #include "md5.h" -#include "sha.h" -  #define BUF_LEN MSG_LEN  #define BUF_LONG ( BUF_LEN * 2 )  #define MSG_LEN 2048  #define BUF_LEN MSG_LEN -#define SELF_ALIAS_LEN 400  #define BUDDY_ALIAS_MAXLEN 388   /* because MSN names can be 387 characters */  #define WEBSITE "http://www.bitlbee.org/" -#define IM_FLAG_AWAY 0x0020 -#define OPT_CONN_HTML 0x00000001 -#define OPT_LOGGED_IN 0x00010000  #define GAIM_AWAY_CUSTOM "Custom" +/* Sharing flags between all kinds of things. I just hope I won't hit any +   limits before 32-bit machines become extinct. ;-) */ +#define OPT_LOGGED_IN   0x00000001 +#define OPT_LOGGING_OUT 0x00000002 +#define OPT_AWAY        0x00000004 +#define OPT_DOES_HTML   0x00000010 +#define OPT_LOCALBUDDY  0x00000020 /* For nicks local to one groupchat */ +#define OPT_TYPING      0x00000100 /* Some pieces of code make assumptions */ +#define OPT_THINKING    0x00000200 /* about these values... Stupid me! */ +  /* ok. now the fun begins. first we create a connection structure */ -struct gaim_connection +struct im_connection  { -	struct prpl *prpl; -	guint32 flags; +	account_t *acc; +	uint32_t flags;  	/* each connection then can have its own protocol-specific data */  	void *proto_data; @@ -76,66 +82,52 @@ struct gaim_connection  	GSList *deny;  	int permdeny; -	struct aim_user *user; -	 -	char username[64];  	char displayname[128]; -	char password[32]; -	  	char *away;  	int evil; -	gboolean wants_to_die; /* defaults to FALSE */  	/* BitlBee */  	irc_t *irc; -	struct conversation *conversations; +	struct groupchat *groupchats;  }; -/* struct buddy_chat went away and got merged with this. */ -struct conversation { -	struct gaim_connection *gc; +struct groupchat { +	struct im_connection *ic;  	/* stuff used just for chat */ -        GList *in_room; -        GList *ignored; -        int id; -         -        /* BitlBee */ -        struct conversation *next; -        char *channel; -        char *title; -        char joined; -        void *data; +	/* The in_room variable is a list of handles (not nicks!), kind of +	 * "nick list". This is how you can check who is in the group chat +	 * already, for example to avoid adding somebody two times. */ +	GList *in_room; +	GList *ignored; +	 +	struct groupchat *next; +	char *channel; +	/* The title variable contains the ID you gave when you created the +	 * chat using imcb_chat_new(). */ +	char *title; +	/* Use imcb_chat_topic() to change this variable otherwise the user +	 * won't notice the topic change. */ +	char *topic; +	char joined; +	/* This is for you, you can add your own structure here to extend this +	 * structure for your protocol's needs. */ +	void *data;  };  struct buddy {  	char name[80];  	char show[BUDDY_ALIAS_MAXLEN]; -        int present; +	int present;  	int evil;  	time_t signon;  	time_t idle; -        int uc; +	int uc;  	guint caps; /* woohoo! */  	void *proto_data; /* what a hack */ -	struct gaim_connection *gc; /* the connection it belongs to */ -}; - -struct aim_user { -	char username[64]; -	char alias[SELF_ALIAS_LEN];  -	char password[32]; -	char user_info[2048]; -	int options; -	struct prpl *prpl; -	/* prpls can use this to save information about the user, -	 * like which server to connect to, etc */ -	char proto_opt[7][256]; - -	struct gaim_connection *gc; -	irc_t *irc; +	struct im_connection *ic; /* the connection it belongs to */  };  struct ft  @@ -159,111 +151,192 @@ typedef void (*ft_recv_handler) (struct ft *, void *data, size_t len);  struct prpl {  	int options; +	/* You should set this to the name of your protocol. +	 * - The user sees this name ie. when imcb_log() is used. */  	const char *name; -	void (* login)		(struct aim_user *); -	void (* keepalive)	(struct gaim_connection *); -	void (* close)		(struct gaim_connection *); +	/* Added this one to be able to add per-account settings, don't think +	 * it should be used for anything else. You are supposed to use the +	 * set_add() function to add new settings. */ +	void (* init)		(account_t *); +	/* The typical usage of the login() function: +	 * - Create an im_connection using imcb_new() from the account_t parameter. +	 * - Initialize your myproto_data struct - you should store all your protocol-specific data there. +	 * - Save your custom structure to im_connection->proto_data. +	 * - Use proxy_connect() to connect to the server. +	 */ +	void (* login)		(account_t *); +	/* Implementing this function is optional. */ +	void (* keepalive)	(struct im_connection *); +	/* In this function you should: +	 * - Tell the server about you are logging out. +	 * - g_free() your myproto_data struct as BitlBee does not know how to +	 *   properly do so. +	 */ +	void (* logout)		(struct im_connection *); -	int  (* send_im)	(struct gaim_connection *, char *who, char *message, int len, int away); -	void (* set_away)	(struct gaim_connection *, char *state, char *message); -	void (* get_away)       (struct gaim_connection *, char *who); -	int  (* send_typing)	(struct gaim_connection *, char *who, int typing); +	/* This function is called when the user wants to send a message to a handle. +	 * - 'to' is a handle, not a nick +	 * - 'flags' may be ignored +	 */ +	int  (* buddy_msg)	(struct im_connection *, char *to, char *message, int flags); +	/* This function is called then the user uses the /away IRC command. +	 * - 'state' contains the away reason. +	 * - 'message' may be ignored if your protocol does not support it. +	 */ +	void (* set_away)	(struct im_connection *, char *state, char *message); +	/* Implementing this function is optional. */ +	void (* get_away)       (struct im_connection *, char *who); +	/* Implementing this function is optional. */ +	int  (* send_typing)	(struct im_connection *, char *who, int flags); -	void (* add_buddy)	(struct gaim_connection *, char *name); -	void (* group_buddy)	(struct gaim_connection *, char *who, char *old_group, char *new_group); -	void (* remove_buddy)	(struct gaim_connection *, char *name, char *group); -	void (* add_permit)	(struct gaim_connection *, char *name); -	void (* add_deny)	(struct gaim_connection *, char *name); -	void (* rem_permit)	(struct gaim_connection *, char *name); -	void (* rem_deny)	(struct gaim_connection *, char *name); -	void (* set_permit_deny)(struct gaim_connection *); +	/* 'name' is a handle to add/remove. For now BitlBee doesn't really +	 * handle groups, just set it to NULL, so you can ignore that +	 * parameter. */ +	void (* add_buddy)	(struct im_connection *, char *name, char *group); +	void (* remove_buddy)	(struct im_connection *, char *name, char *group); -	void (* set_info)	(struct gaim_connection *, char *info); -	void (* get_info)	(struct gaim_connection *, char *who); -	void (* alias_buddy)	(struct gaim_connection *, char *who);	/* save/store buddy's alias on server list/roster */ +	/* Block list stuff. Implementing these are optional. */ +	void (* add_permit)	(struct im_connection *, char *who); +	void (* add_deny)	(struct im_connection *, char *who); +	void (* rem_permit)	(struct im_connection *, char *who); +	void (* rem_deny)	(struct im_connection *, char *who); +	/* Doesn't actually have UI hooks. */ +	void (* set_permit_deny)(struct im_connection *); -	/* Group chat stuff. */ -	void (* join_chat)	(struct gaim_connection *, GList *data); -	void (* chat_invite)	(struct gaim_connection *, int id, char *who, char *message); -	void (* chat_leave)	(struct gaim_connection *, int id); -	int  (* chat_send)	(struct gaim_connection *, int id, char *message); -	int  (* chat_open)	(struct gaim_connection *, char *who); +	/* Request profile info. Free-formatted stuff, the IM module gives back +	   this info via imcb_log(). Implementing these are optional. */ +	void (* get_info)	(struct im_connection *, char *who); +	void (* set_my_name)	(struct im_connection *, char *name); +	void (* set_name)	(struct im_connection *, char *who, char *name); -	/* DIE! */ -	char *(* get_status_string) (struct gaim_connection *gc, int stat); +	/* Group chat stuff. */ +	/* This is called when the user uses the /invite IRC command. +	 * - 'who' may be ignored +	 * - 'message' is a handle to invite +	 */ +	void (* chat_invite)	(struct groupchat *, char *who, char *message); +	/* This is called when the user uses the /part IRC command in a group +	 * chat. You just should tell the user about it, nothing more. */ +	void (* chat_leave)	(struct groupchat *); +	/* This is called when the user sends a message to the groupchat. +	 * 'flags' may be ignored. */ +	void (* chat_msg)	(struct groupchat *, char *message, int flags); +	/* This is called when the user uses the /join #nick IRC command. +	 * - 'who' is the handle of the nick +	 */ +	struct groupchat * +	     (* chat_with)	(struct im_connection *, char *who); +	/* This is used when the user uses the /join #channel IRC command.  If +	 * your protocol does not support publicly named group chats, then do +	 * not implement this. */ +	struct groupchat * +	     (* chat_join)	(struct im_connection *, char *room, char *nick, char *password); +	/* Change the topic, if supported. Note that BitlBee expects the IM +	   server to confirm the topic change with a regular topic change +	   event. If it doesn't do that, you have to fake it to make it +	   visible to the user. */ +	void (* chat_topic)	(struct groupchat *, char *topic); -	GList *(* away_states)(struct gaim_connection *gc); +	/* You can tell what away states your protocol supports, so that +	 * BitlBee will try to map the IRC away reasons to them, or use +	 * GAIM_AWAY_CUSTOM when calling skype_set_away(). */ +	GList *(* away_states)(struct im_connection *ic); -	/* Mainly for AOL, since they think "Bung hole" == "Bu ngho le". *sigh* */ -	int (* cmp_buddynames) (const char *who1, const char *who2); +	/* Mainly for AOL, since they think "Bung hole" == "Bu ngho le". *sigh* +	 * - Most protocols will just want to set this to g_strcasecmp().*/ +	int (* handle_cmp) (const char *who1, const char *who2);  }; -#define UC_UNAVAILABLE  1 - -/* JABBER */ -#define UC_AWAY (0x02 | UC_UNAVAILABLE) -#define UC_CHAT  0x04 -#define UC_XA   (0x08 | UC_UNAVAILABLE) -#define UC_DND  (0x10 | UC_UNAVAILABLE) - -G_MODULE_EXPORT GSList *get_connections(); -G_MODULE_EXPORT struct prpl *find_protocol(const char *name); -G_MODULE_EXPORT void register_protocol(struct prpl *); - -/* nogaim.c */ -int bim_set_away( struct gaim_connection *gc, char *away ); -int bim_buddy_msg( struct gaim_connection *gc, char *handle, char *msg, int flags ); -int bim_chat_msg( struct gaim_connection *gc, int id, char *msg ); - -void bim_add_allow( struct gaim_connection *gc, char *handle ); -void bim_rem_allow( struct gaim_connection *gc, char *handle ); -void bim_add_block( struct gaim_connection *gc, char *handle ); -void bim_rem_block( struct gaim_connection *gc, char *handle ); - +/* im_api core stuff. */  void nogaim_init(); -char *set_eval_away_devoice( irc_t *irc, set_t *set, char *value ); - -gboolean auto_reconnect( gpointer data ); +G_MODULE_EXPORT GSList *get_connections(); +G_MODULE_EXPORT struct prpl *find_protocol( const char *name ); +/* When registering a new protocol, you should allocate space for a new prpl + * struct, initialize it (set the function pointers to point to your + * functions), finally call this function. */ +G_MODULE_EXPORT void register_protocol( struct prpl * ); + +/* Connection management. */ +/* You will need this function in prpl->login() to get an im_connection from + * the account_t parameter. */ +G_MODULE_EXPORT struct im_connection *imcb_new( account_t *acc ); +G_MODULE_EXPORT void imcb_free( struct im_connection *ic ); +/* Once you're connected, you should call this function, so that the user will + * see the success. */ +G_MODULE_EXPORT void imcb_connected( struct im_connection *ic ); +/* This can be used to disconnect when something went wrong (ie. read error + * from the server). You probably want to set the second parameter to TRUE. */ +G_MODULE_EXPORT void imc_logout( struct im_connection *ic, int allow_reconnect ); + +/* Communicating with the user. */ +/* A printf()-like function to tell the user anything you want. */ +G_MODULE_EXPORT void imcb_log( struct im_connection *ic, char *format, ... ) G_GNUC_PRINTF( 2, 3 ); +/* To tell the user an error, ie. before logging out when an error occurs. */ +G_MODULE_EXPORT void imcb_error( struct im_connection *ic, char *format, ... ) G_GNUC_PRINTF( 2, 3 ); +/* To ask a your about something. + * - 'msg' is the question. + * - 'data' can be your custom struct - it will be passed to the callbacks. + * - 'doit' or 'dont' will be called depending of the answer of the user. + */ +G_MODULE_EXPORT void imcb_ask( struct im_connection *ic, char *msg, void *data, void *doit, void *dont ); +G_MODULE_EXPORT void imcb_ask_add( struct im_connection *ic, char *handle, const char *realname ); + +/* Buddy management */ +/* This function should be called for each handle which are visible to the + * user, usually after a login, or if the user added a buddy and the IM + * server confirms that the add was successful. Don't forget to do this! */ +G_MODULE_EXPORT void imcb_add_buddy( struct im_connection *ic, char *handle, char *group ); +G_MODULE_EXPORT void imcb_remove_buddy( struct im_connection *ic, char *handle, char *group ); +G_MODULE_EXPORT struct buddy *imcb_find_buddy( struct im_connection *ic, char *handle ); +G_MODULE_EXPORT void imcb_rename_buddy( struct im_connection *ic, char *handle, char *realname ); +G_MODULE_EXPORT void imcb_buddy_nick_hint( struct im_connection *ic, char *handle, char *nick ); + +/* Buddy activity */ +/* To manipulate the status of a handle. + * - flags can be |='d with OPT_* constants. You will need at least: + *   OPT_LOGGED_IN and OPT_AWAY. + * - 'state' and 'message' can be NULL */ +G_MODULE_EXPORT void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, const char *state, const char *message ); +/* Not implemented yet! */ G_MODULE_EXPORT void imcb_buddy_times( struct im_connection *ic, const char *handle, time_t login, time_t idle ); +/* Call when a handle says something. 'flags' and 'sent_at may be just 0. */ +G_MODULE_EXPORT void imcb_buddy_msg( struct im_connection *ic, char *handle, char *msg, uint32_t flags, time_t sent_at ); +G_MODULE_EXPORT void imcb_buddy_typing( struct im_connection *ic, char *handle, uint32_t flags ); +G_MODULE_EXPORT void imcb_clean_handle( struct im_connection *ic, char *handle ); + +/* Groupchats */ +G_MODULE_EXPORT void imcb_chat_invited( struct im_connection *ic, char *handle, char *who, char *msg, GList *data ); +/* These two functions are to create a group chat. + * - imcb_chat_new(): the 'handle' parameter identifies the chat, like the + *   channel name on IRC. + * - After you have a groupchat pointer, you should add the handles, finally + *   the user her/himself. At that point the group chat will be visible to the + *   user, too. */ +G_MODULE_EXPORT struct groupchat *imcb_chat_new( struct im_connection *ic, char *handle ); +G_MODULE_EXPORT void imcb_chat_add_buddy( struct groupchat *b, char *handle ); +/* To remove a handle from a group chat. Reason can be NULL. */ +G_MODULE_EXPORT void imcb_chat_remove_buddy( struct groupchat *b, char *handle, char *reason ); +/* To tell BitlBee 'who' said 'msg' in 'c'. 'flags' and 'sent_at' can be 0. */ +G_MODULE_EXPORT void imcb_chat_msg( struct groupchat *c, char *who, char *msg, uint32_t flags, time_t sent_at ); +/* System messages specific to a groupchat, so they can be displayed in the right context. */ +G_MODULE_EXPORT void imcb_chat_log( struct groupchat *c, char *format, ... ) G_GNUC_PRINTF( 2, 3 ); +/* To tell BitlBee 'who' changed the topic of 'c' to 'topic'. */ +G_MODULE_EXPORT void imcb_chat_topic( struct groupchat *c, char *who, char *topic, time_t set_at ); +G_MODULE_EXPORT void imcb_chat_free( struct groupchat *c ); + +/* Actions, or whatever. */ +int imc_set_away( struct im_connection *ic, char *away ); +int imc_buddy_msg( struct im_connection *ic, char *handle, char *msg, int flags ); +int imc_chat_msg( struct groupchat *c, char *msg, int flags ); + +void imc_add_allow( struct im_connection *ic, char *handle ); +void imc_rem_allow( struct im_connection *ic, char *handle ); +void imc_add_block( struct im_connection *ic, char *handle ); +void imc_rem_block( struct im_connection *ic, char *handle ); + +/* Misc. stuff */ +char *set_eval_away_devoice( set_t *set, char *value ); +gboolean auto_reconnect( gpointer data, gint fd, b_input_condition cond );  void cancel_auto_reconnect( struct account *a ); -/* multi.c */ -G_MODULE_EXPORT struct gaim_connection *new_gaim_conn( struct aim_user *user ); -G_MODULE_EXPORT void destroy_gaim_conn( struct gaim_connection *gc ); -G_MODULE_EXPORT void set_login_progress( struct gaim_connection *gc, int step, char *msg ); -G_MODULE_EXPORT void hide_login_progress( struct gaim_connection *gc, char *msg ); -G_MODULE_EXPORT void hide_login_progress_error( struct gaim_connection *gc, char *msg ); -G_MODULE_EXPORT void serv_got_crap( struct gaim_connection *gc, char *format, ... ) G_GNUC_PRINTF( 2, 3 ); -G_MODULE_EXPORT void account_online( struct gaim_connection *gc ); -G_MODULE_EXPORT void signoff( struct gaim_connection *gc ); - -/* dialogs.c */ -G_MODULE_EXPORT void do_error_dialog( struct gaim_connection *gc, char *msg, char *title ); -G_MODULE_EXPORT void do_ask_dialog( struct gaim_connection *gc, char *msg, void *data, void *doit, void *dont ); - -/* list.c */ -G_MODULE_EXPORT void add_buddy( struct gaim_connection *gc, char *group, char *handle, char *realname ); -G_MODULE_EXPORT struct buddy *find_buddy( struct gaim_connection *gc, char *handle ); -G_MODULE_EXPORT void signoff_blocked( struct gaim_connection *gc ); - -G_MODULE_EXPORT void serv_buddy_rename( struct gaim_connection *gc, char *handle, char *realname ); - -/* buddy_chat.c */ -G_MODULE_EXPORT void add_chat_buddy( struct conversation *b, char *handle ); -G_MODULE_EXPORT void remove_chat_buddy( struct conversation *b, char *handle, char *reason ); - -/* prpl.c */ -G_MODULE_EXPORT void show_got_added( struct gaim_connection *gc, char *handle, const char *realname ); - -/* server.c */                     -G_MODULE_EXPORT void serv_got_update( struct gaim_connection *gc, char *handle, int loggedin, int evil, time_t signon, time_t idle, int type, guint caps ); -G_MODULE_EXPORT void serv_got_im( struct gaim_connection *gc, char *handle, char *msg, guint32 flags, time_t mtime, gint len ); -G_MODULE_EXPORT void serv_got_typing( struct gaim_connection *gc, char *handle, int timeout, int type ); -G_MODULE_EXPORT void serv_got_chat_invite( struct gaim_connection *gc, char *handle, char *who, char *msg, GList *data ); -G_MODULE_EXPORT struct conversation *serv_got_joined_chat( struct gaim_connection *gc, int id, char *handle ); -G_MODULE_EXPORT void serv_got_chat_in( struct gaim_connection *gc, int id, char *who, int whisper, char *msg, time_t mtime ); -G_MODULE_EXPORT void serv_got_chat_left( struct gaim_connection *gc, int id ); - -struct conversation *conv_findchannel( char *channel ); -  #endif diff --git a/protocols/oscar/Makefile b/protocols/oscar/Makefile index 97a27299..2792f22a 100644 --- a/protocols/oscar/Makefile +++ b/protocols/oscar/Makefile @@ -16,6 +16,10 @@ LFLAGS += -r  # [SH] Phony targets  all: oscar_mod.o +check: all +lcov: check +gcov: +	gcov *.c  .PHONY: all clean distclean diff --git a/protocols/oscar/aim.h b/protocols/oscar/aim.h index 93887103..9516996c 100644 --- a/protocols/oscar/aim.h +++ b/protocols/oscar/aim.h @@ -93,7 +93,7 @@ typedef guint16 flap_seqnum_t;   * the client to connect to it.   *   */ -#define AIM_DEFAULT_LOGIN_SERVER "login.oscar.aol.com" +#define AIM_DEFAULT_LOGIN_SERVER "login.messaging.aol.com"  #define AIM_LOGIN_PORT 5190  /* @@ -573,7 +573,7 @@ struct aim_chat_roominfo {  };  struct aim_chat_invitation { -	struct gaim_connection * gc; +	struct im_connection * ic;  	char * name;  	guint8 exchange;  }; diff --git a/protocols/oscar/chat.c b/protocols/oscar/chat.c index df535c4f..fbf45693 100644 --- a/protocols/oscar/chat.c +++ b/protocols/oscar/chat.c @@ -53,7 +53,7 @@ aim_conn_t *aim_chat_getconn(aim_session_t *sess, const char *name)  		if (cur->type != AIM_CONN_TYPE_CHAT)  			continue;  		if (!cur->priv) { -			do_error_dialog(sess->aux_data, "chat connection with no name!", "Gaim"); +			imcb_error(sess->aux_data, "chat connection with no name!");  			continue;  		} @@ -396,7 +396,7 @@ static int infoupdate(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, a  	detaillevel = aimbs_get8(bs);  	if (detaillevel != 0x02) { -		do_error_dialog(sess->aux_data, "Only detaillevel 0x2 is support at the moment", "Gaim"); +		imcb_error(sess->aux_data, "Only detaillevel 0x2 is support at the moment");  		return 1;  	} @@ -614,7 +614,7 @@ static int incomingmsg(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx,  	channel = aimbs_get16(bs);  	if (channel != 0x0003) { -		do_error_dialog(sess->aux_data, "unknown channel!", "Gaim"); +		imcb_error(sess->aux_data, "unknown channel!");  		return 0;  	} diff --git a/protocols/oscar/chatnav.c b/protocols/oscar/chatnav.c index c7e11765..d94d3c7b 100644 --- a/protocols/oscar/chatnav.c +++ b/protocols/oscar/chatnav.c @@ -285,7 +285,7 @@ static int parseinfo_create(aim_session_t *sess, aim_module_t *mod, aim_frame_t  	tlvlist = aim_readtlvchain(bs);  	if (!(bigblock = aim_gettlv(tlvlist, 0x0004, 1))) { -		do_error_dialog(sess->aux_data, "no bigblock in top tlv in create room response", "Gaim"); +		imcb_error(sess->aux_data, "no bigblock in top tlv in create room response");  		aim_freetlvchain(&tlvlist);  		return 0; @@ -300,7 +300,7 @@ static int parseinfo_create(aim_session_t *sess, aim_module_t *mod, aim_frame_t  	detaillevel = aimbs_get8(&bbbs);  	if (detaillevel != 0x02) { -		do_error_dialog(sess->aux_data, "unknown detaillevel in create room response", "Gaim"); +		imcb_error(sess->aux_data, "unknown detaillevel in create room response");  		aim_freetlvchain(&tlvlist);  		g_free(ck);  		return 0; @@ -366,12 +366,12 @@ static int parseinfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, ai  	int ret = 0;  	if (!(snac2 = aim_remsnac(sess, snac->id))) { -		do_error_dialog(sess->aux_data, "received response to unknown request!", "Gaim"); +		imcb_error(sess->aux_data, "received response to unknown request!");  		return 0;  	}  	if (snac2->family != 0x000d) { -		do_error_dialog(sess->aux_data, "recieved response that maps to corrupt request!", "Gaim"); +		imcb_error(sess->aux_data, "recieved response that maps to corrupt request!");  		return 0;  	} @@ -388,7 +388,7 @@ static int parseinfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, ai  	else if (snac2->type == 0x0008) /* create room */  		ret = parseinfo_create(sess, mod, rx, snac, bs, snac2);  	else -		do_error_dialog(sess->aux_data, "unknown request subtype", "Gaim"); +		imcb_error(sess->aux_data, "unknown request subtype");  	if (snac2)  		g_free(snac2->data); diff --git a/protocols/oscar/icq.c b/protocols/oscar/icq.c index 23959b75..f7c02e04 100644 --- a/protocols/oscar/icq.c +++ b/protocols/oscar/icq.c @@ -239,7 +239,7 @@ static int icqresponse(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx,  	if (!(tl = aim_readtlvchain(bs)) || !(datatlv = aim_gettlv(tl, 0x0001, 1))) {  		aim_freetlvchain(&tl); -		do_error_dialog(sess->aux_data, "corrupt ICQ response\n", "Gaim"); +		imcb_error(sess->aux_data, "corrupt ICQ response\n");  		return 0;  	} diff --git a/protocols/oscar/im.c b/protocols/oscar/im.c index 7cccabc7..51d8ec74 100644 --- a/protocols/oscar/im.c +++ b/protocols/oscar/im.c @@ -936,7 +936,7 @@ static int outgoingim(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, a  	channel = aimbs_get16(bs);  	if (channel != 0x01) { -		do_error_dialog(sess->aux_data, "icbm: ICBM recieved on unsupported channel.  Ignoring.", "Gaim"); +		imcb_error(sess->aux_data, "icbm: ICBM recieved on unsupported channel.  Ignoring.");  		return 0;  	} @@ -1344,7 +1344,7 @@ static int incomingim_ch1(aim_session_t *sess, aim_module_t *mod, aim_frame_t *r  			args.extdata = aimbs_getraw(bs, args.extdatalen);  		} else { -			// do_error_dialog(sess->aux_data, "Unknown TLV encountered", "Gaim"); +			// imcb_error(sess->aux_data, "Unknown TLV encountered");  		}  		/* @@ -1416,7 +1416,7 @@ static void incomingim_ch2_icqserverrelay(aim_session_t *sess, aim_module_t *mod  	guint8 msgtype, msgflags;      guint8 *plugin;      int i = 0, tmp = 0; -    struct gaim_connection *gc = sess->aux_data; +    struct im_connection *ic = sess->aux_data;      /* at the moment we just can deal with requests, not with cancel or accept */      if (args->status != 0) return; @@ -1468,7 +1468,7 @@ static void incomingim_ch2_icqserverrelay(aim_session_t *sess, aim_module_t *mod              case AIM_MTYPE_AUTOFFC:  	    case 0x9c:	/* ICQ 5 seems to send this */                  aim_send_im_ch2_statusmessage(sess, userinfo->sn, args->cookie, -                        gc->away ? gc->away : "", sess->aim_icq_state, dc); +                        ic->away ? ic->away : "", sess->aim_icq_state, dc);                  break;          } @@ -1516,7 +1516,7 @@ static int incomingim_ch2(aim_session_t *sess, aim_module_t *mod, aim_frame_t *r  	 */  	cookie2 = aimbs_getraw(&bbs, 8);  	if (memcmp(cookie, cookie2, 8) != 0)  -		do_error_dialog(sess->aux_data, "rend: warning cookies don't match!", "Gaim"); +		imcb_error(sess->aux_data, "rend: warning cookies don't match!");  	memcpy(args.cookie, cookie2, 8);  	g_free(cookie2); @@ -1782,7 +1782,7 @@ static int incomingim(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, a  	} else { -		do_error_dialog(sess->aux_data, "ICBM received on an unsupported channel.  Ignoring.", "Gaim"); +		imcb_error(sess->aux_data, "ICBM received on an unsupported channel.  Ignoring.");  		return 0;  	} diff --git a/protocols/oscar/info.c b/protocols/oscar/info.c index ffe29d1f..7cc1dbbc 100644 --- a/protocols/oscar/info.c +++ b/protocols/oscar/info.c @@ -260,6 +260,7 @@ guint32 aim_getcap(aim_session_t *sess, aim_bstream_t *bs, int len)  		if (!identified) {  			/*FIXME*/ +			/*REMOVEME :-)  			g_strdup_printf("unknown capability: {%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n",  					cap[0], cap[1], cap[2], cap[3],  					cap[4], cap[5], @@ -267,7 +268,7 @@ guint32 aim_getcap(aim_session_t *sess, aim_bstream_t *bs, int len)  					cap[8], cap[9],  					cap[10], cap[11], cap[12], cap[13],  					cap[14], cap[15]); -			 +			*/  		}  		g_free(cap); @@ -472,7 +473,7 @@ int aim_extractuserinfo(aim_session_t *sess, aim_bstream_t *bs, aim_userinfo_t *  			 *  			 */  #ifdef DEBUG -			// do_error_dialog(sess->aux_data, G_STRLOC, "Unknown TLV encountered"); +			// imcb_error(sess->aux_data, G_STRLOC);  #endif  		} @@ -633,7 +634,7 @@ static int userinfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim  	origsnac = aim_remsnac(sess, snac->id);  	if (!origsnac || !origsnac->data) { -		do_error_dialog(sess->aux_data, "major problem: no snac stored!", "Gaim"); +		imcb_error(sess->aux_data, "major problem: no snac stored!");  		return 0;  	} @@ -642,7 +643,7 @@ static int userinfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim  	if ((inforeq->infotype != AIM_GETINFO_GENERALINFO) &&  			(inforeq->infotype != AIM_GETINFO_AWAYMESSAGE) &&  			(inforeq->infotype != AIM_GETINFO_CAPABILITIES)) { -		do_error_dialog(sess->aux_data, "unknown infotype in request!", "Gaim"); +		imcb_error(sess->aux_data, "unknown infotype in request!");  		return 0;  	} diff --git a/protocols/oscar/msgcookie.c b/protocols/oscar/msgcookie.c index d3c91a94..efeb8cbf 100644 --- a/protocols/oscar/msgcookie.c +++ b/protocols/oscar/msgcookie.c @@ -130,21 +130,6 @@ aim_msgcookie_t *aim_checkcookie(aim_session_t *sess, const guint8 *cookie, int  	return NULL;  } -#if 0 /* debugging feature */ -int aim_dumpcookie(aim_msgcookie_t *cookie)  -{ - -	if (!cookie) -		return -EINVAL; - -	printf("\tCookie at %p: %d/%s with %p, next %p\n",  -			cookie, cookie->type, cookie->cookie,  -			cookie->data, cookie->next); - -	return 0; -} -#endif -  /**   * aim_cookie_free - free an aim_msgcookie_t struct   * @sess: session to remove the cookie from diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c index c2716c6b..9e5de70a 100644 --- a/protocols/oscar/oscar.c +++ b/protocols/oscar/oscar.c @@ -90,6 +90,8 @@ struct oscar_data {  	gboolean killme;  	gboolean icq;  	GSList *evilhack; +	 +	GHashTable *ips;  	struct {  		guint maxbuddies; /* max users you can watch */ @@ -115,21 +117,21 @@ struct chat_connection {  	aim_conn_t *conn;  	int inpa;  	int id; -	struct gaim_connection *gc; /* i hate this. */ -	struct conversation *cnv; /* bah. */ +	struct im_connection *ic; /* i hate this. */ +	struct groupchat *cnv; /* bah. */  	int maxlen;  	int maxvis;  };  struct ask_direct { -	struct gaim_connection *gc; +	struct im_connection *ic;  	char *sn;  	char ip[64];  	guint8 cookie[8];  };  struct icq_auth { -	struct gaim_connection *gc; +	struct im_connection *ic;  	guint32 uin;  }; @@ -157,25 +159,9 @@ static char *extract_name(const char *name) {  	return tmp;  } -static struct chat_connection *find_oscar_chat(struct gaim_connection *gc, int id) { -	GSList *g = ((struct oscar_data *)gc->proto_data)->oscar_chats; -	struct chat_connection *c = NULL; - -	while (g) { -		c = (struct chat_connection *)g->data; -		if (c->id == id) -			break; -		g = g->next; -		c = NULL; -	} - -	return c; -} - - -static struct chat_connection *find_oscar_chat_by_conn(struct gaim_connection *gc, +static struct chat_connection *find_oscar_chat_by_conn(struct im_connection *ic,  							aim_conn_t *conn) { -	GSList *g = ((struct oscar_data *)gc->proto_data)->oscar_chats; +	GSList *g = ((struct oscar_data *)ic->proto_data)->oscar_chats;  	struct chat_connection *c = NULL;  	while (g) { @@ -254,50 +240,48 @@ static char *msgerrreason[] = {  };  static int msgerrreasonlen = 25; -static void oscar_callback(gpointer data, gint source, -				GaimInputCondition condition) { +static gboolean oscar_callback(gpointer data, gint source, +				b_input_condition condition) {  	aim_conn_t *conn = (aim_conn_t *)data;  	aim_session_t *sess = aim_conn_getsess(conn); -	struct gaim_connection *gc = sess ? sess->aux_data : NULL; +	struct im_connection *ic = sess ? sess->aux_data : NULL;  	struct oscar_data *odata; -	if (!gc) { -		/* gc is null. we return, else we seg SIGSEG on next line. */ -		return; +	if (!ic) { +		/* ic is null. we return, else we seg SIGSEG on next line. */ +		return FALSE;  	} -	if (!g_slist_find(get_connections(), gc)) { +	if (!g_slist_find(get_connections(), ic)) {  		/* oh boy. this is probably bad. i guess the only thing we   		 * can really do is return? */ -		return; +		return FALSE;  	} -	odata = (struct oscar_data *)gc->proto_data; +	odata = (struct oscar_data *)ic->proto_data;  	if (condition & GAIM_INPUT_READ) {  		if (aim_get_command(odata->sess, conn) >= 0) {  			aim_rxdispatch(odata->sess);                                 if (odata->killme) -                                       signoff(gc); +                                       imc_logout(ic, TRUE);  		} else {  			if ((conn->type == AIM_CONN_TYPE_BOS) ||  				   !(aim_getconn_type(odata->sess, AIM_CONN_TYPE_BOS))) { -				hide_login_progress_error(gc, _("Disconnected.")); -				signoff(gc); +				imcb_error(ic, _("Disconnected.")); +				imc_logout(ic, TRUE);  			} else if (conn->type == AIM_CONN_TYPE_CHAT) { -				struct chat_connection *c = find_oscar_chat_by_conn(gc, conn); -				char buf[BUF_LONG]; +				struct chat_connection *c = find_oscar_chat_by_conn(ic, conn);  				c->conn = NULL;  				if (c->inpa > 0) -					gaim_input_remove(c->inpa); +					b_event_remove(c->inpa);  				c->inpa = 0;  				c->fd = -1;  				aim_conn_kill(odata->sess, &conn); -				sprintf(buf, _("You have been disconnected from chat room %s."), c->name); -				do_error_dialog(sess->aux_data, buf, _("Chat Error!")); +				imcb_error(sess->aux_data, _("You have been disconnected from chat room %s."), c->name);  			} else if (conn->type == AIM_CONN_TYPE_CHATNAV) {  				if (odata->cnpa > 0) -					gaim_input_remove(odata->cnpa); +					b_event_remove(odata->cnpa);  				odata->cnpa = 0;  				while (odata->create_rooms) {  					struct create_room *cr = odata->create_rooms->data; @@ -305,65 +289,78 @@ static void oscar_callback(gpointer data, gint source,  					odata->create_rooms =  						g_slist_remove(odata->create_rooms, cr);  					g_free(cr); -					do_error_dialog(sess->aux_data, _("Chat is currently unavailable"), -							_("Gaim - Chat")); +					imcb_error(sess->aux_data, _("Chat is currently unavailable"));  				}  				aim_conn_kill(odata->sess, &conn);  			} else if (conn->type == AIM_CONN_TYPE_AUTH) {  				if (odata->paspa > 0) -					gaim_input_remove(odata->paspa); +					b_event_remove(odata->paspa);  				odata->paspa = 0;  				aim_conn_kill(odata->sess, &conn);  			} else {  				aim_conn_kill(odata->sess, &conn);  			}  		} +	} else { +		/* WTF??? */ +		return FALSE;  	} +		 +	return TRUE;  } -static void oscar_login_connect(gpointer data, gint source, GaimInputCondition cond) +static gboolean oscar_login_connect(gpointer data, gint source, b_input_condition cond)  { -	struct gaim_connection *gc = data; +	struct im_connection *ic = data;  	struct oscar_data *odata;  	aim_session_t *sess;  	aim_conn_t *conn; -	if (!g_slist_find(get_connections(), gc)) { +	if (!g_slist_find(get_connections(), ic)) {  		closesocket(source); -		return; +		return FALSE;  	} -	odata = gc->proto_data; +	odata = ic->proto_data;  	sess = odata->sess;  	conn = aim_getconn_type_all(sess, AIM_CONN_TYPE_AUTH);  	if (source < 0) { -		hide_login_progress(gc, _("Couldn't connect to host")); -		signoff(gc); -		return; +		imcb_error(ic, _("Couldn't connect to host")); +		imc_logout(ic, TRUE); +		return FALSE;  	}  	aim_conn_completeconnect(sess, conn); -	gc->inpa = gaim_input_add(conn->fd, GAIM_INPUT_READ, +	ic->inpa = b_input_add(conn->fd, GAIM_INPUT_READ,  			oscar_callback, conn); +	 +	return FALSE; +} + +static void oscar_init(account_t *acc) +{ +	set_t *s; +	 +	s = set_add( &acc->set, "server", AIM_DEFAULT_LOGIN_SERVER, set_eval_account, acc ); +	s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY; +	 +	if (isdigit(acc->user[0])) { +		s = set_add( &acc->set, "web_aware", "false", set_eval_bool, acc ); +		s->flags |= ACC_SET_OFFLINE_ONLY; +	}  } -static void oscar_login(struct aim_user *user) { +static void oscar_login(account_t *acc) {  	aim_session_t *sess;  	aim_conn_t *conn; -	char buf[256]; -	struct gaim_connection *gc = new_gaim_conn(user); -	struct oscar_data *odata = gc->proto_data = g_new0(struct oscar_data, 1); +	struct im_connection *ic = imcb_new(acc); +	struct oscar_data *odata = ic->proto_data = g_new0(struct oscar_data, 1); -	if (isdigit(*user->username)) { +	if (isdigit(acc->user[0]))  		odata->icq = TRUE; -		/* This is odd but it's necessary for a proper do_import and do_export. -		   We don't do those anymore, but let's stick with it, just in case -		   it accidentally fixes something else too... */ -		gc->password[8] = 0; -	} else { -		gc->flags |= OPT_CONN_HTML; -	} +	else +		ic->flags |= OPT_DOES_HTML;  	sess = g_new0(aim_session_t, 1); @@ -373,47 +370,38 @@ static void oscar_login(struct aim_user *user) {  	 * see if things need to be sent. */  	aim_tx_setenqueue(sess, AIM_TX_IMMEDIATE, NULL);  	odata->sess = sess; -	sess->aux_data = gc; +	sess->aux_data = ic;  	conn = aim_newconn(sess, AIM_CONN_TYPE_AUTH, NULL);  	if (conn == NULL) { -		hide_login_progress(gc, _("Unable to login to AIM")); -		signoff(gc); +		imcb_error(ic, _("Unable to login to AIM")); +		imc_logout(ic, TRUE);  		return;  	} -	if (g_strcasecmp(user->proto_opt[USEROPT_AUTH], "login.icq.com") != 0 && -	    g_strcasecmp(user->proto_opt[USEROPT_AUTH], "login.oscar.aol.com") != 0) { -		serv_got_crap(gc, "Warning: Unknown OSCAR server: `%s'. Please review your configuration if the connection fails.",user->proto_opt[USEROPT_AUTH]); -	} -	 -	g_snprintf(buf, sizeof(buf), _("Signon: %s"), gc->username); -	set_login_progress(gc, 2, buf); +	imcb_log(ic, _("Signon: %s"), ic->acc->user);  	aim_conn_addhandler(sess, conn, 0x0017, 0x0007, gaim_parse_login, 0);  	aim_conn_addhandler(sess, conn, 0x0017, 0x0003, gaim_parse_auth_resp, 0);  	conn->status |= AIM_CONN_STATUS_INPROGRESS; -	conn->fd = proxy_connect(user->proto_opt[USEROPT_AUTH][0] ? -					user->proto_opt[USEROPT_AUTH] : AIM_DEFAULT_LOGIN_SERVER, -				 user->proto_opt[USEROPT_AUTHPORT][0] ? -					atoi(user->proto_opt[USEROPT_AUTHPORT]) : AIM_LOGIN_PORT, -				 oscar_login_connect, gc); +	conn->fd = proxy_connect(set_getstr(&acc->set, "server"), +	                         AIM_LOGIN_PORT, oscar_login_connect, ic);  	if (conn->fd < 0) { -		hide_login_progress(gc, _("Couldn't connect to host")); -		signoff(gc); +		imcb_error(ic, _("Couldn't connect to host")); +		imc_logout(ic, TRUE);  		return;  	} -	aim_request_login(sess, conn, gc->username); +	aim_request_login(sess, conn, ic->acc->user);  } -static void oscar_close(struct gaim_connection *gc) { -	struct oscar_data *odata = (struct oscar_data *)gc->proto_data; +static void oscar_logout(struct im_connection *ic) { +	struct oscar_data *odata = (struct oscar_data *)ic->proto_data;  	while (odata->oscar_chats) {  		struct chat_connection *n = odata->oscar_chats->data;  		if (n->inpa > 0) -			gaim_input_remove(n->inpa); +			b_event_remove(n->inpa);  		g_free(n->name);  		g_free(n->show);  		odata->oscar_chats = g_slist_remove(odata->oscar_chats, n); @@ -425,64 +413,65 @@ static void oscar_close(struct gaim_connection *gc) {  		odata->create_rooms = g_slist_remove(odata->create_rooms, cr);  		g_free(cr);  	} +	if (odata->ips) +		g_hash_table_destroy(odata->ips);  	if (odata->email)  		g_free(odata->email);  	if (odata->newp)  		g_free(odata->newp);  	if (odata->oldp)  		g_free(odata->oldp); -	if (gc->inpa > 0) -		gaim_input_remove(gc->inpa); +	if (ic->inpa > 0) +		b_event_remove(ic->inpa);  	if (odata->cnpa > 0) -		gaim_input_remove(odata->cnpa); +		b_event_remove(odata->cnpa);  	if (odata->paspa > 0) -		gaim_input_remove(odata->paspa); +		b_event_remove(odata->paspa);  	aim_session_kill(odata->sess);  	g_free(odata->sess);  	odata->sess = NULL; -	g_free(gc->proto_data); -	gc->proto_data = NULL; +	g_free(ic->proto_data); +	ic->proto_data = NULL;  } -static void oscar_bos_connect(gpointer data, gint source, GaimInputCondition cond) { -	struct gaim_connection *gc = data; +static gboolean oscar_bos_connect(gpointer data, gint source, b_input_condition cond) { +	struct im_connection *ic = data;  	struct oscar_data *odata;  	aim_session_t *sess;  	aim_conn_t *bosconn; -	if (!g_slist_find(get_connections(), gc)) { +	if (!g_slist_find(get_connections(), ic)) {  		closesocket(source); -		return; +		return FALSE;  	} -	odata = gc->proto_data; +	odata = ic->proto_data;  	sess = odata->sess;  	bosconn = odata->conn;  	if (source < 0) { -		hide_login_progress(gc, _("Could Not Connect")); -		signoff(gc); -		return; +		imcb_error(ic, _("Could Not Connect")); +		imc_logout(ic, TRUE); +		return FALSE;  	}  	aim_conn_completeconnect(sess, bosconn); -	gc->inpa = gaim_input_add(bosconn->fd, GAIM_INPUT_READ, +	ic->inpa = b_input_add(bosconn->fd, GAIM_INPUT_READ,  			oscar_callback, bosconn); -	set_login_progress(gc, 4, _("Connection established, cookie sent")); +	imcb_log(ic, _("Connection established, cookie sent")); +	 +	return FALSE;  }  static int gaim_parse_auth_resp(aim_session_t *sess, aim_frame_t *fr, ...) {  	va_list ap;  	struct aim_authresp_info *info;  	int i; char *host; int port; -	struct aim_user *user;  	aim_conn_t *bosconn; -	struct gaim_connection *gc = sess->aux_data; -        struct oscar_data *od = gc->proto_data; -	user = gc->user; -	port = user->proto_opt[USEROPT_AUTHPORT][0] ? -		atoi(user->proto_opt[USEROPT_AUTHPORT]) : AIM_LOGIN_PORT, +	struct im_connection *ic = sess->aux_data; +        struct oscar_data *od = ic->proto_data; +	port = AIM_LOGIN_PORT;  	va_start(ap, fr);  	info = va_arg(ap, struct aim_authresp_info *); @@ -492,23 +481,23 @@ static int gaim_parse_auth_resp(aim_session_t *sess, aim_frame_t *fr, ...) {  		switch (info->errorcode) {  		case 0x05:  			/* Incorrect nick/password */ -			hide_login_progress(gc, _("Incorrect nickname or password.")); +			imcb_error(ic, _("Incorrect nickname or password."));  //			plugin_event(event_error, (void *)980, 0, 0, 0);  			break;  		case 0x11:  			/* Suspended account */ -			hide_login_progress(gc, _("Your account is currently suspended.")); +			imcb_error(ic, _("Your account is currently suspended."));  			break;  		case 0x18:  			/* connecting too frequently */ -			hide_login_progress(gc, _("You have been connecting and disconnecting too frequently. Wait ten minutes and try again. If you continue to try, you will need to wait even longer.")); +			imcb_error(ic, _("You have been connecting and disconnecting too frequently. Wait ten minutes and try again. If you continue to try, you will need to wait even longer."));  			break;  		case 0x1c:  			/* client too old */ -			hide_login_progress(gc, _("The client version you are using is too old. Please upgrade at " WEBSITE)); +			imcb_error(ic, _("The client version you are using is too old. Please upgrade at " WEBSITE));  			break;  		default: -			hide_login_progress(gc, _("Authentication Failed")); +			imcb_error(ic, _("Authentication Failed"));  			break;  		}  		od->killme = TRUE; @@ -520,7 +509,7 @@ static int gaim_parse_auth_resp(aim_session_t *sess, aim_frame_t *fr, ...) {  	bosconn = aim_newconn(sess, AIM_CONN_TYPE_BOS, NULL);  	if (bosconn == NULL) { -		hide_login_progress(gc, _("Internal Error")); +		imcb_error(ic, _("Internal Error"));  		od->killme = TRUE;  		return 0;  	} @@ -554,7 +543,7 @@ static int gaim_parse_auth_resp(aim_session_t *sess, aim_frame_t *fr, ...) {  	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO, gaim_parseaiminfo, 0);  	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_MTN, gaim_parsemtn, 0); -	((struct oscar_data *)gc->proto_data)->conn = bosconn; +	((struct oscar_data *)ic->proto_data)->conn = bosconn;  	for (i = 0; i < (int)strlen(info->bosip); i++) {  		if (info->bosip[i] == ':') {  			port = atoi(&(info->bosip[i+1])); @@ -563,21 +552,21 @@ static int gaim_parse_auth_resp(aim_session_t *sess, aim_frame_t *fr, ...) {  	}  	host = g_strndup(info->bosip, i);  	bosconn->status |= AIM_CONN_STATUS_INPROGRESS; -	bosconn->fd = proxy_connect(host, port, oscar_bos_connect, gc); +	bosconn->fd = proxy_connect(host, port, oscar_bos_connect, ic);  	g_free(host);  	if (bosconn->fd < 0) { -		hide_login_progress(gc, _("Could Not Connect")); +		imcb_error(ic, _("Could Not Connect"));  		od->killme = TRUE;  		return 0;  	}  	aim_sendcookie(sess, bosconn, info->cookie); -	gaim_input_remove(gc->inpa); +	b_event_remove(ic->inpa);  	return 1;  }  struct pieceofcrap { -	struct gaim_connection *gc; +	struct im_connection *ic;  	unsigned long offset;  	unsigned long len;  	char *modname; @@ -586,10 +575,10 @@ struct pieceofcrap {  	unsigned int inpa;  }; -static void damn_you(gpointer data, gint source, GaimInputCondition c) +static gboolean damn_you(gpointer data, gint source, b_input_condition c)  {  	struct pieceofcrap *pos = data; -	struct oscar_data *od = pos->gc->proto_data; +	struct oscar_data *od = pos->ic->proto_data;  	char in = '\0';  	int x = 0;  	unsigned char m[17]; @@ -604,33 +593,35 @@ static void damn_you(gpointer data, gint source, GaimInputCondition c)  		in = '\0';  	}  	if (in != '\n') { -		do_error_dialog(pos->gc, "Gaim was unable to get a valid hash for logging into AIM." -				" You may be disconnected shortly.", "Login Error"); -		gaim_input_remove(pos->inpa); +		imcb_error(pos->ic, "Gaim was unable to get a valid hash for logging into AIM." +				" You may be disconnected shortly."); +		b_event_remove(pos->inpa);  		closesocket(pos->fd);  		g_free(pos); -		return; +		return FALSE;  	}  	/* [WvG] Wheeeee! Who needs error checking anyway? ;-) */  	read(pos->fd, m, 16);  	m[16] = '\0'; -	gaim_input_remove(pos->inpa); +	b_event_remove(pos->inpa);  	closesocket(pos->fd);  	aim_sendmemblock(od->sess, pos->conn, 0, 16, m, AIM_SENDMEMBLOCK_FLAG_ISHASH);  	g_free(pos); +	 +	return FALSE;  } -static void straight_to_hell(gpointer data, gint source, GaimInputCondition cond) { +static gboolean straight_to_hell(gpointer data, gint source, b_input_condition cond) {  	struct pieceofcrap *pos = data;  	char buf[BUF_LONG];  	if (source < 0) { -		do_error_dialog(pos->gc, "Gaim was unable to get a valid hash for logging into AIM." -				" You may be disconnected shortly.", "Login Error"); +		imcb_error(pos->ic, "Gaim was unable to get a valid hash for logging into AIM." +				" You may be disconnected shortly.");  		if (pos->modname)  			g_free(pos->modname);  		g_free(pos); -		return; +		return FALSE;  	}  	g_snprintf(buf, sizeof(buf), "GET " AIMHASHDATA @@ -639,8 +630,8 @@ static void straight_to_hell(gpointer data, gint source, GaimInputCondition cond  	write(pos->fd, buf, strlen(buf));  	if (pos->modname)  		g_free(pos->modname); -	pos->inpa = gaim_input_add(pos->fd, GAIM_INPUT_READ, damn_you, pos); -	return; +	pos->inpa = b_input_add(pos->fd, GAIM_INPUT_READ, damn_you, pos); +	return FALSE;  }  /* size of icbmui.ocm, the largest module in AIM 3.5 */ @@ -691,7 +682,7 @@ int gaim_memrequest(aim_session_t *sess, aim_frame_t *fr, ...) {  	*/  	pos = g_new0(struct pieceofcrap, 1); -	pos->gc = sess->aux_data; +	pos->ic = sess->aux_data;  	pos->conn = fr->conn;  	pos->offset = offset; @@ -703,8 +694,8 @@ int gaim_memrequest(aim_session_t *sess, aim_frame_t *fr, ...) {  		if (pos->modname)  			g_free(pos->modname);  		g_free(pos); -		do_error_dialog(sess->aux_data, "Gaim was unable to get a valid hash for logging into AIM." -				" You may be disconnected shortly.", "Login Error"); +		imcb_error(sess->aux_data, "Gaim was unable to get a valid hash for logging into AIM." +				" You may be disconnected shortly.");  	}  	pos->fd = fd; @@ -719,19 +710,19 @@ static int gaim_parse_login(aim_session_t *sess, aim_frame_t *fr, ...) {  #endif  	char *key;  	va_list ap; -	struct gaim_connection *gc = sess->aux_data; +	struct im_connection *ic = sess->aux_data;  	va_start(ap, fr);  	key = va_arg(ap, char *);  	va_end(ap); -	aim_send_login(sess, fr->conn, gc->username, gc->password, &info, key); +	aim_send_login(sess, fr->conn, ic->acc->user, ic->acc->pass, &info, key);  	return 1;  }  static int conninitdone_chat(aim_session_t *sess, aim_frame_t *fr, ...) { -	struct gaim_connection *gc = sess->aux_data; +	struct im_connection *ic = sess->aux_data;  	struct chat_connection *chatcon;  	static int id = 1; @@ -743,9 +734,10 @@ static int conninitdone_chat(aim_session_t *sess, aim_frame_t *fr, ...) {  	aim_clientready(sess, fr->conn); -	chatcon = find_oscar_chat_by_conn(gc, fr->conn); +	chatcon = find_oscar_chat_by_conn(ic, fr->conn);  	chatcon->id = id; -	chatcon->cnv = serv_got_joined_chat(gc, id++, chatcon->show); +	chatcon->cnv = imcb_chat_new(ic, chatcon->show); +	chatcon->cnv->data = chatcon;  	return 1;  } @@ -762,74 +754,78 @@ static int conninitdone_chatnav(aim_session_t *sess, aim_frame_t *fr, ...) {  	return 1;  } -static void oscar_chatnav_connect(gpointer data, gint source, GaimInputCondition cond) { -	struct gaim_connection *gc = data; +static gboolean oscar_chatnav_connect(gpointer data, gint source, b_input_condition cond) { +	struct im_connection *ic = data;  	struct oscar_data *odata;  	aim_session_t *sess;  	aim_conn_t *tstconn; -	if (!g_slist_find(get_connections(), gc)) { +	if (!g_slist_find(get_connections(), ic)) {  		closesocket(source); -		return; +		return FALSE;  	} -	odata = gc->proto_data; +	odata = ic->proto_data;  	sess = odata->sess;  	tstconn = aim_getconn_type_all(sess, AIM_CONN_TYPE_CHATNAV);  	if (source < 0) {  		aim_conn_kill(sess, &tstconn); -		return; +		return FALSE;  	}  	aim_conn_completeconnect(sess, tstconn); -	odata->cnpa = gaim_input_add(tstconn->fd, GAIM_INPUT_READ, +	odata->cnpa = b_input_add(tstconn->fd, GAIM_INPUT_READ,  					oscar_callback, tstconn); +	 +	return FALSE;  } -static void oscar_auth_connect(gpointer data, gint source, GaimInputCondition cond) +static gboolean oscar_auth_connect(gpointer data, gint source, b_input_condition cond)  { -	struct gaim_connection *gc = data; +	struct im_connection *ic = data;  	struct oscar_data *odata;  	aim_session_t *sess;  	aim_conn_t *tstconn; -	if (!g_slist_find(get_connections(), gc)) { +	if (!g_slist_find(get_connections(), ic)) {  		closesocket(source); -		return; +		return FALSE;  	} -	odata = gc->proto_data; +	odata = ic->proto_data;  	sess = odata->sess;  	tstconn = aim_getconn_type_all(sess, AIM_CONN_TYPE_AUTH);  	if (source < 0) {  		aim_conn_kill(sess, &tstconn); -		return; +		return FALSE;  	}  	aim_conn_completeconnect(sess, tstconn); -	odata->paspa = gaim_input_add(tstconn->fd, GAIM_INPUT_READ, +	odata->paspa = b_input_add(tstconn->fd, GAIM_INPUT_READ,  				oscar_callback, tstconn); +	 +	return FALSE;  } -static void oscar_chat_connect(gpointer data, gint source, GaimInputCondition cond) +static gboolean oscar_chat_connect(gpointer data, gint source, b_input_condition cond)  {  	struct chat_connection *ccon = data; -	struct gaim_connection *gc = ccon->gc; +	struct im_connection *ic = ccon->ic;  	struct oscar_data *odata;  	aim_session_t *sess;  	aim_conn_t *tstconn; -	if (!g_slist_find(get_connections(), gc)) { +	if (!g_slist_find(get_connections(), ic)) {  		closesocket(source);  		g_free(ccon->show);  		g_free(ccon->name);  		g_free(ccon); -		return; +		return FALSE;  	} -	odata = gc->proto_data; +	odata = ic->proto_data;  	sess = odata->sess;  	tstconn = ccon->conn; @@ -838,34 +834,33 @@ static void oscar_chat_connect(gpointer data, gint source, GaimInputCondition co  		g_free(ccon->show);  		g_free(ccon->name);  		g_free(ccon); -		return; +		return FALSE;  	}  	aim_conn_completeconnect(sess, ccon->conn); -	ccon->inpa = gaim_input_add(tstconn->fd, +	ccon->inpa = b_input_add(tstconn->fd,  			GAIM_INPUT_READ,  			oscar_callback, tstconn);  	odata->oscar_chats = g_slist_append(odata->oscar_chats, ccon); +	 +	return FALSE;  }  /* Hrmph. I don't know how to make this look better. --mid */  static int gaim_handle_redirect(aim_session_t *sess, aim_frame_t *fr, ...) {  	va_list ap;  	struct aim_redirect_data *redir; -	struct gaim_connection *gc = sess->aux_data; -	struct aim_user *user = gc->user; +	struct im_connection *ic = sess->aux_data;  	aim_conn_t *tstconn;  	int i;  	char *host;  	int port; -	port = user->proto_opt[USEROPT_AUTHPORT][0] ? -		atoi(user->proto_opt[USEROPT_AUTHPORT]) : AIM_LOGIN_PORT, -  	va_start(ap, fr);  	redir = va_arg(ap, struct aim_redirect_data *);  	va_end(ap); +	port = AIM_LOGIN_PORT;  	for (i = 0; i < (int)strlen(redir->ip); i++) {  		if (redir->ip[i] == ':') {  			port = atoi(&(redir->ip[i+1])); @@ -887,7 +882,7 @@ static int gaim_handle_redirect(aim_session_t *sess, aim_frame_t *fr, ...) {  //		aim_conn_addhandler(sess, tstconn, 0x0007, 0x0007, gaim_account_confirm, 0);  		tstconn->status |= AIM_CONN_STATUS_INPROGRESS; -		tstconn->fd = proxy_connect(host, port, oscar_auth_connect, gc); +		tstconn->fd = proxy_connect(host, port, oscar_auth_connect, ic);  		if (tstconn->fd < 0) {  			aim_conn_kill(sess, &tstconn);  			g_free(host); @@ -904,7 +899,7 @@ static int gaim_handle_redirect(aim_session_t *sess, aim_frame_t *fr, ...) {  		aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_chatnav, 0);  		tstconn->status |= AIM_CONN_STATUS_INPROGRESS; -		tstconn->fd = proxy_connect(host, port, oscar_chatnav_connect, gc); +		tstconn->fd = proxy_connect(host, port, oscar_chatnav_connect, ic);  		if (tstconn->fd < 0) {  			aim_conn_kill(sess, &tstconn);  			g_free(host); @@ -926,7 +921,7 @@ static int gaim_handle_redirect(aim_session_t *sess, aim_frame_t *fr, ...) {  		ccon = g_new0(struct chat_connection, 1);  		ccon->conn = tstconn; -		ccon->gc = gc; +		ccon->ic = ic;  		ccon->fd = -1;  		ccon->name = g_strdup(redir->chat.room);  		ccon->exchange = redir->chat.exchange; @@ -955,49 +950,39 @@ static int gaim_handle_redirect(aim_session_t *sess, aim_frame_t *fr, ...) {  }  static int gaim_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...) { -	struct gaim_connection *gc = sess->aux_data; -	struct oscar_data *od = gc->proto_data; +	struct im_connection *ic = sess->aux_data; +	struct oscar_data *od = ic->proto_data;  	aim_userinfo_t *info;  	time_t time_idle = 0, signon = 0; -	int type = 0; -	int caps = 0; -	char *tmp; +	int flags = OPT_LOGGED_IN; +	char *tmp, *state_string = NULL;  	va_list ap;  	va_start(ap, fr);  	info = va_arg(ap, aim_userinfo_t *);  	va_end(ap); -	if (info->present & AIM_USERINFO_PRESENT_CAPABILITIES) -		caps = info->capabilities; -	if (info->flags & AIM_FLAG_ACTIVEBUDDY) -		type |= UC_AB; -  	if ((!od->icq) && (info->present & AIM_USERINFO_PRESENT_FLAGS)) { -		if (info->flags & AIM_FLAG_UNCONFIRMED) -			type |= UC_UNCONFIRMED; -		if (info->flags & AIM_FLAG_ADMINISTRATOR) -			type |= UC_ADMIN; -		if (info->flags & AIM_FLAG_AOL) -			type |= UC_AOL; -		if (info->flags & AIM_FLAG_FREE) -			type |= UC_NORMAL;  		if (info->flags & AIM_FLAG_AWAY) -			type |= UC_UNAVAILABLE; -		if (info->flags & AIM_FLAG_WIRELESS) -			type |= UC_WIRELESS; +			flags |= OPT_AWAY;  	} +	  	if (info->present & AIM_USERINFO_PRESENT_ICQEXTSTATUS) { -		type = (info->icqinfo.status << 7);  		if (!(info->icqinfo.status & AIM_ICQ_STATE_CHAT) &&  		      (info->icqinfo.status != AIM_ICQ_STATE_NORMAL)) { -			type |= UC_UNAVAILABLE; +			flags |= OPT_AWAY;  		} +		 +		if( info->icqinfo.status & AIM_ICQ_STATE_DND ) +			state_string = "Do Not Disturb"; +		else if( info->icqinfo.status & AIM_ICQ_STATE_OUT ) +			state_string = "Not Available"; +		else if( info->icqinfo.status & AIM_ICQ_STATE_BUSY ) +			state_string = "Occupied"; +		else if( info->icqinfo.status & AIM_ICQ_STATE_INVISIBLE ) +			state_string = "Invisible";  	} -	if (caps & AIM_CAPS_ICQ) -		caps ^= AIM_CAPS_ICQ; -  	if (info->present & AIM_USERINFO_PRESENT_IDLE) {  		time(&time_idle);  		time_idle -= info->idletime*60; @@ -1006,13 +991,23 @@ static int gaim_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...) {  	if (info->present & AIM_USERINFO_PRESENT_SESSIONLEN)  		signon = time(NULL) - info->sessionlen; -	tmp = g_strdup(normalize(gc->username)); +	if (info->present & AIM_USERINFO_PRESENT_ICQIPADDR) { +		uint32_t *uin = g_new0(uint32_t, 1); +		 +		if (od->ips == NULL) +			od->ips = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, NULL); +		 +		if (sscanf(info->sn, "%d", uin) == 1) +			g_hash_table_insert(od->ips, uin, (gpointer) (long) info->icqinfo.ipaddr); +	} + +	tmp = g_strdup(normalize(ic->acc->user));  	if (!strcmp(tmp, normalize(info->sn))) -		g_snprintf(gc->displayname, sizeof(gc->displayname), "%s", info->sn); +		g_snprintf(ic->displayname, sizeof(ic->displayname), "%s", info->sn);  	g_free(tmp); -	serv_got_update(gc, info->sn, 1, info->warnlevel/10, signon, -			time_idle, type, caps); +	imcb_buddy_status(ic, info->sn, flags, state_string, NULL); +	/* imcb_buddy_times(ic, info->sn, signon, time_idle); */  	return 1;  } @@ -1020,24 +1015,24 @@ static int gaim_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...) {  static int gaim_parse_offgoing(aim_session_t *sess, aim_frame_t *fr, ...) {  	aim_userinfo_t *info;  	va_list ap; -	struct gaim_connection *gc = sess->aux_data; +	struct im_connection *ic = sess->aux_data;  	va_start(ap, fr);  	info = va_arg(ap, aim_userinfo_t *);  	va_end(ap); -	serv_got_update(gc, info->sn, 0, 0, 0, 0, 0, 0); +	imcb_buddy_status(ic, info->sn, 0, NULL, NULL );  	return 1;  }  static int incomingim_chan1(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch1_args *args) {  	char *tmp = g_malloc(BUF_LONG + 1); -	struct gaim_connection *gc = sess->aux_data; +	struct im_connection *ic = sess->aux_data;  	int flags = 0;  	if (args->icbmflags & AIM_IMFLAGS_AWAY) -		flags |= IM_FLAG_AWAY; +		flags |= OPT_AWAY;  	if ((args->icbmflags & AIM_IMFLAGS_UNICODE) || (args->icbmflags & AIM_IMFLAGS_ISO_8859_1)) {  		char *src; @@ -1067,11 +1062,22 @@ static int incomingim_chan1(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_  		} else {  			g_snprintf(tmp, BUF_LONG, "%s", args->msg);  		} -	} else +	} else if (args->mpmsg.numparts == 0) {  		g_snprintf(tmp, BUF_LONG, "%s", args->msg); +	} else { +		aim_mpmsg_section_t *part; +		 +		*tmp = 0; +		for (part = args->mpmsg.parts; part; part = part->next) { +			if (part->data) { +				g_strlcat(tmp, (char*) part->data, BUF_LONG); +				g_strlcat(tmp, "\n", BUF_LONG); +			} +		} +	}  	strip_linefeed(tmp); -	serv_got_im(gc, userinfo->sn, tmp, flags, time(NULL), -1); +	imcb_buddy_msg(ic, userinfo->sn, tmp, flags, 0);  	g_free(tmp);  	return 1; @@ -1081,7 +1087,7 @@ void oscar_accept_chat(gpointer w, struct aim_chat_invitation * inv);  void oscar_reject_chat(gpointer w, struct aim_chat_invitation * inv);  static int incomingim_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args) { -	struct gaim_connection *gc = sess->aux_data; +	struct im_connection *ic = sess->aux_data;  	if (args->status != AIM_RENDEZVOUS_PROPOSE)  		return 1; @@ -1099,11 +1105,11 @@ static int incomingim_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_  		g_snprintf( txt, 1024, "Got an invitation to chatroom %s from %s: %s", name, userinfo->sn, args->msg ); -		inv->gc = gc; +		inv->ic = ic;  		inv->exchange = *exch;  		inv->name = g_strdup(name); -		do_ask_dialog( gc, txt, inv, oscar_accept_chat, oscar_reject_chat); +		imcb_ask( ic, txt, inv, oscar_accept_chat, oscar_reject_chat);  		if (name)  			g_free(name); @@ -1114,14 +1120,14 @@ static int incomingim_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_  static void gaim_icq_authgrant(gpointer w, struct icq_auth *data) {  	char *uin, message; -	struct oscar_data *od = (struct oscar_data *)data->gc->proto_data; +	struct oscar_data *od = (struct oscar_data *)data->ic->proto_data;  	uin = g_strdup_printf("%u", data->uin);  	message = 0;  	aim_ssi_auth_reply(od->sess, od->conn, uin, 1, "");  	// aim_send_im_ch4(od->sess, uin, AIM_ICQMSG_AUTHGRANTED, &message); -	if(find_buddy(data->gc, uin) == NULL) -		show_got_added(data->gc, uin, NULL); +	if(imcb_find_buddy(data->ic, uin) == NULL) +		imcb_ask_add(data->ic, uin, NULL);  	g_free(uin);  	g_free(data); @@ -1129,7 +1135,7 @@ static void gaim_icq_authgrant(gpointer w, struct icq_auth *data) {  static void gaim_icq_authdeny(gpointer w, struct icq_auth *data) {  	char *uin, *message; -	struct oscar_data *od = (struct oscar_data *)data->gc->proto_data; +	struct oscar_data *od = (struct oscar_data *)data->ic->proto_data;  	uin = g_strdup_printf("%u", data->uin);  	message = g_strdup_printf("No reason given."); @@ -1144,7 +1150,7 @@ static void gaim_icq_authdeny(gpointer w, struct icq_auth *data) {  /*   * For when other people ask you for authorization   */ -static void gaim_icq_authask(struct gaim_connection *gc, guint32 uin, char *msg) { +static void gaim_icq_authask(struct im_connection *ic, guint32 uin, char *msg) {  	struct icq_auth *data = g_new(struct icq_auth, 1);  	char *reason = NULL;  	char *dialog_msg; @@ -1153,14 +1159,14 @@ static void gaim_icq_authask(struct gaim_connection *gc, guint32 uin, char *msg)  		reason = msg + 6;  	dialog_msg = g_strdup_printf("The user %u wants to add you to their buddy list for the following reason: %s", uin, reason ? reason : "No reason given."); -	data->gc = gc; +	data->ic = ic;  	data->uin = uin; -	do_ask_dialog(gc, dialog_msg, data, gaim_icq_authgrant, gaim_icq_authdeny); +	imcb_ask(ic, dialog_msg, data, gaim_icq_authgrant, gaim_icq_authdeny);  	g_free(dialog_msg);  }  static int incomingim_chan4(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch4_args *args) { -	struct gaim_connection *gc = sess->aux_data; +	struct im_connection *ic = sess->aux_data;  	switch (args->type) {  		case 0x0001: { /* An almost-normal instant message.  Mac ICQ sends this.  It's peculiar. */ @@ -1168,7 +1174,7 @@ static int incomingim_chan4(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_  			uin = g_strdup_printf("%u", args->uin);  			message = g_strdup(args->msg);  			strip_linefeed(message); -			serv_got_im(gc, uin, message, 0, time(NULL), -1); +			imcb_buddy_msg(ic, uin, message, 0, 0);  			g_free(uin);  			g_free(message);  		} break; @@ -1187,22 +1193,22 @@ static int incomingim_chan4(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_  			}  			strip_linefeed(message); -			serv_got_im(gc, uin, message, 0, time(NULL), -1); +			imcb_buddy_msg(ic, uin, message, 0, 0);  			g_free(uin);  			g_free(m);  			g_free(message);  		} break;  		case 0x0006: { /* Someone requested authorization */ -			gaim_icq_authask(gc, args->uin, args->msg); +			gaim_icq_authask(ic, args->uin, args->msg);  		} break;  		case 0x0007: { /* Someone has denied you authorization */ -			serv_got_crap(sess->aux_data, "The user %u has denied your request to add them to your contact list for the following reason:\n%s", args->uin, args->msg ? args->msg : _("No reason given.") ); +			imcb_log(sess->aux_data, "The user %u has denied your request to add them to your contact list for the following reason:\n%s", args->uin, args->msg ? args->msg : _("No reason given.") );  		} break;  		case 0x0008: { /* Someone has granted you authorization */ -			serv_got_crap(sess->aux_data, "The user %u has granted your request to add them to your contact list for the following reason:\n%s", args->uin, args->msg ? args->msg : _("No reason given.") ); +			imcb_log(sess->aux_data, "The user %u has granted your request to add them to your contact list for the following reason:\n%s", args->uin, args->msg ? args->msg : _("No reason given.") );  		} break;  		case 0x0012: { @@ -1225,10 +1231,6 @@ static int gaim_parse_incoming_im(aim_session_t *sess, aim_frame_t *fr, ...) {  	channel = va_arg(ap, int);  	userinfo = va_arg(ap, aim_userinfo_t *); -    if (set_getint(sess->aux_data, "debug")) { -        serv_got_crap(sess->aux_data, "channel %i called", channel); -    } -  	switch (channel) {  		case 1: { /* standard message */  			struct aim_incomingim_ch1_args *args; @@ -1261,7 +1263,6 @@ static int gaim_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...) {  	va_list ap;  	guint16 chan, nummissed, reason;  	aim_userinfo_t *userinfo; -	char buf[1024];  	va_start(ap, fr);  	chan = (guint16)va_arg(ap, unsigned int); @@ -1273,8 +1274,7 @@ static int gaim_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...) {  	switch(reason) {  		case 0:  			/* Invalid (0) */ -			g_snprintf(buf, -				   sizeof(buf), +			imcb_error(sess->aux_data,  				   nummissed == 1 ?   				   _("You missed %d message from %s because it was invalid.") :  				   _("You missed %d messages from %s because they were invalid."), @@ -1283,8 +1283,7 @@ static int gaim_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...) {  			break;  		case 1:  			/* Message too large */ -			g_snprintf(buf, -				   sizeof(buf), +			imcb_error(sess->aux_data,  				   nummissed == 1 ?  				   _("You missed %d message from %s because it was too large.") :  				   _("You missed %d messages from %s because they were too large."), @@ -1293,8 +1292,7 @@ static int gaim_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...) {  			break;  		case 2:  			/* Rate exceeded */ -			g_snprintf(buf, -				   sizeof(buf), +			imcb_error(sess->aux_data,  				   nummissed == 1 ?   				   _("You missed %d message from %s because the rate limit has been exceeded.") :  				   _("You missed %d messages from %s because the rate limit has been exceeded."), @@ -1303,8 +1301,7 @@ static int gaim_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...) {  			break;  		case 3:  			/* Evil Sender */ -			g_snprintf(buf, -				   sizeof(buf), +			imcb_error(sess->aux_data,  				   nummissed == 1 ?  				   _("You missed %d message from %s because it was too evil.") :   				   _("You missed %d messages from %s because they are too evil."), @@ -1313,8 +1310,7 @@ static int gaim_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...) {  			break;  		case 4:  			/* Evil Receiver */ -			g_snprintf(buf, -				   sizeof(buf), +			imcb_error(sess->aux_data,  				   nummissed == 1 ?   				   _("You missed %d message from %s because you are too evil.") :  				   _("You missed %d messages from %s because you are too evil."), @@ -1322,8 +1318,7 @@ static int gaim_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...) {  				   userinfo->sn);  			break;  		default: -			g_snprintf(buf, -				   sizeof(buf), +			imcb_error(sess->aux_data,  				   nummissed == 1 ?   				   _("You missed %d message from %s for unknown reasons.") :  				   _("You missed %d messages from %s for unknown reasons."), @@ -1331,7 +1326,6 @@ static int gaim_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...) {  				   userinfo->sn);  			break;  	} -	do_error_dialog(sess->aux_data, buf, _("Gaim - Error"));  	return 1;  } @@ -1339,16 +1333,13 @@ static int gaim_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...) {  static int gaim_parse_genericerr(aim_session_t *sess, aim_frame_t *fr, ...) {  	va_list ap;  	guint16 reason; -	char *m;  	va_start(ap, fr);  	reason = (guint16)va_arg(ap, unsigned int);  	va_end(ap); -	m = g_strdup_printf(_("SNAC threw error: %s\n"), -			reason < msgerrreasonlen ? msgerrreason[reason] : "Unknown error"); -	do_error_dialog(sess->aux_data, m, _("Gaim - Oscar SNAC Error")); -	g_free(m); +	imcb_error(sess->aux_data, _("SNAC threw error: %s"), +	          reason < msgerrreasonlen ? msgerrreason[reason] : "Unknown error");  	return 1;  } @@ -1357,16 +1348,14 @@ static int gaim_parse_msgerr(aim_session_t *sess, aim_frame_t *fr, ...) {  	va_list ap;  	char *destn;  	guint16 reason; -	char buf[1024];  	va_start(ap, fr);  	reason = (guint16)va_arg(ap, unsigned int);  	destn = va_arg(ap, char *);  	va_end(ap); -	sprintf(buf, _("Your message to %s did not get sent: %s"), destn, +	imcb_error(sess->aux_data, _("Your message to %s did not get sent: %s"), destn,  			(reason < msgerrreasonlen) ? msgerrreason[reason] : _("Reason unknown")); -	do_error_dialog(sess->aux_data, buf, _("Gaim - Error"));  	return 1;  } @@ -1375,17 +1364,14 @@ static int gaim_parse_locerr(aim_session_t *sess, aim_frame_t *fr, ...) {  	va_list ap;  	char *destn;  	guint16 reason; -	char buf[1024];  	va_start(ap, fr);  	reason = (guint16)va_arg(ap, unsigned int);  	destn = va_arg(ap, char *);  	va_end(ap); -	sprintf(buf, _("User information for %s unavailable: %s"), destn, +	imcb_error(sess->aux_data, _("User information for %s unavailable: %s"), destn,  			(reason < msgerrreasonlen) ? msgerrreason[reason] : _("Reason unknown")); -	do_error_dialog(sess->aux_data, buf, _("Gaim - Error")); -  	return 1;  } @@ -1401,8 +1387,7 @@ static int gaim_parse_motd(aim_session_t *sess, aim_frame_t *fr, ...) {  	va_end(ap);  	if (id < 4) -		do_error_dialog(sess->aux_data, _("Your connection may be lost."), -				_("AOL error")); +		imcb_error(sess->aux_data, _("Your connection may be lost."));  	return 1;  } @@ -1410,8 +1395,8 @@ static int gaim_parse_motd(aim_session_t *sess, aim_frame_t *fr, ...) {  static int gaim_chatnav_info(aim_session_t *sess, aim_frame_t *fr, ...) {  	va_list ap;  	guint16 type; -	struct gaim_connection *gc = sess->aux_data; -	struct oscar_data *odata = (struct oscar_data *)gc->proto_data; +	struct im_connection *ic = sess->aux_data; +	struct oscar_data *odata = (struct oscar_data *)ic->proto_data;  	va_start(ap, fr);  	type = (guint16)va_arg(ap, unsigned int); @@ -1469,7 +1454,7 @@ static int gaim_chat_join(aim_session_t *sess, aim_frame_t *fr, ...) {  	va_list ap;  	int count, i;  	aim_userinfo_t *info; -	struct gaim_connection *g = sess->aux_data; +	struct im_connection *g = sess->aux_data;  	struct chat_connection *c = NULL; @@ -1483,7 +1468,7 @@ static int gaim_chat_join(aim_session_t *sess, aim_frame_t *fr, ...) {  		return 1;  	for (i = 0; i < count; i++) -		add_chat_buddy(c->cnv, info[i].sn); +		imcb_chat_add_buddy(c->cnv, info[i].sn);  	return 1;  } @@ -1492,7 +1477,7 @@ static int gaim_chat_leave(aim_session_t *sess, aim_frame_t *fr, ...) {  	va_list ap;  	int count, i;  	aim_userinfo_t *info; -	struct gaim_connection *g = sess->aux_data; +	struct im_connection *g = sess->aux_data;  	struct chat_connection *c = NULL; @@ -1506,7 +1491,7 @@ static int gaim_chat_leave(aim_session_t *sess, aim_frame_t *fr, ...) {  		return 1;  	for (i = 0; i < count; i++) -		remove_chat_buddy(c->cnv, info[i].sn, NULL); +		imcb_chat_remove_buddy(c->cnv, info[i].sn, NULL);  	return 1;  } @@ -1520,8 +1505,8 @@ static int gaim_chat_info_update(aim_session_t *sess, aim_frame_t *fr, ...) {  	char *roomdesc;  	guint16 unknown_c9, unknown_d2, unknown_d5, maxmsglen, maxvisiblemsglen;  	guint32 creationtime; -	struct gaim_connection *gc = sess->aux_data; -	struct chat_connection *ccon = find_oscar_chat_by_conn(gc, fr->conn); +	struct im_connection *ic = sess->aux_data; +	struct chat_connection *ccon = find_oscar_chat_by_conn(ic, fr->conn);  	va_start(ap, fr);  	roominfo = va_arg(ap, struct aim_chat_roominfo *); @@ -1547,8 +1532,8 @@ static int gaim_chat_incoming_msg(aim_session_t *sess, aim_frame_t *fr, ...) {  	va_list ap;  	aim_userinfo_t *info;  	char *msg; -	struct gaim_connection *gc = sess->aux_data; -	struct chat_connection *ccon = find_oscar_chat_by_conn(gc, fr->conn); +	struct im_connection *ic = sess->aux_data; +	struct chat_connection *ccon = find_oscar_chat_by_conn(ic, fr->conn);  	char *tmp;  	va_start(ap, fr); @@ -1557,7 +1542,7 @@ static int gaim_chat_incoming_msg(aim_session_t *sess, aim_frame_t *fr, ...) {  	tmp = g_malloc(BUF_LONG);  	g_snprintf(tmp, BUF_LONG, "%s", msg); -	serv_got_chat_in(gc, ccon->id, info->sn, 0, tmp, time((time_t)NULL)); +	imcb_chat_msg(ccon->cnv, info->sn, tmp, 0, 0);  	g_free(tmp);  	return 1; @@ -1596,8 +1581,8 @@ static int gaim_parse_ratechange(aim_session_t *sess, aim_frame_t *fr, ...) {  	} else if (code == AIM_RATE_CODE_WARNING) {  		aim_conn_setlatency(fr->conn, windowsize/4);  	} else if (code == AIM_RATE_CODE_LIMIT) { -		do_error_dialog(sess->aux_data, _("The last message was not sent because you are over the rate limit. " -				  "Please wait 10 seconds and try again."), _("Gaim - Error")); +		imcb_error(sess->aux_data, _("The last message was not sent because you are over the rate limit. " +			  "Please wait 10 seconds and try again."));  		aim_conn_setlatency(fr->conn, windowsize/2);  	} else if (code == AIM_RATE_CODE_CLEARLIMIT) {  		aim_conn_setlatency(fr->conn, 0); @@ -1609,14 +1594,14 @@ static int gaim_parse_ratechange(aim_session_t *sess, aim_frame_t *fr, ...) {  static int gaim_selfinfo(aim_session_t *sess, aim_frame_t *fr, ...) {  	va_list ap;  	aim_userinfo_t *info; -	struct gaim_connection *gc = sess->aux_data; +	struct im_connection *ic = sess->aux_data;  	va_start(ap, fr);  	info = va_arg(ap, aim_userinfo_t *);  	va_end(ap); -	gc->evil = info->warnlevel/10; -	/* gc->correction_time = (info->onlinesince - gc->login_time); */ +	ic->evil = info->warnlevel/10; +	/* ic->correction_time = (info->onlinesince - ic->login_time); */  	return 1;  } @@ -1638,8 +1623,8 @@ static int conninitdone_bos(aim_session_t *sess, aim_frame_t *fr, ...) {  }  static int conninitdone_admin(aim_session_t *sess, aim_frame_t *fr, ...) { -	struct gaim_connection *gc = sess->aux_data; -	struct oscar_data *od = gc->proto_data; +	struct im_connection *ic = sess->aux_data; +	struct oscar_data *od = ic->proto_data;  	aim_clientready(sess, fr->conn); @@ -1696,8 +1681,8 @@ static int gaim_parse_locaterights(aim_session_t *sess, aim_frame_t *fr, ...)  {  	va_list ap;  	guint16 maxsiglen; -	struct gaim_connection *gc = sess->aux_data; -	struct oscar_data *odata = (struct oscar_data *)gc->proto_data; +	struct im_connection *ic = sess->aux_data; +	struct oscar_data *odata = (struct oscar_data *)ic->proto_data;  	va_start(ap, fr);  	maxsiglen = va_arg(ap, int); @@ -1705,16 +1690,19 @@ static int gaim_parse_locaterights(aim_session_t *sess, aim_frame_t *fr, ...)  	odata->rights.maxsiglen = odata->rights.maxawaymsglen = (guint)maxsiglen; -	aim_bos_setprofile(sess, fr->conn, gc->user->user_info, NULL, gaim_caps); - +	/* FIXME: It seems we're not really using this, and it broke now that +	   struct aim_user is dead. +	aim_bos_setprofile(sess, fr->conn, ic->user->user_info, NULL, gaim_caps); +	*/ +	  	return 1;  }  static int gaim_parse_buddyrights(aim_session_t *sess, aim_frame_t *fr, ...) {  	va_list ap;  	guint16 maxbuddies, maxwatchers; -	struct gaim_connection *gc = sess->aux_data; -	struct oscar_data *odata = (struct oscar_data *)gc->proto_data; +	struct im_connection *ic = sess->aux_data; +	struct oscar_data *odata = (struct oscar_data *)ic->proto_data;  	va_start(ap, fr);  	maxbuddies = (guint16)va_arg(ap, unsigned int); @@ -1730,8 +1718,8 @@ static int gaim_parse_buddyrights(aim_session_t *sess, aim_frame_t *fr, ...) {  static int gaim_bosrights(aim_session_t *sess, aim_frame_t *fr, ...) {  	guint16 maxpermits, maxdenies;  	va_list ap; -	struct gaim_connection *gc = sess->aux_data; -	struct oscar_data *odata = (struct oscar_data *)gc->proto_data; +	struct im_connection *ic = sess->aux_data; +	struct oscar_data *odata = (struct oscar_data *)ic->proto_data;  	va_start(ap, fr);  	maxpermits = (guint16)va_arg(ap, unsigned int); @@ -1754,7 +1742,7 @@ static int gaim_bosrights(aim_session_t *sess, aim_frame_t *fr, ...) {  static int gaim_offlinemsg(aim_session_t *sess, aim_frame_t *fr, ...) {  	va_list ap;  	struct aim_icq_offlinemsg *msg; -	struct gaim_connection *gc = sess->aux_data; +	struct im_connection *ic = sess->aux_data;  	va_start(ap, fr);  	msg = va_arg(ap, struct aim_icq_offlinemsg *); @@ -1767,7 +1755,7 @@ static int gaim_offlinemsg(aim_session_t *sess, aim_frame_t *fr, ...) {  			time_t t = get_time(msg->year, msg->month, msg->day, msg->hour, msg->minute, 0);  			g_snprintf(sender, sizeof(sender), "%u", msg->sender);  			strip_linefeed(dialog_msg); -			serv_got_im(gc, sender, dialog_msg, 0, t, -1); +			imcb_buddy_msg(ic, sender, dialog_msg, 0, t);  			g_free(dialog_msg);  		} break; @@ -1788,21 +1776,21 @@ static int gaim_offlinemsg(aim_session_t *sess, aim_frame_t *fr, ...) {  			}  			strip_linefeed(dialog_msg); -			serv_got_im(gc, sender, dialog_msg, 0, t, -1); +			imcb_buddy_msg(ic, sender, dialog_msg, 0, t);  			g_free(dialog_msg);  			g_free(m);  		} break;  		case 0x0006: { /* Authorization request */ -			gaim_icq_authask(gc, msg->sender, msg->msg); +			gaim_icq_authask(ic, msg->sender, msg->msg);  		} break;  		case 0x0007: { /* Someone has denied you authorization */ -			serv_got_crap(sess->aux_data, "The user %u has denied your request to add them to your contact list for the following reason:\n%s", msg->sender, msg->msg ? msg->msg : _("No reason given.") ); +			imcb_log(sess->aux_data, "The user %u has denied your request to add them to your contact list for the following reason:\n%s", msg->sender, msg->msg ? msg->msg : _("No reason given.") );  		} break;  		case 0x0008: { /* Someone has granted you authorization */ -			serv_got_crap(sess->aux_data, "The user %u has granted your request to add them to your contact list for the following reason:\n%s", msg->sender, msg->msg ? msg->msg : _("No reason given.") ); +			imcb_log(sess->aux_data, "The user %u has granted your request to add them to your contact list for the following reason:\n%s", msg->sender, msg->msg ? msg->msg : _("No reason given.") );  		} break;  		case 0x0012: { @@ -1822,15 +1810,15 @@ static int gaim_offlinemsgdone(aim_session_t *sess, aim_frame_t *fr, ...)  	return 1;  } -static void oscar_keepalive(struct gaim_connection *gc) { -	struct oscar_data *odata = (struct oscar_data *)gc->proto_data; +static void oscar_keepalive(struct im_connection *ic) { +	struct oscar_data *odata = (struct oscar_data *)ic->proto_data;  	aim_flap_nop(odata->sess, odata->conn);  } -static int oscar_send_im(struct gaim_connection *gc, char *name, char *message, int len, int imflags) { -	struct oscar_data *odata = (struct oscar_data *)gc->proto_data; -	int ret = 0; -	if (imflags & IM_FLAG_AWAY) { +static int oscar_buddy_msg(struct im_connection *ic, char *name, char *message, int imflags) { +	struct oscar_data *odata = (struct oscar_data *)ic->proto_data; +	int ret = 0, len = strlen(message); +	if (imflags & OPT_AWAY) {  		ret = aim_send_im(odata->sess, name, AIM_IMFLAGS_AWAY, message);  	} else {  		struct aim_sendimext_args args; @@ -1881,7 +1869,7 @@ static int oscar_send_im(struct gaim_connection *gc, char *name, char *message,  	return ret;  } -static void oscar_get_info(struct gaim_connection *g, char *name) { +static void oscar_get_info(struct im_connection *g, char *name) {  	struct oscar_data *odata = (struct oscar_data *)g->proto_data;  	if (odata->icq)  		aim_icq_getallinfo(odata->sess, name); @@ -1891,10 +1879,10 @@ static void oscar_get_info(struct gaim_connection *g, char *name) {  	}  } -static void oscar_get_away(struct gaim_connection *g, char *who) { +static void oscar_get_away(struct im_connection *g, char *who) {  	struct oscar_data *odata = (struct oscar_data *)g->proto_data;  	if (odata->icq) { -		struct buddy *budlight = find_buddy(g, who); +		struct buddy *budlight = imcb_find_buddy(g, who);  		if (budlight)  			if ((budlight->uc & 0xff80) >> 7)  				if (budlight->caps & AIM_CAPS_ICQSERVERRELAY) @@ -1903,7 +1891,7 @@ static void oscar_get_away(struct gaim_connection *g, char *who) {  		aim_getinfo(odata->sess, odata->conn, who, AIM_GETINFO_AWAYMESSAGE);  } -static void oscar_set_away_aim(struct gaim_connection *gc, struct oscar_data *od, const char *state, const char *message) +static void oscar_set_away_aim(struct im_connection *ic, struct oscar_data *od, const char *state, const char *message)  {  	if (!g_strcasecmp(state, _("Visible"))) { @@ -1915,13 +1903,13 @@ static void oscar_set_away_aim(struct gaim_connection *gc, struct oscar_data *od  	} /* else... */  	if (od->rights.maxawaymsglen == 0) -		do_error_dialog(gc, "oscar_set_away_aim called before locate rights received", "Protocol Error"); +		imcb_error(ic, "oscar_set_away_aim called before locate rights received");  	aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_NORMAL); -	if (gc->away) -		g_free(gc->away); -	gc->away = NULL; +	if (ic->away) +		g_free(ic->away); +	ic->away = NULL;  	if (!message) {  		aim_bos_setprofile(od->sess, od->conn, NULL, "", gaim_caps); @@ -1929,30 +1917,24 @@ static void oscar_set_away_aim(struct gaim_connection *gc, struct oscar_data *od  	}  	if (strlen(message) > od->rights.maxawaymsglen) { -		gchar *errstr; - -		errstr = g_strdup_printf("Maximum away message length of %d bytes exceeded, truncating", od->rights.maxawaymsglen); - -		do_error_dialog(gc, errstr, "Away Message Too Long"); - -		g_free(errstr); +		imcb_error(ic, "Maximum away message length of %d bytes exceeded, truncating", od->rights.maxawaymsglen);  	} -	gc->away = g_strndup(message, od->rights.maxawaymsglen); -	aim_bos_setprofile(od->sess, od->conn, NULL, gc->away, gaim_caps); +	ic->away = g_strndup(message, od->rights.maxawaymsglen); +	aim_bos_setprofile(od->sess, od->conn, NULL, ic->away, gaim_caps);  	return;  } -static void oscar_set_away_icq(struct gaim_connection *gc, struct oscar_data *od, const char *state, const char *message) +static void oscar_set_away_icq(struct im_connection *ic, struct oscar_data *od, const char *state, const char *message)  {      const char *msg = NULL;  	gboolean no_message = FALSE;  	/* clean old states */ -    if (gc->away) { -		g_free(gc->away); -		gc->away = NULL; +    if (ic->away) { +		g_free(ic->away); +		ic->away = NULL;      }  	od->sess->aim_icq_state = 0; @@ -1968,33 +1950,33 @@ static void oscar_set_away_icq(struct gaim_connection *gc, struct oscar_data *od  		aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_NORMAL);  	} else if (!g_strcasecmp(state, "Away")) {  		aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_AWAY); -        gc->away = g_strdup(msg); +        ic->away = g_strdup(msg);  		od->sess->aim_icq_state = AIM_MTYPE_AUTOAWAY;  	} else if (!g_strcasecmp(state, "Do Not Disturb")) {  		aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_DND | AIM_ICQ_STATE_BUSY); -        gc->away = g_strdup(msg); +        ic->away = g_strdup(msg);  		od->sess->aim_icq_state = AIM_MTYPE_AUTODND;  	} else if (!g_strcasecmp(state, "Not Available")) {  		aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_OUT | AIM_ICQ_STATE_AWAY); -        gc->away = g_strdup(msg); +        ic->away = g_strdup(msg);  		od->sess->aim_icq_state = AIM_MTYPE_AUTONA;  	} else if (!g_strcasecmp(state, "Occupied")) {  		aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_BUSY); -        gc->away = g_strdup(msg); +        ic->away = g_strdup(msg);  		od->sess->aim_icq_state = AIM_MTYPE_AUTOBUSY;  	} else if (!g_strcasecmp(state, "Free For Chat")) {  		aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_CHAT); -        gc->away = g_strdup(msg); +        ic->away = g_strdup(msg);  		od->sess->aim_icq_state = AIM_MTYPE_AUTOFFC;  	} else if (!g_strcasecmp(state, "Invisible")) {  		aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_INVISIBLE); -        gc->away = g_strdup(msg); +        ic->away = g_strdup(msg);  	} else if (!g_strcasecmp(state, GAIM_AWAY_CUSTOM)) {  	 	if (no_message) {  			aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_NORMAL);  		} else {  			aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_AWAY); -            gc->away = g_strdup(msg); +            ic->away = g_strdup(msg);  			od->sess->aim_icq_state = AIM_MTYPE_AUTOAWAY;  		}  	} @@ -2002,23 +1984,23 @@ static void oscar_set_away_icq(struct gaim_connection *gc, struct oscar_data *od  	return;  } -static void oscar_set_away(struct gaim_connection *gc, char *state, char *message) +static void oscar_set_away(struct im_connection *ic, char *state, char *message)  { -	struct oscar_data *od = (struct oscar_data *)gc->proto_data; +	struct oscar_data *od = (struct oscar_data *)ic->proto_data; -    oscar_set_away_aim(gc, od, state, message); +    oscar_set_away_aim(ic, od, state, message);  	if (od->icq) -		oscar_set_away_icq(gc, od, state, message); +		oscar_set_away_icq(ic, od, state, message);  	return;  } -static void oscar_add_buddy(struct gaim_connection *g, char *name) { +static void oscar_add_buddy(struct im_connection *g, char *name, char *group) {  	struct oscar_data *odata = (struct oscar_data *)g->proto_data;  	aim_ssi_addbuddies(odata->sess, odata->conn, OSCAR_GROUP, &name, 1, 0);  } -static void oscar_remove_buddy(struct gaim_connection *g, char *name, char *group) { +static void oscar_remove_buddy(struct im_connection *g, char *name, char *group) {  	struct oscar_data *odata = (struct oscar_data *)g->proto_data;  	struct aim_ssi_item *ssigroup;  	while ((ssigroup = aim_ssi_itemlist_findparent(odata->sess->ssi.items, name)) && !aim_ssi_delbuddies(odata->sess, odata->conn, ssigroup->name, &name, 1)); @@ -2029,7 +2011,7 @@ static int gaim_ssi_parserights(aim_session_t *sess, aim_frame_t *fr, ...) {  }  static int gaim_ssi_parselist(aim_session_t *sess, aim_frame_t *fr, ...) { -	struct gaim_connection *gc = sess->aux_data; +	struct im_connection *ic = sess->aux_data;  	struct aim_ssi_item *curitem;  	int tmp; @@ -2038,27 +2020,30 @@ static int gaim_ssi_parselist(aim_session_t *sess, aim_frame_t *fr, ...) {  	for (curitem=sess->ssi.items; curitem; curitem=curitem->next) {  		switch (curitem->type) {  			case 0x0000: /* Buddy */ -				if ((curitem->name) && (!find_buddy(gc, curitem->name))) { +				if ((curitem->name) && (!imcb_find_buddy(ic, curitem->name))) {  					char *realname = NULL;  					if (curitem->data && aim_gettlv(curitem->data, 0x0131, 1))  						    realname = aim_gettlv_str(curitem->data, 0x0131, 1); -					add_buddy(gc, NULL, curitem->name, realname); +					imcb_add_buddy(ic, curitem->name, NULL); -					if (realname) -					    g_free(realname); +					if (realname) { +						imcb_buddy_nick_hint(ic, curitem->name, realname); +						imcb_rename_buddy(ic, curitem->name, realname); +						g_free(realname); +					}  				}  				break;  			case 0x0002: /* Permit buddy */  				if (curitem->name) {  					GSList *list; -					for (list=gc->permit; (list && aim_sncmp(curitem->name, list->data)); list=list->next); +					for (list=ic->permit; (list && aim_sncmp(curitem->name, list->data)); list=list->next);  					if (!list) {  						char *name;  						name = g_strdup(normalize(curitem->name)); -						gc->permit = g_slist_append(gc->permit, name); +						ic->permit = g_slist_append(ic->permit, name);  						tmp++;  					}  				} @@ -2067,11 +2052,11 @@ static int gaim_ssi_parselist(aim_session_t *sess, aim_frame_t *fr, ...) {  			case 0x0003: /* Deny buddy */  				if (curitem->name) {  					GSList *list; -					for (list=gc->deny; (list && aim_sncmp(curitem->name, list->data)); list=list->next); +					for (list=ic->deny; (list && aim_sncmp(curitem->name, list->data)); list=list->next);  					if (!list) {  						char *name;  						name = g_strdup(normalize(curitem->name)); -						gc->deny = g_slist_append(gc->deny, name); +						ic->deny = g_slist_append(ic->deny, name);  						tmp++;  					}  				} @@ -2080,8 +2065,8 @@ static int gaim_ssi_parselist(aim_session_t *sess, aim_frame_t *fr, ...) {  			case 0x0004: /* Permit/deny setting */  				if (curitem->data) {  					guint8 permdeny; -					if ((permdeny = aim_ssi_getpermdeny(sess->ssi.items)) && (permdeny != gc->permdeny)) { -						gc->permdeny = permdeny; +					if ((permdeny = aim_ssi_getpermdeny(sess->ssi.items)) && (permdeny != ic->permdeny)) { +						ic->permdeny = permdeny;  						tmp++;  					}  				} @@ -2099,7 +2084,7 @@ static int gaim_ssi_parselist(aim_session_t *sess, aim_frame_t *fr, ...) {  	aim_icq_reqofflinemsgs(sess);  	/* Now that we have a buddy list, we can tell BitlBee that we're online. */ -	account_online(gc); +	imcb_connected(ic);  	return 1;  } @@ -2121,7 +2106,7 @@ static int gaim_ssi_parseack( aim_session_t *sess, aim_frame_t *fr, ... )  		if( count & 1 )  		{  			/* Hmm, the length should be even... */ -			do_error_dialog( sess->aux_data, "Received SSI ACK package with non-even length", "Gaim - Error" ); +			imcb_error( sess->aux_data, "Received SSI ACK package with non-even length");  			return( 0 );  		}  		count >>= 1; @@ -2130,13 +2115,21 @@ static int gaim_ssi_parseack( aim_session_t *sess, aim_frame_t *fr, ... )  		for( i = 0; i < count; i ++ )  		{  			st = aimbs_get16( &fr->data ); -			if( st == 0x0E ) +			if( st == 0x00 ) +			{ +				imcb_add_buddy( sess->aux_data, list, NULL ); +			} +			else if( st == 0x0E )  			{ -				serv_got_crap( sess->aux_data, "Buddy %s can't be added without authorization, requesting authorization", list ); +				imcb_log( sess->aux_data, "Buddy %s can't be added without authorization, requesting authorization", list );  				aim_ssi_auth_request( sess, fr->conn, list, "" );  				aim_ssi_addbuddies( sess, fr->conn, OSCAR_GROUP, &list, 1, 1 );  			} +			else +			{ +				imcb_error( sess->aux_data, "Error while adding buddy: 0x%04x", st ); +			}  			list += strlen( list ) + 1;  		}  	} @@ -2144,22 +2137,22 @@ static int gaim_ssi_parseack( aim_session_t *sess, aim_frame_t *fr, ... )  	return( 1 );  } -static void oscar_set_permit_deny(struct gaim_connection *gc) { -	struct oscar_data *od = (struct oscar_data *)gc->proto_data; +static void oscar_set_permit_deny(struct im_connection *ic) { +	struct oscar_data *od = (struct oscar_data *)ic->proto_data;  	if (od->icq) {  		GSList *list;  		char buf[MAXMSGLEN];  		int at; -		switch(gc->permdeny) { +		switch(ic->permdeny) {  		case 1: -			aim_bos_changevisibility(od->sess, od->conn, AIM_VISIBILITYCHANGE_DENYADD, gc->username); +			aim_bos_changevisibility(od->sess, od->conn, AIM_VISIBILITYCHANGE_DENYADD, ic->acc->user);  			break;  		case 2: -			aim_bos_changevisibility(od->sess, od->conn, AIM_VISIBILITYCHANGE_PERMITADD, gc->username); +			aim_bos_changevisibility(od->sess, od->conn, AIM_VISIBILITYCHANGE_PERMITADD, ic->acc->user);  			break;  		case 3: -			list = gc->permit; +			list = ic->permit;  			at = 0;  			while (list) {  				at += g_snprintf(buf + at, sizeof(buf) - at, "%s&", (char *)list->data); @@ -2168,7 +2161,7 @@ static void oscar_set_permit_deny(struct gaim_connection *gc) {  			aim_bos_changevisibility(od->sess, od->conn, AIM_VISIBILITYCHANGE_PERMITADD, buf);  			break;  		case 4: -			list = gc->deny; +			list = ic->deny;  			at = 0;  			while (list) {  				at += g_snprintf(buf + at, sizeof(buf) - at, "%s&", (char *)list->data); @@ -2179,15 +2172,14 @@ static void oscar_set_permit_deny(struct gaim_connection *gc) {  			default:  			break;  		} -		signoff_blocked(gc);  	} else {  		if (od->sess->ssi.received_data) -			aim_ssi_setpermdeny(od->sess, od->conn, gc->permdeny, 0xffffffff); +			aim_ssi_setpermdeny(od->sess, od->conn, ic->permdeny, 0xffffffff);  	}  } -static void oscar_add_permit(struct gaim_connection *gc, char *who) { -	struct oscar_data *od = (struct oscar_data *)gc->proto_data; +static void oscar_add_permit(struct im_connection *ic, char *who) { +	struct oscar_data *od = (struct oscar_data *)ic->proto_data;  	if (od->icq) {  		aim_ssi_auth_reply(od->sess, od->conn, who, 1, "");  	} else { @@ -2196,8 +2188,8 @@ static void oscar_add_permit(struct gaim_connection *gc, char *who) {  	}  } -static void oscar_add_deny(struct gaim_connection *gc, char *who) { -	struct oscar_data *od = (struct oscar_data *)gc->proto_data; +static void oscar_add_deny(struct im_connection *ic, char *who) { +	struct oscar_data *od = (struct oscar_data *)ic->proto_data;  	if (od->icq) {  		aim_ssi_auth_reply(od->sess, od->conn, who, 0, "");  	} else { @@ -2206,25 +2198,25 @@ static void oscar_add_deny(struct gaim_connection *gc, char *who) {  	}  } -static void oscar_rem_permit(struct gaim_connection *gc, char *who) { -	struct oscar_data *od = (struct oscar_data *)gc->proto_data; +static void oscar_rem_permit(struct im_connection *ic, char *who) { +	struct oscar_data *od = (struct oscar_data *)ic->proto_data;  	if (!od->icq) {  		if (od->sess->ssi.received_data)  			aim_ssi_delpord(od->sess, od->conn, &who, 1, AIM_SSI_TYPE_PERMIT);  	}  } -static void oscar_rem_deny(struct gaim_connection *gc, char *who) { -	struct oscar_data *od = (struct oscar_data *)gc->proto_data; +static void oscar_rem_deny(struct im_connection *ic, char *who) { +	struct oscar_data *od = (struct oscar_data *)ic->proto_data;  	if (!od->icq) {  		if (od->sess->ssi.received_data)  			aim_ssi_delpord(od->sess, od->conn, &who, 1, AIM_SSI_TYPE_DENY);  	}  } -static GList *oscar_away_states(struct gaim_connection *gc) +static GList *oscar_away_states(struct im_connection *ic)  { -	struct oscar_data *od = gc->proto_data; +	struct oscar_data *od = ic->proto_data;  	GList *m = NULL;  	if (!od->icq) @@ -2243,86 +2235,94 @@ static GList *oscar_away_states(struct gaim_connection *gc)  static int gaim_icqinfo(aim_session_t *sess, aim_frame_t *fr, ...)  { -        struct gaim_connection *gc = sess->aux_data; -        gchar who[16]; -        GString *str; -        va_list ap; -        struct aim_icq_info *info; - -        va_start(ap, fr); -        info = va_arg(ap, struct aim_icq_info *); -        va_end(ap); - -        if (!info->uin) -                return 0; - -        str = g_string_sized_new(100); -        g_snprintf(who, sizeof(who), "%u", info->uin); - -        g_string_sprintfa(str, "%s: %s - %s: %s", _("UIN"), who, _("Nick"),  -				info->nick ? info->nick : "-"); -        info_string_append(str, "\n", _("First Name"), info->first); -        info_string_append(str, "\n", _("Last Name"), info->last); -		info_string_append(str, "\n", _("Email Address"), info->email); -        if (info->numaddresses && info->email2) { -                int i; -                for (i = 0; i < info->numaddresses; i++) { -					info_string_append(str, "\n", _("Email Address"), info->email2[i]); -                } -        } -        info_string_append(str, "\n", _("Mobile Phone"), info->mobile); -        info_string_append(str, "\n", _("Gender"), info->gender==1 ? _("Female") : _("Male")); -        if (info->birthyear || info->birthmonth || info->birthday) { -                char date[30]; -                struct tm tm; -                tm.tm_mday = (int)info->birthday; -                tm.tm_mon = (int)info->birthmonth-1; -                tm.tm_year = (int)info->birthyear%100; -                strftime(date, sizeof(date), "%Y-%m-%d", &tm); -                info_string_append(str, "\n", _("Birthday"), date); -        } -        if (info->age) { -                char age[5]; -                g_snprintf(age, sizeof(age), "%hhd", info->age); -                info_string_append(str, "\n", _("Age"), age); -        } -		info_string_append(str, "\n", _("Personal Web Page"), info->personalwebpage); -        if (info->info && info->info[0]) { -                g_string_sprintfa(str, "\n%s:\n%s\n%s", _("Additional Information"),  -						info->info, _("End of Additional Information")); -        } -        g_string_sprintfa(str, "\n"); -        if ((info->homeaddr && (info->homeaddr[0])) || (info->homecity && info->homecity[0]) || (info->homestate && info->homestate[0]) || (info->homezip && info->homezip[0])) { -                g_string_sprintfa(str, "%s:", _("Home Address")); -                info_string_append(str, "\n", _("Address"), info->homeaddr); -                info_string_append(str, "\n", _("City"), info->homecity); -                info_string_append(str, "\n", _("State"), info->homestate);  -				info_string_append(str, "\n", _("Zip Code"), info->homezip); -                g_string_sprintfa(str, "\n"); -        } -        if ((info->workaddr && info->workaddr[0]) || (info->workcity && info->workcity[0]) || (info->workstate && info->workstate[0]) || (info->workzip && info->workzip[0])) { -                g_string_sprintfa(str, "%s:", _("Work Address")); -                info_string_append(str, "\n", _("Address"), info->workaddr); -                info_string_append(str, "\n", _("City"), info->workcity); -                info_string_append(str, "\n", _("State"), info->workstate); -				info_string_append(str, "\n", _("Zip Code"), info->workzip); -                g_string_sprintfa(str, "\n"); -        } -        if ((info->workcompany && info->workcompany[0]) || (info->workdivision && info->workdivision[0]) || (info->workposition && info->workposition[0]) || (info->workwebpage && info->workwebpage[0])) { -                g_string_sprintfa(str, "%s:", _("Work Information")); -                info_string_append(str, "\n", _("Company"), info->workcompany); -                info_string_append(str, "\n", _("Division"), info->workdivision); -                info_string_append(str, "\n", _("Position"), info->workposition); -                if (info->workwebpage && info->workwebpage[0]) { -                        info_string_append(str, "\n", _("Web Page"), info->workwebpage); -                } -                g_string_sprintfa(str, "\n"); -        } - -		serv_got_crap(gc, "%s\n%s", _("User Info"), str->str); -        g_string_free(str, TRUE); - -        return 1; +	struct im_connection *ic = sess->aux_data; +	struct oscar_data *od = ic->proto_data; +	gchar who[16]; +	GString *str; +	va_list ap; +	struct aim_icq_info *info; +	uint32_t ip; + +	va_start(ap, fr); +	info = va_arg(ap, struct aim_icq_info *); +	va_end(ap); + +	if (!info->uin) +		return 0; + +	str = g_string_sized_new(512); +	g_snprintf(who, sizeof(who), "%u", info->uin); + +	g_string_printf(str, "%s: %s - %s: %s", _("UIN"), who, _("Nick"),  +	info->nick ? info->nick : "-"); +	g_string_append_printf(str, "\n%s: %s", _("First Name"), info->first); +	g_string_append_printf(str, "\n%s: %s", _("Last Name"), info->last); +	g_string_append_printf(str, "\n%s: %s", _("Email Address"), info->email); +	if (info->numaddresses && info->email2) { +		int i; +		for (i = 0; i < info->numaddresses; i++) { +			g_string_append_printf(str, "\n%s: %s", _("Email Address"), info->email2[i]); +		} +	} +	if ((ip = (long) g_hash_table_lookup(od->ips, &info->uin)) != 0) { +		g_string_append_printf(str, "\n%s: %d.%d.%d.%d", _("Last used IP address"), +		                       (ip >> 24), (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff); +	} +	g_string_append_printf(str, "\n%s: %s", _("Mobile Phone"), info->mobile); +	if (info->gender != 0) +		g_string_append_printf(str, "\n%s: %s", _("Gender"), info->gender==1 ? _("Female") : _("Male")); +	if (info->birthyear || info->birthmonth || info->birthday) { +		char date[30]; +		struct tm tm; +		memset(&tm, 0, sizeof(struct tm)); +		tm.tm_mday = (int)info->birthday; +		tm.tm_mon = (int)info->birthmonth-1; +		tm.tm_year = (int)info->birthyear%100; +		strftime(date, sizeof(date), "%Y-%m-%d", &tm); +		g_string_append_printf(str, "\n%s: %s", _("Birthday"), date); +	} +	if (info->age) { +		char age[5]; +		g_snprintf(age, sizeof(age), "%hhd", info->age); +		g_string_append_printf(str, "\n%s: %s", _("Age"), age); +	} +	g_string_append_printf(str, "\n%s: %s", _("Personal Web Page"), info->personalwebpage); +	if (info->info && info->info[0]) { +		g_string_sprintfa(str, "\n%s:\n%s\n%s", _("Additional Information"),  +		info->info, _("End of Additional Information")); +	} +	g_string_append_c(str, '\n'); +	if ((info->homeaddr && (info->homeaddr[0])) || (info->homecity && info->homecity[0]) || (info->homestate && info->homestate[0]) || (info->homezip && info->homezip[0])) { +		g_string_append_printf(str, "%s:", _("Home Address")); +		g_string_append_printf(str, "\n%s: %s", _("Address"), info->homeaddr); +		g_string_append_printf(str, "\n%s: %s", _("City"), info->homecity); +		g_string_append_printf(str, "\n%s: %s", _("State"), info->homestate);  +		g_string_append_printf(str, "\n%s: %s", _("Zip Code"), info->homezip); +		g_string_append_c(str, '\n'); +	} +	if ((info->workaddr && info->workaddr[0]) || (info->workcity && info->workcity[0]) || (info->workstate && info->workstate[0]) || (info->workzip && info->workzip[0])) { +		g_string_append_printf(str, "%s:", _("Work Address")); +		g_string_append_printf(str, "\n%s: %s", _("Address"), info->workaddr); +		g_string_append_printf(str, "\n%s: %s", _("City"), info->workcity); +		g_string_append_printf(str, "\n%s: %s", _("State"), info->workstate); +		g_string_append_printf(str, "\n%s: %s", _("Zip Code"), info->workzip); +		g_string_append_c(str, '\n'); +	} +	if ((info->workcompany && info->workcompany[0]) || (info->workdivision && info->workdivision[0]) || (info->workposition && info->workposition[0]) || (info->workwebpage && info->workwebpage[0])) { +		g_string_append_printf(str, "%s:", _("Work Information")); +		g_string_append_printf(str, "\n%s: %s", _("Company"), info->workcompany); +		g_string_append_printf(str, "\n%s: %s", _("Division"), info->workdivision); +		g_string_append_printf(str, "\n%s: %s", _("Position"), info->workposition); +		if (info->workwebpage && info->workwebpage[0]) { +			g_string_append_printf(str, "\n%s: %s", _("Web Page"), info->workwebpage); +		} +		g_string_append_c(str, '\n'); +	} + +	imcb_log(ic, "%s\n%s", _("User Info"), str->str); +	g_string_free(str, TRUE); + +	return 1;  } @@ -2384,7 +2384,7 @@ static char *oscar_encoding_to_utf8(char *encoding, char *text, int textlen)  static int gaim_parseaiminfo(aim_session_t *sess, aim_frame_t *fr, ...)  { -	struct gaim_connection *gc = sess->aux_data; +	struct im_connection *ic = sess->aux_data;  	va_list ap;  	aim_userinfo_t *userinfo;  	guint16 infotype; @@ -2413,18 +2413,18 @@ static int gaim_parseaiminfo(aim_session_t *sess, aim_frame_t *fr, ...)  			idletime.tm_min = userinfo->idletime % 60;  			idletime.tm_sec = 0;  			strftime(buff, 256, _("%d days %H hours %M minutes"), &idletime); -			serv_got_crap(gc, "%s: %s", _("Idle Time"), buff); +			imcb_log(ic, "%s: %s", _("Idle Time"), buff);  		}  		if(text) {  			utf8 = oscar_encoding_to_utf8(extracted_encoding, text, text_length); -			serv_got_crap(gc, "%s\n%s", _("User Info"), utf8); +			imcb_log(ic, "%s\n%s", _("User Info"), utf8);  		} else { -			serv_got_crap(gc, _("No user info available.")); +			imcb_log(ic, _("No user info available."));  		}  	} else if(infotype == AIM_GETINFO_AWAYMESSAGE && userinfo->flags & AIM_FLAG_AWAY) {  		utf8 = oscar_encoding_to_utf8(extracted_encoding, text, text_length); -		serv_got_crap(gc, "%s\n%s", _("Away Message"), utf8); +		imcb_log(ic, "%s\n%s", _("Away Message"), utf8);  	}  	g_free(utf8); @@ -2434,7 +2434,7 @@ static int gaim_parseaiminfo(aim_session_t *sess, aim_frame_t *fr, ...)  int gaim_parsemtn(aim_session_t *sess, aim_frame_t *fr, ...)  { -	struct gaim_connection * gc = sess->aux_data; +	struct im_connection * ic = sess->aux_data;  	va_list ap;  	guint16 type1, type2;  	char * sn; @@ -2447,65 +2447,37 @@ int gaim_parsemtn(aim_session_t *sess, aim_frame_t *fr, ...)  	if(type2 == 0x0002) {  		/* User is typing */ -		serv_got_typing(gc, sn, 0, 1); +		imcb_buddy_typing(ic, sn, OPT_TYPING);  	}   	else if (type2 == 0x0001) {  		/* User has typed something, but is not actively typing (stale) */ -		serv_got_typing(gc, sn, 0, 2); +		imcb_buddy_typing(ic, sn, OPT_THINKING);  	}  	else {  		/* User has stopped typing */ -		serv_got_typing(gc, sn, 0, 0); -	}         +		imcb_buddy_typing(ic, sn, 0); +	}  	return 1;  } -static char *oscar_get_status_string( struct gaim_connection *gc, int number ) -{ -	struct oscar_data *od = gc->proto_data; -	 -	if( ! number & UC_UNAVAILABLE ) -	{ -		return( NULL ); -	} -	else if( od->icq ) -	{ -		number >>= 7; -		if( number & AIM_ICQ_STATE_DND ) -			return( "Do Not Disturb" ); -		else if( number & AIM_ICQ_STATE_OUT ) -			return( "Not Available" ); -		else if( number & AIM_ICQ_STATE_BUSY ) -			return( "Occupied" ); -		else if( number & AIM_ICQ_STATE_INVISIBLE ) -			return( "Invisible" ); -		else -			return( "Away" ); -	} -	else -	{ -		return( "Away" ); -	} -} - -int oscar_send_typing(struct gaim_connection *gc, char * who, int typing) +int oscar_send_typing(struct im_connection *ic, char * who, int typing)  { -	struct oscar_data *od = gc->proto_data; -	return( aim_im_sendmtn(od->sess, 1, who, typing ? 0x0002 : 0x0000) ); +	struct oscar_data *od = ic->proto_data; +	return( aim_im_sendmtn(od->sess, 1, who, (typing & OPT_TYPING) ? 0x0002 : 0x0000) );  } -int oscar_chat_send(struct gaim_connection * gc, int id, char *message) +void oscar_chat_msg(struct groupchat *c, char *message, int msgflags)  { -	struct oscar_data * od = (struct oscar_data*)gc->proto_data; +	struct im_connection *ic = c->ic; +	struct oscar_data * od = (struct oscar_data*)ic->proto_data;  	struct chat_connection * ccon;  	int ret;  	guint8 len = strlen(message);  	guint16 flags;  	char *s; -	if(!(ccon = find_oscar_chat(gc, id))) -		return -1; +	ccon = c->data;  	for (s = message; *s; s++)  		if (*s & 128) @@ -2539,89 +2511,85 @@ int oscar_chat_send(struct gaim_connection * gc, int id, char *message)  		g_free(s);    } -  return (ret >= 0); +/*  return (ret >= 0); */  } -void oscar_chat_invite(struct gaim_connection * gc, int id, char *message, char *who) +void oscar_chat_invite(struct groupchat *c, char *who, char *message)  { -	struct oscar_data * od = (struct oscar_data *)gc->proto_data; -	struct chat_connection *ccon = find_oscar_chat(gc, id); -	 -	if (ccon == NULL) -		return; +	struct im_connection *ic = c->ic; +	struct oscar_data * od = (struct oscar_data *)ic->proto_data; +	struct chat_connection *ccon = c->data;  	aim_chat_invite(od->sess, od->conn, who, message ? message : "",  					ccon->exchange, ccon->name, 0x0);  } -void oscar_chat_kill(struct gaim_connection *gc, struct chat_connection *cc) +void oscar_chat_kill(struct im_connection *ic, struct chat_connection *cc)  { -	struct oscar_data *od = (struct oscar_data *)gc->proto_data; +	struct oscar_data *od = (struct oscar_data *)ic->proto_data;  	/* Notify the conversation window that we've left the chat */ -	serv_got_chat_left(gc, cc->id); +	imcb_chat_free(cc->cnv);  	/* Destroy the chat_connection */  	od->oscar_chats = g_slist_remove(od->oscar_chats, cc);  	if (cc->inpa > 0) -		gaim_input_remove(cc->inpa); +		b_event_remove(cc->inpa);  	aim_conn_kill(od->sess, &cc->conn);  	g_free(cc->name);  	g_free(cc->show);  	g_free(cc);  } -void oscar_chat_leave(struct gaim_connection * gc, int id) +void oscar_chat_leave(struct groupchat *c)  { -	struct chat_connection * ccon = find_oscar_chat(gc, id); - -	if(ccon == NULL) -		return; - -	oscar_chat_kill(gc, ccon); +	oscar_chat_kill(c->ic, c->data);  } -int oscar_chat_join(struct gaim_connection * gc, char * name) +struct groupchat *oscar_chat_join(struct im_connection * ic, char * room, char * nick, char * password )  { -    struct oscar_data * od = (struct oscar_data *)gc->proto_data; -	 +	struct oscar_data * od = (struct oscar_data *)ic->proto_data;  	aim_conn_t * cur;  	if((cur = aim_getconn_type(od->sess, AIM_CONN_TYPE_CHATNAV))) { -	 -		return (aim_chatnav_createroom(od->sess, cur, name, 4) == 0); -	 +		int st; +		 +		st = aim_chatnav_createroom(od->sess, cur, room, 4); +		 +		return NULL;  	} else {  		struct create_room * cr = g_new0(struct create_room, 1); +		  		cr->exchange = 4; -		cr->name = g_strdup(name); +		cr->name = g_strdup(room);  		od->create_rooms = g_slist_append(od->create_rooms, cr);  		aim_reqservice(od->sess, od->conn, AIM_CONN_TYPE_CHATNAV); -		return 1; +		 +		return NULL;  	}  } -int oscar_chat_open(struct gaim_connection * gc, char *who) +struct groupchat *oscar_chat_with(struct im_connection * ic, char *who)  { -	struct oscar_data * od = (struct oscar_data *)gc->proto_data; -	int ret; +	struct oscar_data * od = (struct oscar_data *)ic->proto_data; +	struct groupchat *ret;  	static int chat_id = 0;  	char * chatname; -	chatname = g_strdup_printf("%s%d", gc->username, chat_id++); +	chatname = g_strdup_printf("%s%d", ic->acc->user, chat_id++); -	ret = oscar_chat_join(gc, chatname); +	ret = oscar_chat_join(ic, chatname, NULL, NULL);  	aim_chat_invite(od->sess, od->conn, who, "", 4, chatname, 0x0);  	g_free(chatname); -	return ret; +	return NULL;  }  void oscar_accept_chat(gpointer w, struct aim_chat_invitation * inv)  { -	oscar_chat_join(inv->gc, inv->name); +	oscar_chat_join(inv->ic, inv->name, NULL, NULL);  	g_free(inv->name);  	g_free(inv);  } @@ -2632,32 +2600,34 @@ void oscar_reject_chat(gpointer w, struct aim_chat_invitation * inv)  	g_free(inv);  } -void oscar_init()  +void oscar_initmodule()   {  	struct prpl *ret = g_new0(struct prpl, 1);  	ret->name = "oscar";  	ret->away_states = oscar_away_states; +	ret->init = oscar_init;  	ret->login = oscar_login; -	ret->close = oscar_close; -	ret->send_im = oscar_send_im; +	ret->keepalive = oscar_keepalive; +	ret->logout = oscar_logout; +	ret->buddy_msg = oscar_buddy_msg;  	ret->get_info = oscar_get_info;  	ret->set_away = oscar_set_away;  	ret->get_away = oscar_get_away;  	ret->add_buddy = oscar_add_buddy;  	ret->remove_buddy = oscar_remove_buddy; -	ret->chat_send = oscar_chat_send; +	ret->chat_msg = oscar_chat_msg;  	ret->chat_invite = oscar_chat_invite;  	ret->chat_leave = oscar_chat_leave; -	ret->chat_open = oscar_chat_open; +	ret->chat_with = oscar_chat_with; +	ret->chat_join = oscar_chat_join;  	ret->add_permit = oscar_add_permit;  	ret->add_deny = oscar_add_deny;  	ret->rem_permit = oscar_rem_permit;  	ret->rem_deny = oscar_rem_deny;  	ret->set_permit_deny = oscar_set_permit_deny; -	ret->keepalive = oscar_keepalive; -	ret->cmp_buddynames = aim_sncmp; -	ret->get_status_string = oscar_get_status_string;  	ret->send_typing = oscar_send_typing; +	 +	ret->handle_cmp = aim_sncmp;  	register_protocol(ret);  } diff --git a/protocols/oscar/rxhandlers.c b/protocols/oscar/rxhandlers.c index be8aba44..7014e693 100644 --- a/protocols/oscar/rxhandlers.c +++ b/protocols/oscar/rxhandlers.c @@ -112,10 +112,6 @@ static int consumesnac(aim_session_t *sess, aim_frame_t *rx)  		/* Following SNAC will be related */  	} -    if (set_getint(sess->aux_data, "debug")) { -        serv_got_crap(sess->aux_data, "snac %x/%x received", snac.family, snac.subtype); -    } -  	for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {  		if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) &&  diff --git a/protocols/oscar/rxqueue.c b/protocols/oscar/rxqueue.c index 6e8dd29c..34f389af 100644 --- a/protocols/oscar/rxqueue.c +++ b/protocols/oscar/rxqueue.c @@ -391,7 +391,7 @@ int aim_get_command(aim_session_t *sess, aim_conn_t *conn)  		aim_bstream_rewind(&flaphdr);  		start = aimbs_get8(&flaphdr); -		do_error_dialog(sess->aux_data, "FLAP framing disrupted", "Gaim"); +		imcb_error(sess->aux_data, "FLAP framing disrupted");  		aim_conn_close(conn);  		return -1;  	}	 diff --git a/protocols/oscar/search.c b/protocols/oscar/search.c index 9685a3d1..3570e4df 100644 --- a/protocols/oscar/search.c +++ b/protocols/oscar/search.c @@ -38,7 +38,7 @@ static int error(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_mo  	/* XXX the modules interface should have already retrieved this for us */  	if (!(snac2 = aim_remsnac(sess, snac->id))) { -		do_error_dialog(sess->aux_data, "couldn't get snac", "Gaim"); +		imcb_error(sess->aux_data, "couldn't get snac");  		return 0;  	} diff --git a/protocols/oscar/service.c b/protocols/oscar/service.c index 4596974f..acd09150 100644 --- a/protocols/oscar/service.c +++ b/protocols/oscar/service.c @@ -566,7 +566,7 @@ static int migrate(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_  		group = aimbs_get16(bs); -		do_error_dialog(sess->aux_data, "bifurcated migration unsupported", "Gaim"); +		imcb_error(sess->aux_data, "bifurcated migration unsupported");  	}  	tl = aim_readtlvchain(bs); @@ -731,8 +731,12 @@ int aim_setextstatus(aim_session_t *sess, aim_conn_t *conn, guint32 status)  	aim_tlvlist_t *tl = NULL;  	guint32 data;  	int tlvlen; +	struct im_connection *ic = sess ? sess->aux_data : NULL;  	data = AIM_ICQ_STATE_HIDEIP | status; /* yay for error checking ;^) */ +	 +	if (ic && set_getbool(&ic->acc->set, "web_aware")) +		data |= AIM_ICQ_STATE_WEBAWARE;  	tlvlen = aim_addtlvtochain32(&tl, 0x0006, data); @@ -889,7 +893,7 @@ int aim_sendmemblock(aim_session_t *sess, aim_conn_t *conn, guint32 offset, guin  			aimbs_put32(&fr->data, 0xecf8427e);  */  		} else -			do_error_dialog(sess->aux_data, "WARNING: unknown hash request", "Gaim"); +			imcb_error(sess->aux_data, "Warning: unknown hash request");  	} diff --git a/protocols/oscar/txqueue.c b/protocols/oscar/txqueue.c index 6b4854c5..d38986d0 100644 --- a/protocols/oscar/txqueue.c +++ b/protocols/oscar/txqueue.c @@ -29,7 +29,7 @@ aim_frame_t *aim_tx_new(aim_session_t *sess, aim_conn_t *conn, guint8 framing, g  	aim_frame_t *fr;  	if (!conn) { -		do_error_dialog(sess->aux_data, "no connection specified", "Gaim"); +		imcb_error(sess->aux_data, "no connection specified");  		return NULL;  	} @@ -45,7 +45,7 @@ aim_frame_t *aim_tx_new(aim_session_t *sess, aim_conn_t *conn, guint8 framing, g  		fr->hdr.flap.type = chan;  	} else  -		do_error_dialog(sess->aux_data, "unknown framing", "Gaim"); +		imcb_error(sess->aux_data, "unknown framing");  	if (datalen > 0) {  		guint8 *data; @@ -79,7 +79,7 @@ static int aim_tx_enqueue__queuebased(aim_session_t *sess, aim_frame_t *fr)  {  	if (!fr->conn) { -		do_error_dialog(sess->aux_data, "WARNING: enqueueing packet with no connection", "Gaim"); +		imcb_error(sess->aux_data, "Warning: enqueueing packet with no connection");  		fr->conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS);  	} @@ -119,7 +119,7 @@ static int aim_tx_enqueue__immediate(aim_session_t *sess, aim_frame_t *fr)  {  	if (!fr->conn) { -		do_error_dialog(sess->aux_data, "packet has no connection", "Gaim"); +		imcb_error(sess->aux_data, "packet has no connection");  		aim_frame_destroy(fr);  		return 0;  	} diff --git a/protocols/proxy.c b/protocols/proxy.c deleted file mode 100644 index 1ca35dfe..00000000 --- a/protocols/proxy.c +++ /dev/null @@ -1,600 +0,0 @@ -/* - * gaim - * - * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net> - * Copyright (C) 2002-2004, Wilmer van der Gaast, Jelmer Vernooij - * - * 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 - * - */ - -/* this is a little piece of code to handle proxy connection */ -/* it is intended to : 1st handle http proxy, using the CONNECT command - , 2nd provide an easy way to add socks support */ - -#define BITLBEE_CORE -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/types.h> -#ifndef _WIN32 -#include <sys/socket.h> -#include <netdb.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <unistd.h> -#else -#include "sock.h" -#define ETIMEDOUT WSAETIMEDOUT -#define EINPROGRESS WSAEINPROGRESS -#endif -#include <fcntl.h> -#include <errno.h> -#include "nogaim.h" -#include "proxy.h" - -#define GAIM_READ_COND  (G_IO_IN | G_IO_HUP | G_IO_ERR) -#define GAIM_WRITE_COND (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL) -#define GAIM_ERR_COND   (G_IO_HUP | G_IO_ERR | G_IO_NVAL) - -char proxyhost[128] = ""; -int proxyport = 0; -int proxytype = PROXY_NONE; -char proxyuser[128] = ""; -char proxypass[128] = ""; - -struct PHB { -	GaimInputFunction func, proxy_func; -	gpointer data, proxy_data; -	char *host; -	int port; -	int fd; -	gint inpa; -}; - -typedef struct _GaimIOClosure { -	GaimInputFunction function; -	guint result; -	gpointer data; -} GaimIOClosure; - - - -static struct sockaddr_in *gaim_gethostbyname(const char *host, int port) -{ -	static struct sockaddr_in sin; - -	if (!inet_aton(host, &sin.sin_addr)) { -		struct hostent *hp; -		if (!(hp = gethostbyname(host))) { -			return NULL; -		} -		memset(&sin, 0, sizeof(struct sockaddr_in)); -		memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); -		sin.sin_family = hp->h_addrtype; -	} else -		sin.sin_family = AF_INET; -	sin.sin_port = htons(port); - -	return &sin; -} - -static void gaim_io_destroy(gpointer data) -{ -	g_free(data); -} - -static gboolean gaim_io_invoke(GIOChannel *source, GIOCondition condition, gpointer data) -{ -	GaimIOClosure *closure = data; -	GaimInputCondition gaim_cond = 0; - -	if (condition & GAIM_READ_COND) -		gaim_cond |= GAIM_INPUT_READ; -	if (condition & GAIM_WRITE_COND) -		gaim_cond |= GAIM_INPUT_WRITE; - -	closure->function(closure->data, g_io_channel_unix_get_fd(source), gaim_cond); - -	return TRUE; -} - -static void gaim_io_connected(gpointer data, gint source, GaimInputCondition cond) -{ -	struct PHB *phb = data; -	unsigned int len; -	int error = ETIMEDOUT; -	len = sizeof(error); -	 -#ifndef _WIN32 -	if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { -		closesocket(source); -		gaim_input_remove(phb->inpa); -		if( phb->proxy_func ) -			phb->proxy_func(phb->proxy_data, -1, GAIM_INPUT_READ); -		else { -			phb->func(phb->data, -1, GAIM_INPUT_READ); -			g_free(phb); -		} -		return; -	} -#endif -	sock_make_blocking(source); -	gaim_input_remove(phb->inpa); -	if( phb->proxy_func ) -		phb->proxy_func(phb->proxy_data, source, GAIM_INPUT_READ); -	else { -		phb->func(phb->data, source, GAIM_INPUT_READ); -		g_free(phb); -	} -} - -static int proxy_connect_none(const char *host, unsigned short port, struct PHB *phb) -{ -	struct sockaddr_in *sin; -	int fd = -1; - -	if (!(sin = gaim_gethostbyname(host, port))) { -		g_free(phb); -		return -1; -	} - -	if ((fd = socket(sin->sin_family, SOCK_STREAM, 0)) < 0) { -		g_free(phb); -		return -1; -	} - -	sock_make_nonblocking(fd); - -	if (connect(fd, (struct sockaddr *)sin, sizeof(*sin)) < 0) { -		if (sockerr_again()) { -			phb->inpa = gaim_input_add(fd, GAIM_INPUT_WRITE, gaim_io_connected, phb); -			phb->fd = fd; -		} else { -			closesocket(fd); -			g_free(phb); -			return -1; -		} -	} - -	return fd; -} - - -/* Connecting to HTTP proxies */ - -#define HTTP_GOODSTRING "HTTP/1.0 200 Connection established" -#define HTTP_GOODSTRING2 "HTTP/1.1 200 Connection established" - -static void http_canread(gpointer data, gint source, GaimInputCondition cond) -{ -	int nlc = 0; -	int pos = 0; -	struct PHB *phb = data; -	char inputline[8192]; - -	gaim_input_remove(phb->inpa); - -	while ((pos < sizeof(inputline)-1) && (nlc != 2) && (read(source, &inputline[pos++], 1) == 1)) { -		if (inputline[pos - 1] == '\n') -			nlc++; -		else if (inputline[pos - 1] != '\r') -			nlc = 0; -	} -	inputline[pos] = '\0'; - -	if ((memcmp(HTTP_GOODSTRING, inputline, strlen(HTTP_GOODSTRING)) == 0) || -	    (memcmp(HTTP_GOODSTRING2, inputline, strlen(HTTP_GOODSTRING2)) == 0)) { -		phb->func(phb->data, source, GAIM_INPUT_READ); -		g_free(phb->host); -		g_free(phb); -		return; -	} - -	close(source); -	phb->func(phb->data, -1, GAIM_INPUT_READ); -	g_free(phb->host); -	g_free(phb); -	return; -} - -static void http_canwrite(gpointer data, gint source, GaimInputCondition cond) -{ -	char cmd[384]; -	struct PHB *phb = data; -	unsigned int len; -	int error = ETIMEDOUT; -	if (phb->inpa > 0) -		gaim_input_remove(phb->inpa); -	len = sizeof(error); -	if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { -		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); -		g_free(phb->host); -		g_free(phb); -		return; -	} -	sock_make_blocking(source); - -	g_snprintf(cmd, sizeof(cmd), "CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\n", phb->host, phb->port, -		   phb->host, phb->port); -	if (send(source, cmd, strlen(cmd), 0) < 0) { -		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); -		g_free(phb->host); -		g_free(phb); -		return; -	} - -	if (proxyuser && *proxyuser) { -		char *t1, *t2; -		t1 = g_strdup_printf("%s:%s", proxyuser, proxypass); -		t2 = tobase64(t1); -		g_free(t1); -		g_snprintf(cmd, sizeof(cmd), "Proxy-Authorization: Basic %s\r\n", t2); -		g_free(t2); -		if (send(source, cmd, strlen(cmd), 0) < 0) { -			close(source); -			phb->func(phb->data, -1, GAIM_INPUT_READ); -			g_free(phb->host); -			g_free(phb); -			return; -		} -	} - -	g_snprintf(cmd, sizeof(cmd), "\r\n"); -	if (send(source, cmd, strlen(cmd), 0) < 0) { -		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); -		g_free(phb->host); -		g_free(phb); -		return; -	} - -	phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, http_canread, phb); -} - -static int proxy_connect_http(const char *host, unsigned short port, struct PHB *phb) -{ -	phb->host = g_strdup(host); -	phb->port = port; -	phb->proxy_func = http_canwrite; -	phb->proxy_data = phb; -	 -	return( proxy_connect_none( proxyhost, proxyport, phb ) ); -} - - -/* Connecting to SOCKS4 proxies */ - -static void s4_canread(gpointer data, gint source, GaimInputCondition cond) -{ -	unsigned char packet[12]; -	struct PHB *phb = data; - -	gaim_input_remove(phb->inpa); - -	memset(packet, 0, sizeof(packet)); -	if (read(source, packet, 9) >= 4 && packet[1] == 90) { -		phb->func(phb->data, source, GAIM_INPUT_READ); -		g_free(phb->host); -		g_free(phb); -		return; -	} - -	close(source); -	phb->func(phb->data, -1, GAIM_INPUT_READ); -	g_free(phb->host); -	g_free(phb); -} - -static void s4_canwrite(gpointer data, gint source, GaimInputCondition cond) -{ -	unsigned char packet[12]; -	struct hostent *hp; -	struct PHB *phb = data; -	unsigned int len; -	int error = ETIMEDOUT; -	if (phb->inpa > 0) -		gaim_input_remove(phb->inpa); -	len = sizeof(error); -	if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { -		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); -		g_free(phb->host); -		g_free(phb); -		return; -	} -	sock_make_blocking(source); - -	/* XXX does socks4 not support host name lookups by the proxy? */ -	if (!(hp = gethostbyname(phb->host))) { -		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); -		g_free(phb->host); -		g_free(phb); -		return; -	} - -	packet[0] = 4; -	packet[1] = 1; -	packet[2] = phb->port >> 8; -	packet[3] = phb->port & 0xff; -	packet[4] = (unsigned char)(hp->h_addr_list[0])[0]; -	packet[5] = (unsigned char)(hp->h_addr_list[0])[1]; -	packet[6] = (unsigned char)(hp->h_addr_list[0])[2]; -	packet[7] = (unsigned char)(hp->h_addr_list[0])[3]; -	packet[8] = 0; -	if (write(source, packet, 9) != 9) { -		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); -		g_free(phb->host); -		g_free(phb); -		return; -	} - -	phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s4_canread, phb); -} - -static int proxy_connect_socks4(const char *host, unsigned short port, struct PHB *phb) -{ -	phb->host = g_strdup(host); -	phb->port = port; -	phb->proxy_func = s4_canwrite; -	phb->proxy_data = phb; -	 -	return( proxy_connect_none( proxyhost, proxyport, phb ) ); -} - - -/* Connecting to SOCKS5 proxies */ - -static void s5_canread_again(gpointer data, gint source, GaimInputCondition cond) -{ -	unsigned char buf[512]; -	struct PHB *phb = data; - -	gaim_input_remove(phb->inpa); - -	if (read(source, buf, 10) < 10) { -		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); -		g_free(phb->host); -		g_free(phb); -		return; -	} -	if ((buf[0] != 0x05) || (buf[1] != 0x00)) { -		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); -		g_free(phb->host); -		g_free(phb); -		return; -	} - -	phb->func(phb->data, source, GAIM_INPUT_READ); -	g_free(phb->host); -	g_free(phb); -	return; -} - -static void s5_sendconnect(gpointer data, gint source) -{ -	unsigned char buf[512]; -	struct PHB *phb = data; -	int hlen = strlen(phb->host); - -	buf[0] = 0x05; -	buf[1] = 0x01;		/* CONNECT */ -	buf[2] = 0x00;		/* reserved */ -	buf[3] = 0x03;		/* address type -- host name */ -	buf[4] = hlen; -	memcpy(buf + 5, phb->host, hlen); -	buf[5 + strlen(phb->host)] = phb->port >> 8; -	buf[5 + strlen(phb->host) + 1] = phb->port & 0xff; - -	if (write(source, buf, (5 + strlen(phb->host) + 2)) < (5 + strlen(phb->host) + 2)) { -		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); -		g_free(phb->host); -		g_free(phb); -		return; -	} - -	phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s5_canread_again, phb); -} - -static void s5_readauth(gpointer data, gint source, GaimInputCondition cond) -{ -	unsigned char buf[512]; -	struct PHB *phb = data; - -	gaim_input_remove(phb->inpa); - -	if (read(source, buf, 2) < 2) { -		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); -		g_free(phb->host); -		g_free(phb); -		return; -	} - -	if ((buf[0] != 0x01) || (buf[1] != 0x00)) { -		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); -		g_free(phb->host); -		g_free(phb); -		return; -	} - -	s5_sendconnect(phb, source); -} - -static void s5_canread(gpointer data, gint source, GaimInputCondition cond) -{ -	unsigned char buf[512]; -	struct PHB *phb = data; - -	gaim_input_remove(phb->inpa); - -	if (read(source, buf, 2) < 2) { -		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); -		g_free(phb->host); -		g_free(phb); -		return; -	} - -	if ((buf[0] != 0x05) || (buf[1] == 0xff)) { -		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); -		g_free(phb->host); -		g_free(phb); -		return; -	} - -	if (buf[1] == 0x02) { -		unsigned int i = strlen(proxyuser), j = strlen(proxypass); -		buf[0] = 0x01;	/* version 1 */ -		buf[1] = i; -		memcpy(buf + 2, proxyuser, i); -		buf[2 + i] = j; -		memcpy(buf + 2 + i + 1, proxypass, j); -		if (write(source, buf, 3 + i + j) < 3 + i + j) { -			close(source); -			phb->func(phb->data, -1, GAIM_INPUT_READ); -			g_free(phb->host); -			g_free(phb); -			return; -		} - -		phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s5_readauth, phb); -	} else { -		s5_sendconnect(phb, source); -	} -} - -static void s5_canwrite(gpointer data, gint source, GaimInputCondition cond) -{ -	unsigned char buf[512]; -	int i; -	struct PHB *phb = data; -	unsigned int len; -	int error = ETIMEDOUT; -	if (phb->inpa > 0) -		gaim_input_remove(phb->inpa); -	len = sizeof(error); -	if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { -		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); -		g_free(phb->host); -		g_free(phb); -		return; -	} -	sock_make_blocking(source); - -	i = 0; -	buf[0] = 0x05;		/* SOCKS version 5 */ -	if (proxyuser[0]) { -		buf[1] = 0x02;	/* two methods */ -		buf[2] = 0x00;	/* no authentication */ -		buf[3] = 0x02;	/* username/password authentication */ -		i = 4; -	} else { -		buf[1] = 0x01; -		buf[2] = 0x00; -		i = 3; -	} - -	if (write(source, buf, i) < i) { -		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); -		g_free(phb->host); -		g_free(phb); -		return; -	} - -	phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s5_canread, phb); -} - -static int proxy_connect_socks5(const char *host, unsigned short port, struct PHB *phb) -{ -	phb->host = g_strdup(host); -	phb->port = port; -	phb->proxy_func = s5_canwrite; -	phb->proxy_data = phb; -	 -	return( proxy_connect_none( proxyhost, proxyport, phb ) ); -} - - -/* Export functions */ - -gint gaim_input_add(gint source, GaimInputCondition condition, GaimInputFunction function, gpointer data) -{ -	GaimIOClosure *closure = g_new0(GaimIOClosure, 1); -	GIOChannel *channel; -	GIOCondition cond = 0; -	 -	closure->function = function; -	closure->data = data; -	 -	if (condition & GAIM_INPUT_READ) -		cond |= GAIM_READ_COND; -	if (condition & GAIM_INPUT_WRITE) -		cond |= GAIM_WRITE_COND; -	 -	channel = g_io_channel_unix_new(source); -	closure->result = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond, -					      gaim_io_invoke, closure, gaim_io_destroy); -	 -	g_io_channel_unref(channel); -	return closure->result; -} - -void gaim_input_remove(gint tag) -{ -	if (tag > 0) -		g_source_remove(tag); -} - -int proxy_connect(const char *host, int port, GaimInputFunction func, gpointer data) -{ -	struct PHB *phb; -	 -	if (!host || !port || (port == -1) || !func || strlen(host) > 128) { -		return -1; -	} -	 -	phb = g_new0(struct PHB, 1); -	phb->func = func; -	phb->data = data; -	 -#ifndef _WIN32 -	sethostent(1); -#endif -	 -	if ((proxytype == PROXY_NONE) || !proxyhost || !proxyhost[0] || !proxyport || (proxyport == -1)) -		return proxy_connect_none(host, port, phb); -	else if (proxytype == PROXY_HTTP) -		return proxy_connect_http(host, port, phb); -	else if (proxytype == PROXY_SOCKS4) -		return proxy_connect_socks4(host, port, phb); -	else if (proxytype == PROXY_SOCKS5) -		return proxy_connect_socks5(host, port, phb); -	 -	if (phb->host) g_free(phb); -	g_free(phb); -	return -1; -} diff --git a/protocols/proxy.h b/protocols/proxy.h deleted file mode 100644 index 47c966d2..00000000 --- a/protocols/proxy.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * gaim - * - * Copyright (C) 1998-1999, Mark Spencer <markster@marko.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA - * - */ - -/* this is the export part of the proxy.c file. it does a little -   prototype-ing stuff and redefine some net function to mask them -   with some kind of transparent layer */  - -#ifndef _PROXY_H_ -#define _PROXY_H_ - -#include <sys/types.h> -#ifndef _WIN32 -#include <sys/socket.h> -#include <netdb.h> -#include <netinet/in.h> -#endif -#include <glib.h> -#include <gmodule.h> - -#define PROXY_NONE 0 -#define PROXY_HTTP 1 -#define PROXY_SOCKS4 2 -#define PROXY_SOCKS5 3 - -extern char proxyhost[128]; -extern int  proxyport; -extern int  proxytype; -extern char proxyuser[128]; -extern char proxypass[128]; - -typedef enum { -	GAIM_INPUT_READ = 1 << 0, -	GAIM_INPUT_WRITE = 1 << 1 -} GaimInputCondition; -typedef void (*GaimInputFunction)(gpointer, gint, GaimInputCondition); - -G_MODULE_EXPORT gint gaim_input_add(int, GaimInputCondition, GaimInputFunction, gpointer); -G_MODULE_EXPORT void gaim_input_remove(gint); - -G_MODULE_EXPORT int proxy_connect(const char *host, int port, GaimInputFunction func, gpointer data); - -#endif /* _PROXY_H_ */ diff --git a/protocols/sha.c b/protocols/sha.c deleted file mode 100644 index 895505a1..00000000 --- a/protocols/sha.c +++ /dev/null @@ -1,173 +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 SHA 180-1 Reference Implementation (Compact version) - *  - * 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): - * - */ - -#define BITLBEE_CORE -#include "nogaim.h" - -static void shaHashBlock(SHA_CTX *ctx); - -void shaInit(SHA_CTX *ctx) { -  int i; - -  ctx->lenW = 0; -  ctx->sizeHi = ctx->sizeLo = 0; - -  /* Initialize H with the magic constants (see FIPS180 for constants) -   */ -  ctx->H[0] = 0x67452301L; -  ctx->H[1] = 0xefcdab89L; -  ctx->H[2] = 0x98badcfeL; -  ctx->H[3] = 0x10325476L; -  ctx->H[4] = 0xc3d2e1f0L; - -  for (i = 0; i < 80; i++) -    ctx->W[i] = 0; -} - - -void shaUpdate(SHA_CTX *ctx, unsigned char *dataIn, int len) { -  int i; - -  /* Read the data into W and process blocks as they get full -   */ -  for (i = 0; i < len; i++) { -    ctx->W[ctx->lenW / 4] <<= 8; -    ctx->W[ctx->lenW / 4] |= (guint32)dataIn[i]; -    if ((++ctx->lenW) % 64 == 0) { -      shaHashBlock(ctx); -      ctx->lenW = 0; -    } -    ctx->sizeLo += 8; -    ctx->sizeHi += (ctx->sizeLo < 8); -  } -} - - -void shaFinal(SHA_CTX *ctx, unsigned char hashout[20]) { -  unsigned char pad0x80 = 0x80; -  unsigned char pad0x00 = 0x00; -  unsigned char padlen[8]; -  int i; - -  /* Pad with a binary 1 (e.g. 0x80), then zeroes, then length -   */ -  padlen[0] = (unsigned char)((ctx->sizeHi >> 24) & 255); -  padlen[1] = (unsigned char)((ctx->sizeHi >> 16) & 255); -  padlen[2] = (unsigned char)((ctx->sizeHi >> 8) & 255); -  padlen[3] = (unsigned char)((ctx->sizeHi >> 0) & 255); -  padlen[4] = (unsigned char)((ctx->sizeLo >> 24) & 255); -  padlen[5] = (unsigned char)((ctx->sizeLo >> 16) & 255); -  padlen[6] = (unsigned char)((ctx->sizeLo >> 8) & 255); -  padlen[7] = (unsigned char)((ctx->sizeLo >> 0) & 255); -  shaUpdate(ctx, &pad0x80, 1); -  while (ctx->lenW != 56) -    shaUpdate(ctx, &pad0x00, 1); -  shaUpdate(ctx, padlen, 8); - -  /* Output hash -   */ -  for (i = 0; i < 20; i++) { -    hashout[i] = (unsigned char)(ctx->H[i / 4] >> 24); -    ctx->H[i / 4] <<= 8; -  } - -  /* -   *  Re-initialize the context (also zeroizes contents) -   */ -  shaInit(ctx);  -} - - -void shaBlock(unsigned char *dataIn, int len, unsigned char hashout[20]) { -  SHA_CTX ctx; - -  shaInit(&ctx); -  shaUpdate(&ctx, dataIn, len); -  shaFinal(&ctx, hashout); -} - - -#define SHA_ROTL(X,n) ((((X) << (n)) | ((X) >> (32-(n)))) & 0xffffffffL) - -static void shaHashBlock(SHA_CTX *ctx) { -  int t; -  guint32 A,B,C,D,E,TEMP; - -  for (t = 16; t <= 79; t++) -    ctx->W[t] = -      SHA_ROTL(ctx->W[t-3] ^ ctx->W[t-8] ^ ctx->W[t-14] ^ ctx->W[t-16], 1); - -  A = ctx->H[0]; -  B = ctx->H[1]; -  C = ctx->H[2]; -  D = ctx->H[3]; -  E = ctx->H[4]; - -  for (t = 0; t <= 19; t++) { -    TEMP = (SHA_ROTL(A,5) + (((C^D)&B)^D)     + E + ctx->W[t] + 0x5a827999L) & 0xffffffffL; -    E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; -  } -  for (t = 20; t <= 39; t++) { -    TEMP = (SHA_ROTL(A,5) + (B^C^D)           + E + ctx->W[t] + 0x6ed9eba1L) & 0xffffffffL; -    E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; -  } -  for (t = 40; t <= 59; t++) { -    TEMP = (SHA_ROTL(A,5) + ((B&C)|(D&(B|C))) + E + ctx->W[t] + 0x8f1bbcdcL) & 0xffffffffL; -    E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; -  } -  for (t = 60; t <= 79; t++) { -    TEMP = (SHA_ROTL(A,5) + (B^C^D)           + E + ctx->W[t] + 0xca62c1d6L) & 0xffffffffL; -    E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; -  } - -  ctx->H[0] += A; -  ctx->H[1] += B; -  ctx->H[2] += C; -  ctx->H[3] += D; -  ctx->H[4] += E; -} - -/*---------------------------------------------------------------------------- - * - * This code added by Thomas "temas" Muldowney for Jabber compatability - * - *---------------------------------------------------------------------------*/ -char *shahash(char *str) -{ -    static char final[41]; -    char *pos; -    unsigned char hashval[20]; -    int x; - -    if(!str || strlen(str) == 0) -        return NULL; - -    shaBlock((unsigned char *)str, strlen(str), hashval); - -    pos = final; -    for(x=0;x<20;x++) -    { -        g_snprintf(pos, 3, "%02x", hashval[x]); -        pos += 2; -    } -    return (char *)final; -} diff --git a/protocols/sha.h b/protocols/sha.h deleted file mode 100644 index e8152b1b..00000000 --- a/protocols/sha.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef __SHA_H__ -#define __SHA_H__ - -#include <gmodule.h> - -G_MODULE_EXPORT int strprintsha(char *dest, int *hashval); -  -typedef struct { -  guint32 H[5]; -  guint32 W[80]; -  int lenW; -  guint32 sizeHi,sizeLo; -} SHA_CTX; -  -G_MODULE_EXPORT void shaInit(SHA_CTX *ctx); -G_MODULE_EXPORT void shaUpdate(SHA_CTX *ctx, unsigned char *dataIn, int len); -G_MODULE_EXPORT void shaFinal(SHA_CTX *ctx, unsigned char hashout[20]); -G_MODULE_EXPORT void shaBlock(unsigned char *dataIn, int len, unsigned char hashout[20]); -G_MODULE_EXPORT char *shahash(char *str); - -#endif diff --git a/protocols/ssl_bogus.c b/protocols/ssl_bogus.c deleted file mode 100644 index 52406b75..00000000 --- a/protocols/ssl_bogus.c +++ /dev/null @@ -1,57 +0,0 @@ -  /********************************************************************\ -  * BitlBee -- An IRC to other IM-networks gateway                     * -  *                                                                    * -  * Copyright 2002-2004 Wilmer van der Gaast and others                * -  \********************************************************************/ - -/* SSL module - dummy version                                           */ - -/* -  This program is free software; you can redistribute it and/or modify -  it under the terms of the GNU General Public License as published by -  the Free Software Foundation; either version 2 of the License, or -  (at your option) any later version. - -  This program is distributed in the hope that it will be useful, -  but WITHOUT ANY WARRANTY; without even the implied warranty of -  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -  GNU General Public License for more details. - -  You should have received a copy of the GNU General Public License with -  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; -  if not, write to the Free Software Foundation, Inc., 59 Temple Place, -  Suite 330, Boston, MA  02111-1307  USA -*/ - -#include "ssl_client.h" - -int ssl_errno; - -void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data ) -{ -	return( NULL ); -} - -int ssl_read( void *conn, char *buf, int len ) -{ -	return( -1 ); -} - -int ssl_write( void *conn, const char *buf, int len ) -{ -	return( -1 ); -} - -void ssl_disconnect( void *conn_ ) -{ -} - -int ssl_getfd( void *conn ) -{ -	return( -1 ); -} - -GaimInputCondition ssl_getdirection( void *conn ) -{ -	return GAIM_INPUT_READ; -} diff --git a/protocols/ssl_client.h b/protocols/ssl_client.h deleted file mode 100644 index 89189db9..00000000 --- a/protocols/ssl_client.h +++ /dev/null @@ -1,42 +0,0 @@ -  /********************************************************************\ -  * BitlBee -- An IRC to other IM-networks gateway                     * -  *                                                                    * -  * Copyright 2002-2004 Wilmer van der Gaast and others                * -  \********************************************************************/ - -/* SSL module                                                           */ - -/* -  This program is free software; you can redistribute it and/or modify -  it under the terms of the GNU General Public License as published by -  the Free Software Foundation; either version 2 of the License, or -  (at your option) any later version. - -  This program is distributed in the hope that it will be useful, -  but WITHOUT ANY WARRANTY; without even the implied warranty of -  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -  GNU General Public License for more details. - -  You should have received a copy of the GNU General Public License with -  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; -  if not, write to the Free Software Foundation, Inc., 59 Temple Place, -  Suite 330, Boston, MA  02111-1307  USA -*/ - -#include <glib.h> -#include "proxy.h" - -#define SSL_OK            0 -#define SSL_NOHANDSHAKE   1 -#define SSL_AGAIN         2 - -extern int ssl_errno; - -typedef void (*ssl_input_function)(gpointer, void*, GaimInputCondition); - -G_MODULE_EXPORT void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data ); -G_MODULE_EXPORT int ssl_read( void *conn, char *buf, int len ); -G_MODULE_EXPORT int ssl_write( void *conn, const char *buf, int len ); -G_MODULE_EXPORT void ssl_disconnect( void *conn_ ); -G_MODULE_EXPORT int ssl_getfd( void *conn ); -G_MODULE_EXPORT GaimInputCondition ssl_getdirection( void *conn ); diff --git a/protocols/ssl_gnutls.c b/protocols/ssl_gnutls.c deleted file mode 100644 index f2cb3e08..00000000 --- a/protocols/ssl_gnutls.c +++ /dev/null @@ -1,210 +0,0 @@ -  /********************************************************************\ -  * BitlBee -- An IRC to other IM-networks gateway                     * -  *                                                                    * -  * Copyright 2002-2004 Wilmer van der Gaast and others                * -  \********************************************************************/ - -/* SSL module - GnuTLS version                                          */ - -/* -  This program is free software; you can redistribute it and/or modify -  it under the terms of the GNU General Public License as published by -  the Free Software Foundation; either version 2 of the License, or -  (at your option) any later version. - -  This program is distributed in the hope that it will be useful, -  but WITHOUT ANY WARRANTY; without even the implied warranty of -  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -  GNU General Public License for more details. - -  You should have received a copy of the GNU General Public License with -  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; -  if not, write to the Free Software Foundation, Inc., 59 Temple Place, -  Suite 330, Boston, MA  02111-1307  USA -*/ - -#include <gnutls/gnutls.h> -#include <fcntl.h> -#include <unistd.h> -#include "proxy.h" -#include "ssl_client.h" -#include "sock.h" -#include "stdlib.h" - -int ssl_errno = 0; - -static gboolean initialized = FALSE; - -struct scd -{ -	ssl_input_function func; -	gpointer data; -	int fd; -	gboolean established; -	int inpa; -	 -	gnutls_session session; -	gnutls_certificate_credentials xcred; -}; - -static void ssl_connected( gpointer data, gint source, GaimInputCondition cond ); - - -void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data ) -{ -	struct scd *conn = g_new0( struct scd, 1 ); -	 -	conn->fd = proxy_connect( host, port, ssl_connected, conn ); -	conn->func = func; -	conn->data = data; -	conn->inpa = -1; -	 -	if( conn->fd < 0 ) -	{ -		g_free( conn ); -		return( NULL ); -	} -	 -	if( !initialized ) -	{ -		gnutls_global_init(); -		initialized = TRUE; -		atexit( gnutls_global_deinit ); -	} -	 -	gnutls_certificate_allocate_credentials( &conn->xcred ); -	gnutls_init( &conn->session, GNUTLS_CLIENT ); -	gnutls_set_default_priority( conn->session ); -	gnutls_credentials_set( conn->session, GNUTLS_CRD_CERTIFICATE, conn->xcred ); -	 -	return( conn ); -} - -static void ssl_handshake( gpointer data, gint source, GaimInputCondition cond ); - -static void ssl_connected( gpointer data, gint source, GaimInputCondition cond ) -{ -	struct scd *conn = data; -	 -	if( source == -1 ) -	{ -		conn->func( conn->data, NULL, cond ); -		 -		gnutls_deinit( conn->session ); -		gnutls_certificate_free_credentials( conn->xcred ); -		 -		g_free( conn ); -		 -		return; -	} -	 -	sock_make_nonblocking( conn->fd ); -	gnutls_transport_set_ptr( conn->session, (gnutls_transport_ptr) conn->fd ); -	 -	ssl_handshake( data, source, cond ); -} - -static void ssl_handshake( gpointer data, gint source, GaimInputCondition cond ) -{ -	struct scd *conn = data; -	int st; -	 -	if( conn->inpa != -1 ) -	{ -		gaim_input_remove( conn->inpa ); -		conn->inpa = -1; -	} -	 -	if( ( st = gnutls_handshake( conn->session ) ) < 0 ) -	{ -		if( st == GNUTLS_E_AGAIN || st == GNUTLS_E_INTERRUPTED ) -		{ -			conn->inpa = gaim_input_add( conn->fd, ssl_getdirection( conn ), -			                             ssl_handshake, data ); -		} -		else -		{ -			conn->func( conn->data, NULL, cond ); -			 -			gnutls_deinit( conn->session ); -			gnutls_certificate_free_credentials( conn->xcred ); -			closesocket( conn->fd ); -			 -			g_free( conn ); -		} -	} -	else -	{ -		/* For now we can't handle non-blocking perfectly everywhere... */ -		sock_make_blocking( conn->fd ); -		 -		conn->established = TRUE; -		conn->func( conn->data, conn, cond ); -	} -} - -int ssl_read( void *conn, char *buf, int len ) -{ -	int st; -	 -	if( !((struct scd*)conn)->established ) -	{ -		ssl_errno = SSL_NOHANDSHAKE; -		return( -1 ); -	} -	 -	st = gnutls_record_recv( ((struct scd*)conn)->session, buf, len ); -	 -	ssl_errno = SSL_OK; -	if( st == GNUTLS_E_AGAIN || st == GNUTLS_E_INTERRUPTED ) -		ssl_errno = SSL_AGAIN; -	 -	return st; -} - -int ssl_write( void *conn, const char *buf, int len ) -{ -	int st; -	 -	if( !((struct scd*)conn)->established ) -	{ -		ssl_errno = SSL_NOHANDSHAKE; -		return( -1 ); -	} -	 -	st = gnutls_record_send( ((struct scd*)conn)->session, buf, len ); -	 -	ssl_errno = SSL_OK; -	if( st == GNUTLS_E_AGAIN || st == GNUTLS_E_INTERRUPTED ) -		ssl_errno = SSL_AGAIN; -	 -	return st; -} - -void ssl_disconnect( void *conn_ ) -{ -	struct scd *conn = conn_; -	 -	if( conn->inpa != -1 ) -		gaim_input_remove( conn->inpa ); -	 -	if( conn->established ) -		gnutls_bye( conn->session, GNUTLS_SHUT_WR ); -	 -	closesocket( conn->fd ); -	 -	gnutls_deinit( conn->session ); -	gnutls_certificate_free_credentials( conn->xcred ); -	g_free( conn ); -} - -int ssl_getfd( void *conn ) -{ -	return( ((struct scd*)conn)->fd ); -} - -GaimInputCondition ssl_getdirection( void *conn ) -{ -	return( gnutls_record_get_direction( ((struct scd*)conn)->session ) ? -	        GAIM_INPUT_WRITE : GAIM_INPUT_READ ); -} diff --git a/protocols/ssl_nss.c b/protocols/ssl_nss.c deleted file mode 100644 index 00d32834..00000000 --- a/protocols/ssl_nss.c +++ /dev/null @@ -1,188 +0,0 @@ -  /********************************************************************\ -  * BitlBee -- An IRC to other IM-networks gateway                     * -  *                                                                    * -  * Copyright 2002-2005 Wilmer van der Gaast and others                * -  \********************************************************************/ - -/* SSL module - NSS version                                             */ - -/* Copyright 2005 Jelmer Vernooij                                       */ - -/* -  This program is free software; you can redistribute it and/or modify -  it under the terms of the GNU General Public License as published by -  the Free Software Foundation; either version 2 of the License, or -  (at your option) any later version. - -  This program is distributed in the hope that it will be useful, -  but WITHOUT ANY WARRANTY; without even the implied warranty of -  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -  GNU General Public License for more details. - -  You should have received a copy of the GNU General Public License with -  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; -  if not, write to the Free Software Foundation, Inc., 59 Temple Place, -  Suite 330, Boston, MA  02111-1307  USA -*/ - -#include "bitlbee.h" -#include "proxy.h" -#include "ssl_client.h" -#include "sock.h" -#include <nspr.h> -#include <prio.h> -#include <sslproto.h> -#include <nss.h> -#include <private/pprio.h> -#include <ssl.h> -#include <secerr.h> -#include <sslerr.h> - -int ssl_errno = 0; - -static gboolean initialized = FALSE; - -struct scd -{ -	ssl_input_function func; -	gpointer data; -	int fd; -	PRFileDesc *prfd; -	gboolean established; -}; - -static void ssl_connected( gpointer data, gint source, GaimInputCondition cond ); - - -static SECStatus nss_auth_cert (void *arg, PRFileDesc *socket, PRBool checksig, PRBool isserver) -{ -	return SECSuccess; -} - -static SECStatus nss_bad_cert (void *arg, PRFileDesc *socket)  -{ -	PRErrorCode err; - -	if(!arg) return SECFailure; - -	*(PRErrorCode *)arg = err = PORT_GetError(); - -	switch(err) { -	case SEC_ERROR_INVALID_AVA: -	case SEC_ERROR_INVALID_TIME: -	case SEC_ERROR_BAD_SIGNATURE: -	case SEC_ERROR_EXPIRED_CERTIFICATE: -	case SEC_ERROR_UNKNOWN_ISSUER: -	case SEC_ERROR_UNTRUSTED_CERT: -	case SEC_ERROR_CERT_VALID: -	case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: -	case SEC_ERROR_CRL_EXPIRED: -	case SEC_ERROR_CRL_BAD_SIGNATURE: -	case SEC_ERROR_EXTENSION_VALUE_INVALID: -	case SEC_ERROR_CA_CERT_INVALID: -	case SEC_ERROR_CERT_USAGES_INVALID: -	case SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION: -		return SECSuccess; - -	default: -		return SECFailure; -	} -} - - -void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data ) -{ -	struct scd *conn = g_new0( struct scd, 1 ); -	 -	conn->fd = proxy_connect( host, port, ssl_connected, conn ); -	conn->func = func; -	conn->data = data; -	 -	if( conn->fd < 0 ) -	{ -		g_free( conn ); -		return( NULL ); -	} -	 -	if( !initialized ) -	{ -		PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); -		NSS_NoDB_Init(NULL); -		NSS_SetDomesticPolicy(); -	} - -	 -	return( conn ); -} - -static void ssl_connected( gpointer data, gint source, GaimInputCondition cond ) -{ -	struct scd *conn = data; -	 -	if( source == -1 ) -		goto ssl_connected_failure; -	 -	/* Until we find out how to handle non-blocking I/O with NSS... */ -	sock_make_blocking( conn->fd ); -	 -	conn->prfd = SSL_ImportFD(NULL, PR_ImportTCPSocket(source)); -	SSL_OptionSet(conn->prfd, SSL_SECURITY, PR_TRUE); -	SSL_OptionSet(conn->prfd, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE); -	SSL_BadCertHook(conn->prfd, (SSLBadCertHandler)nss_bad_cert, NULL); -	SSL_AuthCertificateHook(conn->prfd, (SSLAuthCertificate)nss_auth_cert, (void *)CERT_GetDefaultCertDB()); -	SSL_ResetHandshake(conn->prfd, PR_FALSE); - -	if (SSL_ForceHandshake(conn->prfd)) { -		goto ssl_connected_failure; -	} -	 -	 -	conn->established = TRUE; -	conn->func( conn->data, conn, cond ); -	return; -	 -	ssl_connected_failure: -	 -	conn->func( conn->data, NULL, cond ); -	 -	PR_Close( conn -> prfd ); -	if( source >= 0 ) closesocket( source ); -	g_free( conn ); -} - -int ssl_read( void *conn, char *buf, int len ) -{ -	if( !((struct scd*)conn)->established ) -		return( 0 ); -	 -	return( PR_Read( ((struct scd*)conn)->prfd, buf, len ) ); -} - -int ssl_write( void *conn, const char *buf, int len ) -{ -	if( !((struct scd*)conn)->established ) -		return( 0 ); -	 -	return( PR_Write ( ((struct scd*)conn)->prfd, buf, len ) ); -} - -void ssl_disconnect( void *conn_ ) -{ -	struct scd *conn = conn_; -	 -	PR_Close( conn->prfd ); -	closesocket( conn->fd ); -	 -	g_free( conn ); -} - -int ssl_getfd( void *conn ) -{ -	return( ((struct scd*)conn)->fd ); -} - -GaimInputCondition ssl_getdirection( void *conn ) -{ -	/* Just in case someone calls us, let's return the most likely case: */ -	return GAIM_INPUT_READ; -} diff --git a/protocols/ssl_openssl.c b/protocols/ssl_openssl.c deleted file mode 100644 index b79088cc..00000000 --- a/protocols/ssl_openssl.c +++ /dev/null @@ -1,226 +0,0 @@ -  /********************************************************************\ -  * BitlBee -- An IRC to other IM-networks gateway                     * -  *                                                                    * -  * Copyright 2002-2004 Wilmer van der Gaast and others                * -  \********************************************************************/ - -/* SSL module - OpenSSL version                                         */ - -/* -  This program is free software; you can redistribute it and/or modify -  it under the terms of the GNU General Public License as published by -  the Free Software Foundation; either version 2 of the License, or -  (at your option) any later version. - -  This program is distributed in the hope that it will be useful, -  but WITHOUT ANY WARRANTY; without even the implied warranty of -  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -  GNU General Public License for more details. - -  You should have received a copy of the GNU General Public License with -  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; -  if not, write to the Free Software Foundation, Inc., 59 Temple Place, -  Suite 330, Boston, MA  02111-1307  USA -*/ - -#include <openssl/crypto.h> -#include <openssl/rand.h> -#include <openssl/x509.h> -#include <openssl/pem.h> -#include <openssl/ssl.h> -#include <openssl/err.h> - -#include "proxy.h" -#include "ssl_client.h" -#include "sock.h" - -int ssl_errno = 0; - -static gboolean initialized = FALSE; - -struct scd -{ -	ssl_input_function func; -	gpointer data; -	int fd; -	gboolean established; -	 -	int inpa; -	int lasterr;		/* Necessary for SSL_get_error */ -	SSL *ssl; -	SSL_CTX *ssl_ctx; -}; - -static void ssl_connected( gpointer data, gint source, GaimInputCondition cond ); - - - -void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data ) -{ -	struct scd *conn = g_new0( struct scd, 1 ); -	SSL_METHOD *meth; -	 -	conn->fd = proxy_connect( host, port, ssl_connected, conn ); -	conn->func = func; -	conn->data = data; -	 -	if( conn->fd < 0 ) -	{ -		g_free( conn ); -		return( NULL ); -	} -	 -	if( !initialized ) -	{ -		initialized = TRUE; -		SSLeay_add_ssl_algorithms(); -	} -	 -	meth = TLSv1_client_method(); -	conn->ssl_ctx = SSL_CTX_new( meth ); -	if( conn->ssl_ctx == NULL ) -	{ -		conn->fd = -1; -		return( NULL ); -	} -	 -	conn->ssl = SSL_new( conn->ssl_ctx ); -	if( conn->ssl == NULL ) -	{ -		conn->fd = -1; -		return( NULL ); -	} -	 -	return( conn ); -} - -static void ssl_handshake( gpointer data, gint source, GaimInputCondition cond ); - -static void ssl_connected( gpointer data, gint source, GaimInputCondition cond ) -{ -	struct scd *conn = data; -	 -	if( source == -1 ) -		return ssl_handshake( data, -1, cond ); -	 -	/* Make it non-blocking at least during the handshake... */ -	sock_make_nonblocking( conn->fd ); -	SSL_set_fd( conn->ssl, conn->fd ); -	 -	return ssl_handshake( data, source, cond ); -}	 - -static void ssl_handshake( gpointer data, gint source, GaimInputCondition cond ) -{ -	struct scd *conn = data; -	int st; -	 -	if( conn->inpa != -1 ) -	{ -		gaim_input_remove( conn->inpa ); -		conn->inpa = -1; -	} -	 -	if( ( st = SSL_connect( conn->ssl ) ) < 0 ) -	{ -		conn->lasterr = SSL_get_error( conn->ssl, st ); -		if( conn->lasterr != SSL_ERROR_WANT_READ && conn->lasterr != SSL_ERROR_WANT_WRITE ) -			goto ssl_connected_failure; -		 -		conn->inpa = gaim_input_add( conn->fd, ssl_getdirection( conn ), ssl_handshake, data ); -		return; -	} -	 -	conn->established = TRUE; -	sock_make_blocking( conn->fd );		/* For now... */ -	conn->func( conn->data, conn, cond ); -	return; -	 -ssl_connected_failure: -	conn->func( conn->data, NULL, cond ); -	 -	if( conn->ssl ) -	{ -		SSL_shutdown( conn->ssl ); -		SSL_free( conn->ssl ); -	} -	if( conn->ssl_ctx ) -	{ -		SSL_CTX_free( conn->ssl_ctx ); -	} -	if( source >= 0 ) closesocket( source ); -	g_free( conn ); -} - -int ssl_read( void *conn, char *buf, int len ) -{ -	int st; -	 -	if( !((struct scd*)conn)->established ) -	{ -		ssl_errno = SSL_NOHANDSHAKE; -		return -1; -	} -	 -	st = SSL_read( ((struct scd*)conn)->ssl, buf, len ); -	 -	ssl_errno = SSL_OK; -	if( st <= 0 ) -	{ -		((struct scd*)conn)->lasterr = SSL_get_error( ((struct scd*)conn)->ssl, st ); -		if( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_READ || ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ) -			ssl_errno = SSL_AGAIN; -	} -	 -	return st; -} - -int ssl_write( void *conn, const char *buf, int len ) -{ -	int st; -	 -	if( !((struct scd*)conn)->established ) -	{ -		ssl_errno = SSL_NOHANDSHAKE; -		return -1; -	} -	 -	st = SSL_write( ((struct scd*)conn)->ssl, buf, len ); -	 -	ssl_errno = SSL_OK; -	if( st <= 0 ) -	{ -		((struct scd*)conn)->lasterr = SSL_get_error( ((struct scd*)conn)->ssl, st ); -		if( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_READ || ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ) -			ssl_errno = SSL_AGAIN; -	} -	 -	return st; -} - -void ssl_disconnect( void *conn_ ) -{ -	struct scd *conn = conn_; -	 -	if( conn->inpa != -1 ) -		gaim_input_remove( conn->inpa ); -	 -	if( conn->established ) -		SSL_shutdown( conn->ssl ); -	 -	closesocket( conn->fd ); -	 -	SSL_free( conn->ssl ); -	SSL_CTX_free( conn->ssl_ctx ); -	g_free( conn ); -} - -int ssl_getfd( void *conn ) -{ -	return( ((struct scd*)conn)->fd ); -} - -GaimInputCondition ssl_getdirection( void *conn ) -{ -	return( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ? GAIM_INPUT_WRITE : GAIM_INPUT_READ ); -} diff --git a/protocols/yahoo/Makefile b/protocols/yahoo/Makefile index b4014f8a..b4fe56e2 100644 --- a/protocols/yahoo/Makefile +++ b/protocols/yahoo/Makefile @@ -16,6 +16,10 @@ LFLAGS += -r  # [SH] Phony targets  all: yahoo_mod.o +check: all +lcov: check +gcov:  +	gcov *.c  .PHONY: all clean distclean diff --git a/protocols/yahoo/libyahoo2.c b/protocols/yahoo/libyahoo2.c index 967ba681..4e33d0ab 100644 --- a/protocols/yahoo/libyahoo2.c +++ b/protocols/yahoo/libyahoo2.c @@ -73,7 +73,7 @@ char *strchr (), *strrchr ();  #include <stdlib.h>  #include <ctype.h> -#include "sha.h" +#include "sha1.h"  #include "md5.h"  #include "yahoo2.h"  #include "yahoo_httplib.h" @@ -87,6 +87,8 @@ char *strchr (), *strrchr ();  #define vsnprintf _vsnprintf  #endif +#include "base64.h" +  #ifdef USE_STRUCT_CALLBACKS  struct yahoo_callbacks *yc=NULL; @@ -100,6 +102,8 @@ void yahoo_register_callbacks(struct yahoo_callbacks * tyc)  #define YAHOO_CALLBACK(x)	x  #endif +static int yahoo_send_data(int fd, void *data, int len); +  int yahoo_log_message(char * fmt, ...)  {  	char out[1024]; @@ -199,7 +203,12 @@ enum yahoo_service { /* these are easier to see in hex */  	YAHOO_SERVICE_CHATEXIT = 0x9b,  	YAHOO_SERVICE_CHATLOGOUT = 0xa0,  	YAHOO_SERVICE_CHATPING, -	YAHOO_SERVICE_COMMENT = 0xa8 +	YAHOO_SERVICE_COMMENT = 0xa8, +	YAHOO_SERVICE_STEALTH = 0xb9, +	YAHOO_SERVICE_PICTURE_CHECKSUM = 0xbd, +	YAHOO_SERVICE_PICTURE = 0xbe, +	YAHOO_SERVICE_PICTURE_UPDATE = 0xc1, +	YAHOO_SERVICE_PICTURE_UPLOAD = 0xc2  };  struct yahoo_pair { @@ -692,34 +701,10 @@ static void yahoo_packet_dump(unsigned char *data, int len)  	}  } -static char base64digits[] = 	"ABCDEFGHIJKLMNOPQRSTUVWXYZ" -				"abcdefghijklmnopqrstuvwxyz" -				"0123456789._"; -static void to_y64(unsigned char *out, const unsigned char *in, int inlen)  /* raw bytes in quasi-big-endian order to base 64 string (NUL-terminated) */ +static void to_y64(unsigned char *out, const unsigned char *in, int inlen)  { -	for (; inlen >= 3; inlen -= 3) -		{ -			*out++ = base64digits[in[0] >> 2]; -			*out++ = base64digits[((in[0]<<4) & 0x30) | (in[1]>>4)]; -			*out++ = base64digits[((in[1]<<2) & 0x3c) | (in[2]>>6)]; -			*out++ = base64digits[in[2] & 0x3f]; -			in += 3; -		} -	if (inlen > 0) -		{ -			unsigned char fragment; - -			*out++ = base64digits[in[0] >> 2]; -			fragment = (in[0] << 4) & 0x30; -			if (inlen > 1) -				fragment |= in[1] >> 4; -			*out++ = base64digits[fragment]; -			*out++ = (inlen < 2) ? '-'  -					: base64digits[(in[1] << 2) & 0x3c]; -			*out++ = '-'; -		} -	*out = '\0'; +	base64_encode_real(in, inlen, out, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-");  }  static void yahoo_add_to_send_queue(struct yahoo_input_data *yid, void *data, int length) @@ -749,7 +734,7 @@ static void yahoo_send_packet(struct yahoo_input_data *yid, struct yahoo_packet  	data = y_new0(unsigned char, len + 1);  	memcpy(data + pos, "YMSG", 4); pos += 4; -	pos += yahoo_put16(data + pos, 0x0a00); +	pos += yahoo_put16(data + pos, 0x000c);  	pos += yahoo_put16(data + pos, 0x0000);  	pos += yahoo_put16(data + pos, pktlen + extra_pad);  	pos += yahoo_put16(data + pos, pkt->service); @@ -760,6 +745,9 @@ static void yahoo_send_packet(struct yahoo_input_data *yid, struct yahoo_packet  	yahoo_packet_dump(data, len); +	if( yid->type == YAHOO_CONNECTION_FT ) +		yahoo_send_data(yid->fd, data, len); +	else  	yahoo_add_to_send_queue(yid, data, len);  	FREE(data);  } @@ -945,6 +933,7 @@ static void yahoo_process_notify(struct yahoo_input_data *yid, struct yahoo_pack  	struct yahoo_data *yd = yid->yd;  	char *msg = NULL;  	char *from = NULL; +	char *to = NULL;  	int stat = 0;  	int accept = 0;  	char *ind = NULL; @@ -953,6 +942,8 @@ static void yahoo_process_notify(struct yahoo_input_data *yid, struct yahoo_pack  		struct yahoo_pair *pair = l->data;  		if (pair->key == 4)  			from = pair->value; +		if (pair->key == 5) +			to = pair->value;  		if (pair->key == 49)  			msg = pair->value;  		if (pair->key == 13) @@ -970,19 +961,19 @@ static void yahoo_process_notify(struct yahoo_input_data *yid, struct yahoo_pack  		return;  	if (!strncasecmp(msg, "TYPING", strlen("TYPING")))  -		YAHOO_CALLBACK(ext_yahoo_typing_notify)(yd->client_id, from, stat); +		YAHOO_CALLBACK(ext_yahoo_typing_notify)(yd->client_id, to, from, stat);  	else if (!strncasecmp(msg, "GAME", strlen("GAME")))  -		YAHOO_CALLBACK(ext_yahoo_game_notify)(yd->client_id, from, stat); +		YAHOO_CALLBACK(ext_yahoo_game_notify)(yd->client_id, to, from, stat);  	else if (!strncasecmp(msg, "WEBCAMINVITE", strlen("WEBCAMINVITE")))   	{  		if (!strcmp(ind, " ")) { -			YAHOO_CALLBACK(ext_yahoo_webcam_invite)(yd->client_id, from); +			YAHOO_CALLBACK(ext_yahoo_webcam_invite)(yd->client_id, to, from);  		} else {  			accept = atoi(ind);  			/* accept the invitation (-1 = deny 1 = accept) */  			if (accept < 0)  				accept = 0; -			YAHOO_CALLBACK(ext_yahoo_webcam_invite_reply)(yd->client_id, from, accept); +			YAHOO_CALLBACK(ext_yahoo_webcam_invite_reply)(yd->client_id, to, from, accept);  		}  	}  	else @@ -1041,7 +1032,7 @@ static void yahoo_process_filetransfer(struct yahoo_input_data *yid, struct yaho  			*tmp = '\0';  	}  	if(url && from) -		YAHOO_CALLBACK(ext_yahoo_got_file)(yd->client_id, from, url, expires, msg, filename, filesize); +		YAHOO_CALLBACK(ext_yahoo_got_file)(yd->client_id, to, from, url, expires, msg, filename, filesize);  } @@ -1115,31 +1106,31 @@ static void yahoo_process_conference(struct yahoo_input_data *yid, struct yahoo_  		if(pkt->status == 2)  			;  		else if(members) -			YAHOO_CALLBACK(ext_yahoo_got_conf_invite)(yd->client_id, host, room, msg, members); +			YAHOO_CALLBACK(ext_yahoo_got_conf_invite)(yd->client_id, id, host, room, msg, members);  		else if(msg) -			YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, msg, 0); +			YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, msg, 0, E_CONFNOTAVAIL);  		break;  	case YAHOO_SERVICE_CONFADDINVITE:  		if(pkt->status == 2)  			;  		else -			YAHOO_CALLBACK(ext_yahoo_got_conf_invite)(yd->client_id, host, room, msg, members); +			YAHOO_CALLBACK(ext_yahoo_got_conf_invite)(yd->client_id, id, host, room, msg, members);  		break;  	case YAHOO_SERVICE_CONFDECLINE:  		if(who) -			YAHOO_CALLBACK(ext_yahoo_conf_userdecline)(yd->client_id, who, room, msg); +			YAHOO_CALLBACK(ext_yahoo_conf_userdecline)(yd->client_id, id, who, room, msg);  		break;  	case YAHOO_SERVICE_CONFLOGON:  		if(who) -			YAHOO_CALLBACK(ext_yahoo_conf_userjoin)(yd->client_id, who, room); +			YAHOO_CALLBACK(ext_yahoo_conf_userjoin)(yd->client_id, id, who, room);  		break;  	case YAHOO_SERVICE_CONFLOGOFF:  		if(who) -			YAHOO_CALLBACK(ext_yahoo_conf_userleave)(yd->client_id, who, room); +			YAHOO_CALLBACK(ext_yahoo_conf_userleave)(yd->client_id, id, who, room);  		break;  	case YAHOO_SERVICE_CONFMSG:  		if(who) -			YAHOO_CALLBACK(ext_yahoo_conf_message)(yd->client_id, who, room, msg, utf8); +			YAHOO_CALLBACK(ext_yahoo_conf_message)(yd->client_id, id, who, room, msg, utf8);  		break;  	}  } @@ -1147,6 +1138,7 @@ static void yahoo_process_conference(struct yahoo_input_data *yid, struct yahoo_  static void yahoo_process_chat(struct yahoo_input_data *yid, struct yahoo_packet *pkt)  {  	char *msg = NULL; +	char *id = NULL;  	char *who = NULL;  	char *room = NULL;  	char *topic = NULL; @@ -1163,6 +1155,11 @@ static void yahoo_process_chat(struct yahoo_input_data *yid, struct yahoo_packet  	for (l = pkt->hash; l; l = l->next) {  		struct yahoo_pair *pair = l->data; +		if (pair->key == 1) { +			/* My identity */ +			id = pair->value; +		} +  		if (pair->key == 104) {  			/* Room name */  			room = pair->value; @@ -1237,12 +1234,12 @@ static void yahoo_process_chat(struct yahoo_input_data *yid, struct yahoo_packet  	if(!room) {  		if (pkt->service == YAHOO_SERVICE_CHATLOGOUT) { /* yahoo originated chat logout */ -			YAHOO_CALLBACK(ext_yahoo_chat_yahoologout)(yid->yd->client_id); +			YAHOO_CALLBACK(ext_yahoo_chat_yahoologout)(yid->yd->client_id, id);  			return ;  		}  		if (pkt->service == YAHOO_SERVICE_COMMENT && chaterr)  { -			YAHOO_CALLBACK(ext_yahoo_chat_yahooerror)(yid->yd->client_id); -			return ; +			YAHOO_CALLBACK(ext_yahoo_chat_yahooerror)(yid->yd->client_id, id); +			return;  		}  		WARNING(("We didn't get a room name, ignoring packet")); @@ -1255,7 +1252,7 @@ static void yahoo_process_chat(struct yahoo_input_data *yid, struct yahoo_packet  			WARNING(("Count of members doesn't match No. of members we got"));  		}  		if(firstjoin && members) { -			YAHOO_CALLBACK(ext_yahoo_chat_join)(yid->yd->client_id, room, topic, members, yid->fd); +			YAHOO_CALLBACK(ext_yahoo_chat_join)(yid->yd->client_id, id, room, topic, members, yid->fd);  		} else if(who) {  			if(y_list_length(members) != 1) {  				WARNING(("Got more than 1 member on a normal join")); @@ -1264,7 +1261,7 @@ static void yahoo_process_chat(struct yahoo_input_data *yid, struct yahoo_packet  			while(members) {  				YList *n = members->next;  				currentmember = members->data; -				YAHOO_CALLBACK(ext_yahoo_chat_userjoin)(yid->yd->client_id, room, currentmember); +				YAHOO_CALLBACK(ext_yahoo_chat_userjoin)(yid->yd->client_id, id, room, currentmember);  				y_list_free_1(members);  				members=n;  			} @@ -1272,12 +1269,12 @@ static void yahoo_process_chat(struct yahoo_input_data *yid, struct yahoo_packet  		break;  	case YAHOO_SERVICE_CHATEXIT:  		if(who) { -			YAHOO_CALLBACK(ext_yahoo_chat_userleave)(yid->yd->client_id, room, who); +			YAHOO_CALLBACK(ext_yahoo_chat_userleave)(yid->yd->client_id, id, room, who);  		}  		break;  	case YAHOO_SERVICE_COMMENT:  		if(who) { -			YAHOO_CALLBACK(ext_yahoo_chat_message)(yid->yd->client_id, who, room, msg, msgtype, utf8); +			YAHOO_CALLBACK(ext_yahoo_chat_message)(yid->yd->client_id, id, who, room, msg, msgtype, utf8);  		}  		break;  	} @@ -1336,9 +1333,9 @@ static void yahoo_process_message(struct yahoo_input_data *yid, struct yahoo_pac  		if (pkt->service == YAHOO_SERVICE_SYSMESSAGE) {  			YAHOO_CALLBACK(ext_yahoo_system_message)(yd->client_id, message->msg);  		} else if (pkt->status <= 2 || pkt->status == 5) { -			YAHOO_CALLBACK(ext_yahoo_got_im)(yd->client_id, message->from, message->msg, message->tm, pkt->status, message->utf8); +			YAHOO_CALLBACK(ext_yahoo_got_im)(yd->client_id, message->to, message->from, message->msg, message->tm, pkt->status, message->utf8);  		} else if (pkt->status == 0xffffffff) { -			YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, message->msg, 0); +			YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, message->msg, 0, E_SYSTEM);  		}  		free(message);  	} @@ -1351,13 +1348,32 @@ static void yahoo_process_status(struct yahoo_input_data *yid, struct yahoo_pack  {  	YList *l;  	struct yahoo_data *yd = yid->yd; -	char *name = NULL; -	int state = 0; -	int away = 0; -	int idle = 0; -	char *msg = NULL; + +	struct user +	{ +		char *name;	/* 7	name */ +		int   state;	/* 10	state */ +		int   flags;	/* 13	flags, bit 0 = pager, bit 1 = chat, bit 2 = game */ +		int   mobile;	/* 60	mobile */ +		char *msg;	/* 19	custom status message */ +		int   away;	/* 47	away (or invisible)*/ +		int   buddy_session;	/* 11	state */ +		int   f17;	/* 17	in chat? then what about flags? */ +		int   idle;	/* 137	seconds idle */ +		int   f138;	/* 138	state */ +		char *f184;	/* 184	state */ +		int   f192;	/* 192	state */ +		int   f10001;	/* 10001	state */ +		int   f10002;	/* 10002	state */ +		int   f198;	/* 198	state */ +		char *f197;	/* 197	state */ +		char *f205;	/* 205	state */ +		int   f213;	/* 213	state */ +	} *u; + +	YList *users = 0; -	if(pkt->service == YAHOO_SERVICE_LOGOFF && pkt->status == -1) { +	if (pkt->service == YAHOO_SERVICE_LOGOFF && pkt->status == -1) {  		YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_DUPL, NULL);  		return;  	} @@ -1381,51 +1397,87 @@ static void yahoo_process_status(struct yahoo_input_data *yid, struct yahoo_pack  			NOTICE(("key %d:%s", pair->key, pair->value));  			break;  		case 7: /* the current buddy */ -			name = pair->value; +			u = y_new0(struct user, 1); +			u->name = pair->value; +			users = y_list_prepend(users, u);  			break;  		case 10: /* state */ -			state = strtol(pair->value, NULL, 10); +			((struct user*)users->data)->state = strtol(pair->value, NULL, 10);  			break;  		case 19: /* custom status message */ -			msg = pair->value; +			((struct user*)users->data)->msg = pair->value;  			break;  		case 47: /* is it an away message or not */ -			away = atoi(pair->value); +			((struct user*)users->data)->away = atoi(pair->value);  			break;  		case 137: /* seconds idle */ -			idle = atoi(pair->value); +			((struct user*)users->data)->idle = atoi(pair->value);  			break; -		case 11: /* what is this? */ -			NOTICE(("key %d:%s", pair->key, pair->value)); +		case 11: /* this is the buddy's session id */ +			((struct user*)users->data)->buddy_session = atoi(pair->value);  			break;  		case 17: /* in chat? */ +			((struct user*)users->data)->f17 = atoi(pair->value);  			break; -		case 13: /* in pager? */ -			if (pkt->service == YAHOO_SERVICE_LOGOFF || strtol(pair->value, NULL, 10) == 0) { -				YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, name, YAHOO_STATUS_OFFLINE, NULL, 1); -				break; -			} -			if (state == YAHOO_STATUS_AVAILABLE) { -				YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, name, state, NULL, 0); -			} else if (state == YAHOO_STATUS_CUSTOM) { -				YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, name, state, msg, away); -			} else { -				YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, name, state, NULL, idle); -			} - +		case 13: /* bitmask, bit 0 = pager, bit 1 = chat, bit 2 = game */ +			((struct user*)users->data)->flags = atoi(pair->value);  			break; -		case 60:  +		case 60: /* SMS -> 1 MOBILE USER */  			/* sometimes going offline makes this 2, but invisible never sends it */ -			NOTICE(("key %d:%s", pair->key, pair->value)); -			 break; +			((struct user*)users->data)->mobile = atoi(pair->value); +			break; +		case 138: +			((struct user*)users->data)->f138 = atoi(pair->value); +			break; +		case 184: +			((struct user*)users->data)->f184 = pair->value; +			break; +		case 192: +			((struct user*)users->data)->f192 = atoi(pair->value); +			break; +		case 10001: +			((struct user*)users->data)->f10001 = atoi(pair->value); +			break; +		case 10002: +			((struct user*)users->data)->f10002 = atoi(pair->value); +			break; +		case 198: +			((struct user*)users->data)->f198 = atoi(pair->value); +			break; +		case 197: +			((struct user*)users->data)->f197 = pair->value; +			break; +		case 205: +			((struct user*)users->data)->f205 = pair->value; +			break; +		case 213: +			((struct user*)users->data)->f213 = atoi(pair->value); +			break;  		case 16: /* Custom error message */ -			YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, pair->value, 0); +			YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, pair->value, 0, E_CUSTOM);  			break;  		default:  			WARNING(("unknown status key %d:%s", pair->key, pair->value));  			break;  		}  	} +	 +	while (users) { +		YList *t = users; +		struct user *u = users->data; + +		if (u->name != NULL) { +			if (pkt->service == YAHOO_SERVICE_LOGOFF || u->flags == 0) { +				YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, u->name, YAHOO_STATUS_OFFLINE, NULL, 1, 0, 0); +			} else { +				YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, u->name, u->state, u->msg, u->away, u->idle, u->mobile); +			} +		} + +		users = y_list_remove_link(users, users); +		y_list_free_1(t); +		FREE(u); +	}  }  static void yahoo_process_list(struct yahoo_input_data *yid, struct yahoo_packet *pkt) @@ -1531,6 +1583,113 @@ static void yahoo_process_verify(struct yahoo_input_data *yid, struct yahoo_pack  } +static void yahoo_process_picture_checksum( struct yahoo_input_data *yid, struct yahoo_packet *pkt) +{ +	struct yahoo_data *yd = yid->yd; +	char *from = NULL; +	char *to = NULL; +	int checksum = 0; +	YList *l; + +	for(l = pkt->hash; l; l = l->next) +	{ +		struct yahoo_pair *pair = l->data; + +		switch(pair->key) +		{ +			case 1: +			case 4: +				from = pair->value; +			case 5: +				to = pair->value; +				break; +			case 212: +				break; +			case 192: +				checksum = atoi( pair->value ); +				break; +		} +	} + +	YAHOO_CALLBACK(ext_yahoo_got_buddyicon_checksum)(yd->client_id,to,from,checksum); +} + +static void yahoo_process_picture(struct yahoo_input_data *yid, struct yahoo_packet *pkt) +{ +	struct yahoo_data *yd = yid->yd; +	char *url = NULL; +	char *from = NULL; +	char *to = NULL; +	int status = 0; +	int checksum = 0; +	YList *l; +	 +	for(l = pkt->hash; l; l = l->next) +	{ +		struct yahoo_pair *pair = l->data; + +		switch(pair->key) +		{ +		case 1: +		case 4:		/* sender */ +			from = pair->value; +			break; +		case 5:		/* we */ +			to = pair->value; +			break; +		case 13:		/* request / sending */ +			status = atoi( pair->value ); +			break; +		case 20:		/* url */ +			url = pair->value; +			break; +		case 192:	/*checksum */ +			checksum = atoi( pair->value ); +			break; +		} +	} + +	switch( status ) +	{ +		case 1:	/* this is a request, ignore for now */ +			YAHOO_CALLBACK(ext_yahoo_got_buddyicon_request)(yd->client_id, to, from); +			break; +		case 2:	/* this is cool - we get a picture :) */ +			YAHOO_CALLBACK(ext_yahoo_got_buddyicon)(yd->client_id,to, from, url, checksum); +			break; +	} +} + +static void yahoo_process_picture_upload(struct yahoo_input_data *yid, struct yahoo_packet *pkt) +{ +	struct yahoo_data *yd = yid->yd; +	YList *l; +	char *url = NULL; + +	if ( pkt->status != 1 ) +		return;		/* something went wrong */ +	 +	for(l = pkt->hash; l; l = l->next) +	{ +		struct yahoo_pair *pair = l->data; + +		switch(pair->key) +		{ +			case 5:		/* we */ +				break; +			case 20:		/* url */ +				url = pair->value; +				break; +			case 27:		/* local filename */ +				break; +			case 38:		/* time */ +				break; +		} +	} + +	YAHOO_CALLBACK(ext_yahoo_buddyicon_uploaded)(yd->client_id, url); +} +  static void yahoo_process_auth_pre_0x0b(struct yahoo_input_data *yid,   		const char *seed, const char *sn)  { @@ -1658,8 +1817,8 @@ static void yahoo_process_auth_0x0b(struct yahoo_input_data *yid, const char *se  	md5_byte_t         result[16];  	md5_state_t        ctx; -	SHA_CTX            ctx1; -	SHA_CTX            ctx2; +	sha1_state_t       ctx1; +	sha1_state_t       ctx2;  	char *alphabet1 = "FBZDWAGHrJTLMNOPpRSKUVEXYChImkwQ";  	char *alphabet2 = "F0E1D2C3B4A59687abcdefghijklmnop"; @@ -1715,7 +1874,7 @@ static void yahoo_process_auth_0x0b(struct yahoo_input_data *yid, const char *se  	magic_ptr = (unsigned char *)seed; -	while (*magic_ptr != (int)NULL) { +	while (*magic_ptr != 0) {  		char *loc;  		/* Ignore parentheses.  */ @@ -1894,27 +2053,27 @@ static void yahoo_process_auth_0x0b(struct yahoo_input_data *yid, const char *se  	if (cnt < 64)   		memset(&(pass_hash_xor2[cnt]), 0x5c, 64-cnt); -	shaInit(&ctx1); -	shaInit(&ctx2); +	sha1_init(&ctx1); +	sha1_init(&ctx2);  	/* The first context gets the password hash XORed   	 * with 0x36 plus a magic value  	 * which we previously extrapolated from our   	 * challenge. */ -	shaUpdate(&ctx1, pass_hash_xor1, 64); +	sha1_append(&ctx1, pass_hash_xor1, 64);  	if (j >= 3 ) -		ctx1.sizeLo = 0x1ff; -	shaUpdate(&ctx1, magic_key_char, 4); -	shaFinal(&ctx1, digest1); +		ctx1.Length_Low = 0x1ff; +	sha1_append(&ctx1, magic_key_char, 4); +	sha1_finish(&ctx1, digest1);  	 /* The second context gets the password hash XORed   	  * with 0x5c plus the SHA-1 digest  	  * of the first context. */ -	shaUpdate(&ctx2, pass_hash_xor2, 64); -	shaUpdate(&ctx2, digest1, 20); -	shaFinal(&ctx2, digest2); +	sha1_append(&ctx2, pass_hash_xor2, 64); +	sha1_append(&ctx2, digest1, 20); +	sha1_finish(&ctx2, digest2);  	/* Now that we have digest2, use it to fetch   	 * characters from an alphabet to construct @@ -1985,27 +2144,27 @@ static void yahoo_process_auth_0x0b(struct yahoo_input_data *yid, const char *se  	if (cnt < 64)   		memset(&(crypt_hash_xor2[cnt]), 0x5c, 64-cnt); -	shaInit(&ctx1); -	shaInit(&ctx2); +	sha1_init(&ctx1); +	sha1_init(&ctx2);  	/* The first context gets the password hash XORed   	 * with 0x36 plus a magic value  	 * which we previously extrapolated from our   	 * challenge. */ -	shaUpdate(&ctx1, crypt_hash_xor1, 64); +	sha1_append(&ctx1, crypt_hash_xor1, 64);  	if (j >= 3 ) -		ctx1.sizeLo = 0x1ff; -	shaUpdate(&ctx1, magic_key_char, 4); -	shaFinal(&ctx1, digest1); +		ctx1.Length_Low = 0x1ff; +	sha1_append(&ctx1, magic_key_char, 4); +	sha1_finish(&ctx1, digest1);  	/* The second context gets the password hash XORed   	 * with 0x5c plus the SHA-1 digest  	 * of the first context. */ -	shaUpdate(&ctx2, crypt_hash_xor2, 64); -	shaUpdate(&ctx2, digest1, 20); -	shaFinal(&ctx2, digest2); +	sha1_append(&ctx2, crypt_hash_xor2, 64); +	sha1_append(&ctx2, digest1, 20); +	sha1_finish(&ctx2, digest2);  	/* Now that we have digest2, use it to fetch   	 * characters from an alphabet to construct @@ -2173,6 +2332,8 @@ static void yahoo_process_contact(struct yahoo_input_data *yid, struct yahoo_pac  	int state = YAHOO_STATUS_AVAILABLE;  	int online = FALSE;  	int away = 0; +	int idle = 0; +	int mobile = 0;  	YList *l; @@ -2194,12 +2355,17 @@ static void yahoo_process_contact(struct yahoo_input_data *yid, struct yahoo_pac  			online = strtol(pair->value, NULL, 10);  		else if (pair->key == 47)  			away = strtol(pair->value, NULL, 10); +		else if (pair->key == 137) +			idle = strtol(pair->value, NULL, 10); +		else if (pair->key == 60) +			mobile = strtol(pair->value, NULL, 10); +		  	}  	if (id)  		YAHOO_CALLBACK(ext_yahoo_contact_added)(yd->client_id, id, who, msg);  	else if (name) -		YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, name, state, msg, away); +		YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, name, state, msg, away, idle, mobile);  	else if(pkt->status == 0x07)  		YAHOO_CALLBACK(ext_yahoo_rejected)(yd->client_id, who, msg);  } @@ -2234,12 +2400,19 @@ static void yahoo_process_buddyadd(struct yahoo_input_data *yid, struct yahoo_pa  	if(!where)  		where = "Unknown"; -	bud = y_new0(struct yahoo_buddy, 1); -	bud->id = strdup(who); -	bud->group = strdup(where); -	bud->real_name = NULL; - -	yd->buddies = y_list_append(yd->buddies, bud); +	/* status: 0 == Successful, 1 == Error (does not exist), 2 == Already in list */ +	if( status == 0 ) { +		bud = y_new0(struct yahoo_buddy, 1); +		bud->id = strdup(who); +		bud->group = strdup(where); +		bud->real_name = NULL; +		 +		yd->buddies = y_list_append(yd->buddies, bud); +		 +		/* Possibly called already, but at least the call above doesn't +		   seem to happen every time (not anytime I tried). */ +		YAHOO_CALLBACK(ext_yahoo_contact_added)(yd->client_id, me, who, NULL); +	}  /*	YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, who, status, NULL, (status==YAHOO_STATUS_AVAILABLE?0:1)); */  } @@ -2327,7 +2500,7 @@ static void yahoo_process_ignore(struct yahoo_input_data *yid, struct yahoo_pack  	 */  /*	if(status) -		YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, status, who, 0); +		YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, who, 0, status);  */	  } @@ -2351,7 +2524,7 @@ static void yahoo_process_voicechat(struct yahoo_input_data *yid, struct yahoo_p  			room=pair->value;  	} -	NOTICE(("got voice chat invite from %s in %s", who, room)); +	NOTICE(("got voice chat invite from %s in %s to identity %s", who, room, me));  	/*   	 * send: s:0 1:me 5:who 57:room 13:1  	 * ????  s:4 5:who 10:99 19:-1615114531 @@ -2363,6 +2536,21 @@ static void yahoo_process_voicechat(struct yahoo_input_data *yid, struct yahoo_p  	 */  } +static void yahoo_process_ping(struct yahoo_input_data *yid, struct yahoo_packet *pkt) +{ +	char *errormsg = NULL; +	 +	YList *l; +	for (l = pkt->hash; l; l = l->next) { +		struct yahoo_pair *pair = l->data; +		if (pair->key == 16) +			errormsg = pair->value; +	} +	 +	NOTICE(("got ping packet")); +	YAHOO_CALLBACK(ext_yahoo_got_ping)(yid->yd->client_id, errormsg); +} +  static void _yahoo_webcam_get_server_connected(int fd, int error, void *d)  {  	struct yahoo_input_data *yid = d; @@ -2538,6 +2726,9 @@ static void yahoo_packet_process(struct yahoo_input_data *yid, struct yahoo_pack  	case YAHOO_SERVICE_WEBCAM:  		yahoo_process_webcam_key(yid, pkt);  		break; +	case YAHOO_SERVICE_PING: +		yahoo_process_ping(yid, pkt); +		break;  	case YAHOO_SERVICE_IDLE:  	case YAHOO_SERVICE_MAILSTAT:  	case YAHOO_SERVICE_CHATINVITE: @@ -2545,7 +2736,6 @@ static void yahoo_packet_process(struct yahoo_input_data *yid, struct yahoo_pack  	case YAHOO_SERVICE_NEWPERSONALMAIL:  	case YAHOO_SERVICE_ADDIDENT:  	case YAHOO_SERVICE_ADDIGNORE: -	case YAHOO_SERVICE_PING:  	case YAHOO_SERVICE_GOTGROUPRENAME:  	case YAHOO_SERVICE_GROUPRENAME:  	case YAHOO_SERVICE_PASSTHROUGH2: @@ -2557,6 +2747,15 @@ static void yahoo_packet_process(struct yahoo_input_data *yid, struct yahoo_pack  		WARNING(("unhandled service 0x%02x", pkt->service));  		yahoo_dump_unhandled(pkt);  		break; +	case YAHOO_SERVICE_PICTURE: +		yahoo_process_picture(yid, pkt); +		break; +	case YAHOO_SERVICE_PICTURE_CHECKSUM: +		yahoo_process_picture_checksum(yid, pkt); +		break; +	case YAHOO_SERVICE_PICTURE_UPLOAD: +		yahoo_process_picture_upload(yid, pkt); +		break;	  	default:  		WARNING(("unknown service 0x%02x", pkt->service));  		yahoo_dump_unhandled(pkt); @@ -3149,7 +3348,7 @@ static void yahoo_process_search_connection(struct yahoo_input_data *yid, int ov  					yct->age = atoi(cp);  					break;  				case 5:  -					if(cp != "\005") +					if(strcmp(cp, "5") != 0)  						yct->location = cp;  					k = 0;  					break; @@ -3366,7 +3565,7 @@ int yahoo_read_ready(int id, int fd, void *data)  		DEBUG_MSG(("len == %d (<= 0)", len));  		if(yid->type == YAHOO_CONNECTION_PAGER) { -			YAHOO_CALLBACK(ext_yahoo_login_response)(yid->yd->client_id, YAHOO_LOGIN_SOCK, NULL); +			YAHOO_CALLBACK(ext_yahoo_error)(yid->yd->client_id, "Connection closed by server", 1, E_CONNECTION);  		}  		yahoo_process_connection[yid->type](yid, 1); @@ -3514,11 +3713,12 @@ int yahoo_get_fd(int id)  		return yid->fd;  } -void yahoo_send_im(int id, const char *from, const char *who, const char *what, int utf8) +void yahoo_send_im(int id, const char *from, const char *who, const char *what, int utf8, int picture)  {  	struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);  	struct yahoo_packet *pkt = NULL;  	struct yahoo_data *yd; +	char pic_str[10];  	if(!yid)  		return; @@ -3527,6 +3727,8 @@ void yahoo_send_im(int id, const char *from, const char *who, const char *what,  	pkt = yahoo_packet_new(YAHOO_SERVICE_MESSAGE, YAHOO_STATUS_OFFLINE, yd->session_id); +	snprintf(pic_str, sizeof(pic_str), "%d", picture); +	  	if(from && strcmp(from, yd->user))  		yahoo_packet_hash(pkt, 0, yd->user);  	yahoo_packet_hash(pkt, 1, from?from:yd->user); @@ -3538,6 +3740,7 @@ void yahoo_send_im(int id, const char *from, const char *who, const char *what,  	yahoo_packet_hash(pkt, 63, ";0");	/* imvironment name; or ;0 */  	yahoo_packet_hash(pkt, 64, "0"); +	yahoo_packet_hash(pkt, 206, pic_str);  	yahoo_send_packet(yid, pkt, 0); @@ -3590,12 +3793,24 @@ void yahoo_set_away(int id, enum yahoo_status state, const char *msg, int away)  		service = YAHOO_SERVICE_ISBACK;  	else  		service = YAHOO_SERVICE_ISAWAY; -	pkt = yahoo_packet_new(service, yd->current_status, yd->session_id); -	snprintf(s, sizeof(s), "%d", yd->current_status); -	yahoo_packet_hash(pkt, 10, s); -	if (yd->current_status == YAHOO_STATUS_CUSTOM) { -		yahoo_packet_hash(pkt, 19, msg); -		yahoo_packet_hash(pkt, 47, away?"1":"0"); +	  +	if ((away == 2) && (yd->current_status == YAHOO_STATUS_AVAILABLE)) { +		pkt = yahoo_packet_new(YAHOO_SERVICE_ISAWAY, YAHOO_STATUS_BRB, yd->session_id); +		yahoo_packet_hash(pkt, 10, "999"); +		yahoo_packet_hash(pkt, 47, "2"); +	}else { +		pkt = yahoo_packet_new(service, YAHOO_STATUS_AVAILABLE, yd->session_id); +		snprintf(s, sizeof(s), "%d", yd->current_status); +		yahoo_packet_hash(pkt, 10, s); +		if (yd->current_status == YAHOO_STATUS_CUSTOM) { +			yahoo_packet_hash(pkt, 19, msg); +			yahoo_packet_hash(pkt, 47, (away == 2)? "2": (away) ?"1":"0"); +		} else { +			yahoo_packet_hash(pkt, 47, (away == 2)? "2": (away) ?"1":"0"); +		} +		 +		 +		  	}  	yahoo_send_packet(yid, pkt, 0); @@ -3836,7 +4051,7 @@ void yahoo_chat_keepalive (int id)  	yahoo_packet_free (pkt);  } -void yahoo_add_buddy(int id, const char *who, const char *group) +void yahoo_add_buddy(int id, const char *who, const char *group, const char *msg)  {  	struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);  	struct yahoo_data *yd; @@ -3853,6 +4068,8 @@ void yahoo_add_buddy(int id, const char *who, const char *group)  	yahoo_packet_hash(pkt, 1, yd->user);  	yahoo_packet_hash(pkt, 7, who);  	yahoo_packet_hash(pkt, 65, group); +	if (msg != NULL) /* add message/request "it's me add me" */ +		yahoo_packet_hash(pkt, 14, msg);  	yahoo_send_packet(yid, pkt, 0);  	yahoo_packet_free(pkt);  } @@ -3918,6 +4135,28 @@ void yahoo_ignore_buddy(int id, const char *who, int unignore)  	yahoo_packet_free(pkt);  } +void yahoo_stealth_buddy(int id, const char *who, int unstealth) +{ +	struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER); +	struct yahoo_data *yd; +	struct yahoo_packet *pkt; + +	if(!yid) +		return; +	yd = yid->yd; + +	if (!yd->logged_in) +		return; + +	pkt = yahoo_packet_new(YAHOO_SERVICE_STEALTH, YAHOO_STATUS_AVAILABLE, yd->session_id); +	yahoo_packet_hash(pkt, 1, yd->user); +	yahoo_packet_hash(pkt, 7, who); +	yahoo_packet_hash(pkt, 31, unstealth?"2":"1"); +	yahoo_packet_hash(pkt, 13, "2"); +	yahoo_send_packet(yid, pkt, 0); +	yahoo_packet_free(pkt); +} +  void yahoo_change_buddy_group(int id, const char *who, const char *old_group, const char *new_group)  {  	struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER); @@ -4226,6 +4465,100 @@ void yahoo_chat_logoff(int id, const char *from)  	yahoo_packet_free(pkt);  } +void yahoo_buddyicon_request(int id, const char *who) +{ +	struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER); +	struct yahoo_data *yd; +	struct yahoo_packet *pkt; + +	if( !yid ) +		return; + +	yd = yid->yd; +	 +	pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE, YAHOO_STATUS_AVAILABLE, 0); +	yahoo_packet_hash(pkt, 4, yd->user); +	yahoo_packet_hash(pkt, 5, who); +	yahoo_packet_hash(pkt, 13, "1"); +	yahoo_send_packet(yid, pkt, 0); + +	yahoo_packet_free(pkt); +} + +void yahoo_send_picture_info(int id, const char *who, const char *url, int checksum) +{ +	struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER); +	struct yahoo_data *yd; +	struct yahoo_packet *pkt; +	char checksum_str[10]; + +	if( !yid ) +		return; + +	yd = yid->yd; + +	snprintf(checksum_str, sizeof(checksum_str), "%d", checksum); + +	pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE, YAHOO_STATUS_AVAILABLE, 0); +	yahoo_packet_hash(pkt, 1, yd->user); +	yahoo_packet_hash(pkt, 4, yd->user); +	yahoo_packet_hash(pkt, 5, who); +	yahoo_packet_hash(pkt, 13, "2"); +	yahoo_packet_hash(pkt, 20, url); +	yahoo_packet_hash(pkt, 192, checksum_str); +	yahoo_send_packet(yid, pkt, 0); + +	yahoo_packet_free(pkt); +} + +void yahoo_send_picture_update(int id, const char *who, int type) +{ +	struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER); +	struct yahoo_data *yd; +	struct yahoo_packet *pkt; +	char type_str[10]; + +	if( !yid ) +		return; + +	yd = yid->yd; + +	snprintf(type_str, sizeof(type_str), "%d", type); + +	pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE_UPDATE, YAHOO_STATUS_AVAILABLE, 0); +	yahoo_packet_hash(pkt, 1, yd->user); +	yahoo_packet_hash(pkt, 5, who); +	yahoo_packet_hash(pkt, 206, type_str); +	yahoo_send_packet(yid, pkt, 0); + +	yahoo_packet_free(pkt); +} + +void yahoo_send_picture_checksum(int id, const char *who, int checksum) +{ +	struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER); +	struct yahoo_data *yd; +	struct yahoo_packet *pkt; +	char checksum_str[10]; + +	if( !yid ) +		return; + +	yd = yid->yd; +	 +	snprintf(checksum_str, sizeof(checksum_str), "%d", checksum); + +	pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE_CHECKSUM, YAHOO_STATUS_AVAILABLE, 0); +	yahoo_packet_hash(pkt, 1, yd->user); +	if( who != 0 ) +		yahoo_packet_hash(pkt, 5, who); +	yahoo_packet_hash(pkt, 192, checksum_str); +	yahoo_packet_hash(pkt, 212, "1"); +	yahoo_send_packet(yid, pkt, 0); + +	yahoo_packet_free(pkt); +} +  void yahoo_webcam_close_feed(int id, const char *who)  {  	struct yahoo_input_data *yid = find_input_by_id_and_webcam_user(id, who); @@ -4429,6 +4762,99 @@ struct send_file_data {  	void *user_data;  }; +static void _yahoo_send_picture_connected(int id, int fd, int error, void *data) +{ +	struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_FT); +	struct send_file_data *sfd = data; +	struct yahoo_packet *pkt = sfd->pkt; +	unsigned char buff[1024]; + +	if(fd <= 0) { +		sfd->callback(id, fd, error, sfd->user_data); +		FREE(sfd); +		yahoo_packet_free(pkt); +		inputs = y_list_remove(inputs, yid); +		FREE(yid); +		return; +	} + +	yid->fd = fd; +	yahoo_send_packet(yid, pkt, 8); +	yahoo_packet_free(pkt); + +	snprintf((char *)buff, sizeof(buff), "29"); +	buff[2] = 0xc0; +	buff[3] = 0x80; +	 +	write(yid->fd, buff, 4); + +	/*	YAHOO_CALLBACK(ext_yahoo_add_handler)(nyd->fd, YAHOO_INPUT_READ); */ + +	sfd->callback(id, fd, error, sfd->user_data); +	FREE(sfd); +	inputs = y_list_remove(inputs, yid); +	/* +	while(yahoo_tcp_readline(buff, sizeof(buff), nyd->fd) > 0) { +	if(!strcmp(buff, "")) +	break; +} + +	*/ +	yahoo_input_close(yid); +} + +void yahoo_send_picture(int id, const char *name, unsigned long size, +							yahoo_get_fd_callback callback, void *data) +{ +	struct yahoo_data *yd = find_conn_by_id(id); +	struct yahoo_input_data *yid; +	struct yahoo_server_settings *yss; +	struct yahoo_packet *pkt = NULL; +	char size_str[10]; +	char expire_str[10]; +	long content_length=0; +	unsigned char buff[1024]; +	char url[255]; +	struct send_file_data *sfd; + +	if(!yd) +		return; + +	yss = yd->server_settings; + +	yid = y_new0(struct yahoo_input_data, 1); +	yid->yd = yd; +	yid->type = YAHOO_CONNECTION_FT; + +	pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE_UPLOAD, YAHOO_STATUS_AVAILABLE, yd->session_id); + +	snprintf(size_str, sizeof(size_str), "%ld", size); +	snprintf(expire_str, sizeof(expire_str), "%ld", (long)604800); + +	yahoo_packet_hash(pkt, 0, yd->user); +	yahoo_packet_hash(pkt, 1, yd->user); +	yahoo_packet_hash(pkt, 14, ""); +	yahoo_packet_hash(pkt, 27, name); +	yahoo_packet_hash(pkt, 28, size_str); +	yahoo_packet_hash(pkt, 38, expire_str); +	 + +	content_length = YAHOO_PACKET_HDRLEN + yahoo_packet_length(pkt); + +	snprintf(url, sizeof(url), "http://%s:%d/notifyft", +				yss->filetransfer_host, yss->filetransfer_port); +	snprintf((char *)buff, sizeof(buff), "Y=%s; T=%s", +				 yd->cookie_y, yd->cookie_t); +	inputs = y_list_prepend(inputs, yid); + +	sfd = y_new0(struct send_file_data, 1); +	sfd->pkt = pkt; +	sfd->callback = callback; +	sfd->user_data = data; +	yahoo_http_post(yid->yd->client_id, url, (char *)buff, content_length+4+size, +						_yahoo_send_picture_connected, sfd); +} +  static void _yahoo_send_file_connected(int id, int fd, int error, void *data)  {  	struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_FT); diff --git a/protocols/yahoo/yahoo.c b/protocols/yahoo/yahoo.c index 1c3c73d9..36579d66 100644 --- a/protocols/yahoo/yahoo.c +++ b/protocols/yahoo/yahoo.c @@ -57,20 +57,20 @@ struct byahoo_input_data  struct byahoo_conf_invitation  {  	char *name; -	struct conversation *c; +	struct groupchat *c;  	int yid;  	YList *members; -	struct gaim_connection *gc; +	struct im_connection *ic;  };  static GSList *byahoo_inputs = NULL;  static int byahoo_chat_id = 0; -static char *byahoo_strip( char *in ) +static char *byahoo_strip( const char *in )  {  	int len; -	/* This should get rid of HTML tags at the beginning of the string. */ +	/* This should get rid of the markup noise at the beginning of the string. */  	while( *in )  	{  		if( g_strncasecmp( in, "<font", 5 ) == 0 || @@ -85,7 +85,7 @@ static char *byahoo_strip( char *in )  		}  		else if( strncmp( in, "\e[", 2 ) == 0 )  		{ -			char *s; +			const char *s;  			for( s = in + 2; *s && *s != 'm'; s ++ ); @@ -100,17 +100,23 @@ static char *byahoo_strip( char *in )  		}  	} -	/* This is supposed to get rid of the closing HTML tags at the end of the line. */ +	/* This is supposed to get rid of the noise at the end of the line. */  	len = strlen( in ); -	while( len > 0 && in[len-1] == '>' ) +	while( len > 0 && ( in[len-1] == '>' || in[len-1] == 'm' ) )  	{  		int blen = len; +		const char *search; -		len --; -		while( len > 0 && ( in[len] != '<' || in[len+1] != '/' ) ) +		if( in[len-1] == '>' ) +			search = "</"; +		else +			search = "\e["; +		 +		len -= 3; +		while( len > 0 && strncmp( in + len, search, 2 ) != 0 )  			len --; -		if( len == 0 && ( in[len] != '<' || in[len+1] != '/' ) ) +		if( len <= 0 && strncmp( in, search, 2 ) != 0 )  		{  			len = blen;  			break; @@ -120,26 +126,31 @@ static char *byahoo_strip( char *in )  	return( g_strndup( in, len ) );  } -static void byahoo_login( struct aim_user *user ) +static void byahoo_init( account_t *acc ) +{ +	set_add( &acc->set, "mail_notifications", "false", set_eval_bool, acc ); +} + +static void byahoo_login( account_t *acc )  { -	struct gaim_connection *gc = new_gaim_conn( user ); -	struct byahoo_data *yd = gc->proto_data = g_new0( struct byahoo_data, 1 ); +	struct im_connection *ic = imcb_new( acc ); +	struct byahoo_data *yd = ic->proto_data = g_new0( struct byahoo_data, 1 );  	yd->logged_in = FALSE;  	yd->current_status = YAHOO_STATUS_AVAILABLE; -	set_login_progress( gc, 1, "Connecting" ); -	yd->y2_id = yahoo_init( user->username, user->password ); +	imcb_log( ic, "Connecting" ); +	yd->y2_id = yahoo_init( acc->user, acc->pass );  	yahoo_login( yd->y2_id, yd->current_status );  } -static void byahoo_close( struct gaim_connection *gc ) +static void byahoo_logout( struct im_connection *ic )  { -	struct byahoo_data *yd = (struct byahoo_data *) gc->proto_data; +	struct byahoo_data *yd = (struct byahoo_data *) ic->proto_data;  	GSList *l; -	while( gc->conversations ) -		serv_got_chat_left( gc, gc->conversations->id ); +	while( ic->groupchats ) +		imcb_chat_free( ic->groupchats );  	for( l = yd->buddygroups; l; l = l->next )  	{ @@ -159,50 +170,55 @@ static void byahoo_close( struct gaim_connection *gc )  	g_free( yd );  } -static void byahoo_get_info(struct gaim_connection *gc, char *who)  +static void byahoo_get_info(struct im_connection *ic, char *who)   {  	/* Just make an URL and let the user fetch the info */ -	serv_got_crap(gc, "%s\n%s: %s%s", _("User Info"),  +	imcb_log(ic, "%s\n%s: %s%s", _("User Info"),   			_("For now, fetch yourself"), yahoo_get_profile_url(),  			who);  } -static int byahoo_send_im( struct gaim_connection *gc, char *who, char *what, int len, int flags ) +static int byahoo_buddy_msg( struct im_connection *ic, char *who, char *what, int flags )  { -	struct byahoo_data *yd = gc->proto_data; +	struct byahoo_data *yd = ic->proto_data; -	yahoo_send_im( yd->y2_id, NULL, who, what, 1 ); +	yahoo_send_im( yd->y2_id, NULL, who, what, 1, 0 );  	return 1;  } -static int byahoo_send_typing( struct gaim_connection *gc, char *who, int typing ) +static int byahoo_send_typing( struct im_connection *ic, char *who, int typing )  { -	struct byahoo_data *yd = gc->proto_data; +	struct byahoo_data *yd = ic->proto_data; -	yahoo_send_typing( yd->y2_id, NULL, who, typing ); +	yahoo_send_typing( yd->y2_id, NULL, who, ( typing & OPT_TYPING ) != 0 );  	return 1;  } -static void byahoo_set_away( struct gaim_connection *gc, char *state, char *msg ) +static void byahoo_set_away( struct im_connection *ic, char *state, char *msg )  { -	struct byahoo_data *yd = (struct byahoo_data *) gc->proto_data; +	struct byahoo_data *yd = (struct byahoo_data *) ic->proto_data; -	gc->away = NULL; +	ic->away = NULL; -	if( msg ) +	if( state && msg && g_strcasecmp( state, msg ) != 0 )  	{  		yd->current_status = YAHOO_STATUS_CUSTOM; -		gc->away = ""; +		ic->away = "";  	} -	if( state ) +	else if( state )  	{ -		gc->away = ""; +		/* Set msg to NULL since (if it isn't NULL already) it's equal +		   to state. msg must be empty if we want to use an existing +		   away state. */ +		msg = NULL; +		 +		ic->away = "";  		if( g_strcasecmp( state, "Available" ) == 0 )  		{  			yd->current_status = YAHOO_STATUS_AVAILABLE; -			gc->away = NULL; +			ic->away = NULL;  		}  		else if( g_strcasecmp( state, "Be Right Back" ) == 0 )  			yd->current_status = YAHOO_STATUS_BRB; @@ -228,19 +244,16 @@ static void byahoo_set_away( struct gaim_connection *gc, char *state, char *msg  		{  			yd->current_status = YAHOO_STATUS_AVAILABLE; -			gc->away = NULL; +			ic->away = NULL;  		}  	}  	else  		yd->current_status = YAHOO_STATUS_AVAILABLE; -	if( yd->current_status == YAHOO_STATUS_INVISIBLE ) -		yahoo_set_away( yd->y2_id, yd->current_status, NULL, gc->away != NULL ); -	else -		yahoo_set_away( yd->y2_id, yd->current_status, msg, gc->away != NULL ); +	yahoo_set_away( yd->y2_id, yd->current_status, msg, ic->away != NULL ? 2 : 0 );  } -static GList *byahoo_away_states( struct gaim_connection *gc ) +static GList *byahoo_away_states( struct im_connection *ic )  {  	GList *m = NULL; @@ -260,23 +273,23 @@ static GList *byahoo_away_states( struct gaim_connection *gc )  	return m;  } -static void byahoo_keepalive( struct gaim_connection *gc ) +static void byahoo_keepalive( struct im_connection *ic )  { -	struct byahoo_data *yd = gc->proto_data; +	struct byahoo_data *yd = ic->proto_data;  	yahoo_keepalive( yd->y2_id );  } -static void byahoo_add_buddy( struct gaim_connection *gc, char *who ) +static void byahoo_add_buddy( struct im_connection *ic, char *who, char *group )  { -	struct byahoo_data *yd = (struct byahoo_data *) gc->proto_data; +	struct byahoo_data *yd = (struct byahoo_data *) ic->proto_data; -	yahoo_add_buddy( yd->y2_id, who, BYAHOO_DEFAULT_GROUP ); +	yahoo_add_buddy( yd->y2_id, who, group ? group : BYAHOO_DEFAULT_GROUP, NULL );  } -static void byahoo_remove_buddy( struct gaim_connection *gc, char *who, char *group ) +static void byahoo_remove_buddy( struct im_connection *ic, char *who, char *group )  { -	struct byahoo_data *yd = (struct byahoo_data *) gc->proto_data; +	struct byahoo_data *yd = (struct byahoo_data *) ic->proto_data;  	GSList *bgl;  	yahoo_remove_buddy( yd->y2_id, who, BYAHOO_DEFAULT_GROUP ); @@ -290,90 +303,39 @@ static void byahoo_remove_buddy( struct gaim_connection *gc, char *who, char *gr  	}  } -static char *byahoo_get_status_string( struct gaim_connection *gc, int stat ) +static void byahoo_chat_msg( struct groupchat *c, char *message, int flags )  { -	enum yahoo_status a = stat >> 1; +	struct byahoo_data *yd = (struct byahoo_data *) c->ic->proto_data; -	switch (a) -	{ -	case YAHOO_STATUS_BRB: -		return "Be Right Back"; -	case YAHOO_STATUS_BUSY: -		return "Busy"; -	case YAHOO_STATUS_NOTATHOME: -		return "Not At Home"; -	case YAHOO_STATUS_NOTATDESK: -		return "Not At Desk"; -	case YAHOO_STATUS_NOTINOFFICE: -		return "Not In Office"; -	case YAHOO_STATUS_ONPHONE: -		return "On Phone"; -	case YAHOO_STATUS_ONVACATION: -		return "On Vacation"; -	case YAHOO_STATUS_OUTTOLUNCH: -		return "Out To Lunch"; -	case YAHOO_STATUS_STEPPEDOUT: -		return "Stepped Out"; -	case YAHOO_STATUS_INVISIBLE: -		return "Invisible"; -	case YAHOO_STATUS_CUSTOM: -		return "Away"; -	case YAHOO_STATUS_IDLE: -		return "Idle"; -	case YAHOO_STATUS_OFFLINE: -		return "Offline"; -	case YAHOO_STATUS_NOTIFY: -		return "Notify"; -	default: -		return "Away"; -	} -} - -static int byahoo_chat_send( struct gaim_connection *gc, int id, char *message ) -{ -	struct byahoo_data *yd = (struct byahoo_data *) gc->proto_data; -	struct conversation *c; -	 -	for( c = gc->conversations; c && c->id != id; c = c->next ); -  	yahoo_conference_message( yd->y2_id, NULL, c->data, c->title, message, 1 ); -	 -	return( 0 );  } -static void byahoo_chat_invite( struct gaim_connection *gc, int id, char *msg, char *who ) +static void byahoo_chat_invite( struct groupchat *c, char *who, char *msg )  { -	struct byahoo_data *yd = (struct byahoo_data *) gc->proto_data; -	struct conversation *c; -	 -	for( c = gc->conversations; c && c->id != id; c = c->next ); +	struct byahoo_data *yd = (struct byahoo_data *) c->ic->proto_data; -	yahoo_conference_invite( yd->y2_id, NULL, c->data, c->title, msg ); +	yahoo_conference_invite( yd->y2_id, NULL, c->data, c->title, msg ? msg : "" );  } -static void byahoo_chat_leave( struct gaim_connection *gc, int id ) +static void byahoo_chat_leave( struct groupchat *c )  { -	struct byahoo_data *yd = (struct byahoo_data *) gc->proto_data; -	struct conversation *c; -	 -	for( c = gc->conversations; c && c->id != id; c = c->next ); +	struct byahoo_data *yd = (struct byahoo_data *) c->ic->proto_data;  	yahoo_conference_logoff( yd->y2_id, NULL, c->data, c->title ); -	serv_got_chat_left( gc, c->id ); +	imcb_chat_free( c );  } -static int byahoo_chat_open( struct gaim_connection *gc, char *who ) +static struct groupchat *byahoo_chat_with( struct im_connection *ic, char *who )  { -	struct byahoo_data *yd = (struct byahoo_data *) gc->proto_data; -	struct conversation *c; +	struct byahoo_data *yd = (struct byahoo_data *) ic->proto_data; +	struct groupchat *c;  	char *roomname;  	YList *members; -	roomname = g_new0( char, strlen( gc->username ) + 16 ); -	g_snprintf( roomname, strlen( gc->username ) + 16, "%s-Bee-%d", gc->username, byahoo_chat_id ); +	roomname = g_strdup_printf( "%s-Bee-%d", ic->acc->user, byahoo_chat_id ); -	c = serv_got_joined_chat( gc, ++byahoo_chat_id, roomname ); -	add_chat_buddy( c, gc->username ); +	c = imcb_chat_new( ic, roomname ); +	imcb_chat_add_buddy( c, ic->acc->user );  	/* FIXME: Free this thing when the chat's destroyed. We can't *always*  	          do this because it's not always created here. */ @@ -384,48 +346,50 @@ static int byahoo_chat_open( struct gaim_connection *gc, char *who )  	g_free( roomname ); -	return( 1 ); +	return c;  } -void byahoo_init( ) +void byahoo_initmodule( )  {  	struct prpl *ret = g_new0(struct prpl, 1);  	ret->name = "yahoo"; +	ret->init = byahoo_init;  	ret->login = byahoo_login; -	ret->close = byahoo_close; -	ret->send_im = byahoo_send_im; +	ret->keepalive = byahoo_keepalive; +	ret->logout = byahoo_logout; +	 +	ret->buddy_msg = byahoo_buddy_msg;  	ret->get_info = byahoo_get_info;  	ret->away_states = byahoo_away_states;  	ret->set_away = byahoo_set_away; -	ret->keepalive = byahoo_keepalive;  	ret->add_buddy = byahoo_add_buddy;  	ret->remove_buddy = byahoo_remove_buddy; -	ret->get_status_string = byahoo_get_status_string;  	ret->send_typing = byahoo_send_typing; -	ret->chat_send = byahoo_chat_send; +	ret->chat_msg = byahoo_chat_msg;  	ret->chat_invite = byahoo_chat_invite;  	ret->chat_leave = byahoo_chat_leave; -	ret->chat_open = byahoo_chat_open; -	ret->cmp_buddynames = g_strcasecmp; +	ret->chat_with = byahoo_chat_with; + +	ret->handle_cmp = g_strcasecmp;  	register_protocol(ret);  } -static struct gaim_connection *byahoo_get_gc_by_id( int id ) +static struct im_connection *byahoo_get_ic_by_id( int id )  {  	GSList *l; -	struct gaim_connection *gc; +	struct im_connection *ic;  	struct byahoo_data *yd;  	for( l = get_connections(); l; l = l->next )  	{ -		gc = l->data; -		yd = gc->proto_data; +		ic = l->data; +		yd = ic->proto_data; -		if( !strcmp(gc->prpl->name, "yahoo") && yd->y2_id == id ) -			return( gc ); +		if( strcmp( ic->acc->prpl->name, "yahoo" ) == 0 && yd->y2_id == id ) +			return( ic );  	}  	return( NULL ); @@ -442,11 +406,11 @@ struct byahoo_connect_callback_data  	int id;  }; -void byahoo_connect_callback( gpointer data, gint source, GaimInputCondition cond ) +void byahoo_connect_callback( gpointer data, gint source, b_input_condition cond )  {  	struct byahoo_connect_callback_data *d = data; -	if( !byahoo_get_gc_by_id( d->id ) ) +	if( !byahoo_get_ic_by_id( d->id ) )  	{  		g_free( d );  		return; @@ -464,18 +428,17 @@ struct byahoo_read_ready_data  	gpointer data;  }; -void byahoo_read_ready_callback( gpointer data, gint source, GaimInputCondition cond ) +gboolean byahoo_read_ready_callback( gpointer data, gint source, b_input_condition cond )  {  	struct byahoo_read_ready_data *d = data; -	if( !byahoo_get_gc_by_id( d->id ) ) -	{ +	if( !byahoo_get_ic_by_id( d->id ) )  		/* WTF doesn't libyahoo clean this up? */ -		ext_yahoo_remove_handler( d->id, d->tag ); -		return; -	} +		return FALSE;  	yahoo_read_ready( d->id, d->fd, d->data ); +	 +	return TRUE;  }  struct byahoo_write_ready_data @@ -486,26 +449,25 @@ struct byahoo_write_ready_data  	gpointer data;  }; -void byahoo_write_ready_callback( gpointer data, gint source, GaimInputCondition cond ) +gboolean byahoo_write_ready_callback( gpointer data, gint source, b_input_condition cond )  {  	struct byahoo_write_ready_data *d = data; -	if( !byahoo_get_gc_by_id( d->id ) ) -	{ +	if( !byahoo_get_ic_by_id( d->id ) )  		/* WTF doesn't libyahoo clean this up? */ -		ext_yahoo_remove_handler( d->id, d->tag ); -		return; -	} +		return FALSE;  	yahoo_write_ready( d->id, d->fd, d->data ); +	 +	return FALSE;  } -void ext_yahoo_login_response( int id, int succ, char *url ) +void ext_yahoo_login_response( int id, int succ, const char *url )  { -	struct gaim_connection *gc = byahoo_get_gc_by_id( id ); +	struct im_connection *ic = byahoo_get_ic_by_id( id );  	struct byahoo_data *yd = NULL; -	if( gc == NULL ) +	if( ic == NULL )  	{  		/* libyahoo2 seems to call this one twice when something  		   went wrong sometimes. Don't know why. Because we clean @@ -515,18 +477,18 @@ void ext_yahoo_login_response( int id, int succ, char *url )  		return;  	} -	yd = (struct byahoo_data *) gc->proto_data; +	yd = (struct byahoo_data *) ic->proto_data;  	if( succ == YAHOO_LOGIN_OK )  	{ -		account_online( gc ); +		imcb_connected( ic );  		yd->logged_in = TRUE;  	}  	else  	{  		char *errstr; -		char *s; +		int allow_reconnect = TRUE;  		yd->logged_in = FALSE; @@ -539,7 +501,7 @@ void ext_yahoo_login_response( int id, int succ, char *url )  		else if( succ == YAHOO_LOGIN_DUPL )  		{  			errstr = "Logged in on a different machine or device"; -			gc->wants_to_die = TRUE; +			allow_reconnect = FALSE;  		}  		else if( succ == YAHOO_LOGIN_SOCK )  			errstr = "Socket problem"; @@ -547,31 +509,18 @@ void ext_yahoo_login_response( int id, int succ, char *url )  			errstr = "Unknown error";  		if( url && *url ) -		{ -			s = g_malloc( strlen( "Error %d (%s). See %s for more information." ) + strlen( url ) + strlen( errstr ) + 16 ); -			sprintf( s, "Error %d (%s). See %s for more information.", succ, errstr, url ); -		} +			imcb_error( ic, "Error %d (%s). See %s for more information.", succ, errstr, url );  		else -		{ -			s = g_malloc( strlen( "Error %d (%s)" ) + strlen( errstr ) + 16 ); -			sprintf( s, "Error %d (%s)", succ, errstr ); -		} -		 -		if( yd->logged_in ) -			hide_login_progress_error( gc, s ); -		else -			hide_login_progress( gc, s ); -		 -		g_free( s ); +			imcb_error( ic, "Error %d (%s)", succ, errstr ); -		signoff( gc ); +		imc_logout( ic, allow_reconnect );  	}  }  void ext_yahoo_got_buddies( int id, YList *buds )  { -	struct gaim_connection *gc = byahoo_get_gc_by_id( id ); -	struct byahoo_data *yd = gc->proto_data; +	struct im_connection *ic = byahoo_get_ic_by_id( id ); +	struct byahoo_data *yd = ic->proto_data;  	YList *bl = buds;  	while( bl ) @@ -588,7 +537,9 @@ void ext_yahoo_got_buddies( int id, YList *buds )  			yd->buddygroups = g_slist_append( yd->buddygroups, bg );  		} -		add_buddy( gc, b->group, b->id, b->real_name ); +		imcb_add_buddy( ic, b->id, b->group ); +		imcb_rename_buddy( ic, b->id, b->real_name ); +		  		bl = bl->next;  	}  } @@ -605,71 +556,124 @@ void ext_yahoo_got_cookies( int id )  {  } -void ext_yahoo_status_changed( int id, char *who, int stat, char *msg, int away ) +void ext_yahoo_status_changed( int id, const char *who, int stat, const char *msg, int away, int idle, int mobile )  { -	struct gaim_connection *gc = byahoo_get_gc_by_id( id ); +	struct im_connection *ic = byahoo_get_ic_by_id( id ); +	char *state_string = NULL; +	int flags = OPT_LOGGED_IN; +	 +	if( away ) +		flags |= OPT_AWAY; +	 +	switch (stat) +	{ +	case YAHOO_STATUS_BRB: +		state_string = "Be Right Back"; +		break; +	case YAHOO_STATUS_BUSY: +		state_string = "Busy"; +		break; +	case YAHOO_STATUS_NOTATHOME: +		state_string = "Not At Home"; +		break; +	case YAHOO_STATUS_NOTATDESK: +		state_string = "Not At Desk"; +		break; +	case YAHOO_STATUS_NOTINOFFICE: +		state_string = "Not In Office"; +		break; +	case YAHOO_STATUS_ONPHONE: +		state_string = "On Phone"; +		break; +	case YAHOO_STATUS_ONVACATION: +		state_string = "On Vacation"; +		break; +	case YAHOO_STATUS_OUTTOLUNCH: +		state_string = "Out To Lunch"; +		break; +	case YAHOO_STATUS_STEPPEDOUT: +		state_string = "Stepped Out"; +		break; +	case YAHOO_STATUS_INVISIBLE: +		state_string = "Invisible"; +		break; +	case YAHOO_STATUS_CUSTOM: +		state_string = "Away"; +		break; +	case YAHOO_STATUS_IDLE: +		state_string = "Idle"; +		break; +	case YAHOO_STATUS_OFFLINE: +		state_string = "Offline"; +		flags = 0; +		break; +	case YAHOO_STATUS_NOTIFY: +		state_string = "Notify"; +		break; +	} -	serv_got_update( gc, who, stat != YAHOO_STATUS_OFFLINE, 0, 0, -	                 ( stat == YAHOO_STATUS_IDLE ) ? away : 0, -	                 ( stat != YAHOO_STATUS_AVAILABLE ) | ( stat << 1 ), 0 ); +	imcb_buddy_status( ic, who, flags, state_string, msg ); +	 +	/* Not implemented yet... +	if( stat == YAHOO_STATUS_IDLE ) +		imcb_buddy_times( ic, who, 0, away ); +	*/  } -void ext_yahoo_got_im( int id, char *who, char *msg, long tm, int stat, int utf8 ) +void ext_yahoo_got_im( int id, const char *me, const char *who, const char *msg, long tm, int stat, int utf8 )  { -	struct gaim_connection *gc = byahoo_get_gc_by_id( id ); -	char *m = byahoo_strip( msg ); +	struct im_connection *ic = byahoo_get_ic_by_id( id ); +	char *m; -	serv_got_im( gc, who, m, 0, 0, strlen( m ) ); -	g_free( m ); +	if( msg ) +	{ +		m = byahoo_strip( msg ); +		imcb_buddy_msg( ic, (char*) who, (char*) m, 0, 0 ); +		g_free( m ); +	}  } -void ext_yahoo_got_file( int id, char *who, char *url, long expires, char *msg, char *fname, unsigned long fesize ) +void ext_yahoo_got_file( int id, +                         const char *ignored, +                         const char *who, const char *url, long expires, const char *msg, const char *fname, unsigned long fesize )  { -	struct gaim_connection *gc = byahoo_get_gc_by_id( id ); +	struct im_connection *ic = byahoo_get_ic_by_id( id ); -	serv_got_crap( gc, "Got a file transfer (file = %s) from %s. Ignoring for now due to lack of support.", fname, who ); +	imcb_log( ic, "Got a file transfer (file = %s) from %s. Ignoring for now due to lack of support.", fname, who );  } -void ext_yahoo_typing_notify( int id, char *who, int stat ) +void ext_yahoo_typing_notify( int id, const char *ignored, const char *who, int stat )  { -	struct gaim_connection *gc = byahoo_get_gc_by_id( id ); -	if (stat == 1) { -		/* User is typing */ -		serv_got_typing( gc, who, 1, 1 ); -	} -	else { -		/* User stopped typing */ -		serv_got_typing( gc, who, 1, 0 ); -	} +	struct im_connection *ic = byahoo_get_ic_by_id( id ); +	 +	if( stat == 1 ) +		imcb_buddy_typing( ic, (char*) who, OPT_TYPING ); +	else +		imcb_buddy_typing( ic, (char*) who, 0 );  } -void ext_yahoo_system_message( int id, char *msg ) +void ext_yahoo_system_message( int id, const char *msg )  { -	struct gaim_connection *gc = byahoo_get_gc_by_id( id ); +	struct im_connection *ic = byahoo_get_ic_by_id( id ); -	serv_got_crap( gc, "Yahoo! system message: %s", msg ); +	imcb_log( ic, "Yahoo! system message: %s", msg );  } -void ext_yahoo_webcam_invite( int id, char *from ) +void ext_yahoo_webcam_invite( int id, const char *ignored, const char *from )  { -	struct gaim_connection *gc = byahoo_get_gc_by_id( id ); +	struct im_connection *ic = byahoo_get_ic_by_id( id ); -	serv_got_crap( gc, "Got a webcam invitation from %s. IRC+webcams is a no-no though...", from ); +	imcb_log( ic, "Got a webcam invitation from %s. IRC+webcams is a no-no though...", from );  } -void ext_yahoo_error( int id, char *err, int fatal ) +void ext_yahoo_error( int id, const char *err, int fatal, int num )  { -	struct gaim_connection *gc = byahoo_get_gc_by_id( id ); +	struct im_connection *ic = byahoo_get_ic_by_id( id ); +	 +	imcb_error( ic, "%s", err );  	if( fatal ) -	{ -		hide_login_progress_error( gc, err ); -		signoff( gc ); -	} -	else -	{ -		do_error_dialog( gc, err, "Yahoo! error" ); -	} +		imc_logout( ic, TRUE );  }  /* TODO: Clear up the mess of inp and d structures */ @@ -686,7 +690,7 @@ int ext_yahoo_add_handler( int id, int fd, yahoo_input_condition cond, void *dat  		d->data = data;  		inp->d = d; -		d->tag = inp->h = gaim_input_add( fd, GAIM_INPUT_READ, (GaimInputFunction) byahoo_read_ready_callback, (gpointer) d ); +		d->tag = inp->h = b_input_add( fd, GAIM_INPUT_READ, (b_event_handler) byahoo_read_ready_callback, (gpointer) d );  	}  	else if( cond == YAHOO_INPUT_WRITE )  	{ @@ -697,7 +701,7 @@ int ext_yahoo_add_handler( int id, int fd, yahoo_input_condition cond, void *dat  		d->data = data;  		inp->d = d; -		d->tag = inp->h = gaim_input_add( fd, GAIM_INPUT_WRITE, (GaimInputFunction) byahoo_write_ready_callback, (gpointer) d ); +		d->tag = inp->h = b_input_add( fd, GAIM_INPUT_WRITE, (b_event_handler) byahoo_write_ready_callback, (gpointer) d );  	}  	else  	{ @@ -728,16 +732,16 @@ void ext_yahoo_remove_handler( int id, int tag )  		l = l->next;  	} -	gaim_input_remove( tag ); +	b_event_remove( tag );  } -int ext_yahoo_connect_async( int id, char *host, int port, yahoo_connect_callback callback, void *data ) +int ext_yahoo_connect_async( int id, const char *host, int port, yahoo_connect_callback callback, void *data )  {  	struct byahoo_connect_callback_data *d;  	int fd;  	d = g_new0( struct byahoo_connect_callback_data, 1 ); -	if( ( fd = proxy_connect( host, port, (GaimInputFunction) byahoo_connect_callback, (gpointer) d ) ) < 0 ) +	if( ( fd = proxy_connect( host, port, (b_event_handler) byahoo_connect_callback, (gpointer) d ) ) < 0 )  	{  		g_free( d );  		return( fd ); @@ -752,7 +756,7 @@ int ext_yahoo_connect_async( int id, char *host, int port, yahoo_connect_callbac  /* Because we don't want asynchronous connects in BitlBee, and because     libyahoo doesn't seem to use this one anyway, this one is now defunct. */ -int ext_yahoo_connect(char *host, int port) +int ext_yahoo_connect(const char *host, int port)  {  #if 0  	struct sockaddr_in serv_addr; @@ -795,7 +799,7 @@ int ext_yahoo_connect(char *host, int port)  static void byahoo_accept_conf( gpointer w, struct byahoo_conf_invitation *inv )  {  	yahoo_conference_logon( inv->yid, NULL, inv->members, inv->name ); -	add_chat_buddy( inv->c, inv->gc->username ); +	imcb_chat_add_buddy( inv->c, inv->ic->acc->user );  	g_free( inv->name );  	g_free( inv );  } @@ -803,14 +807,15 @@ static void byahoo_accept_conf( gpointer w, struct byahoo_conf_invitation *inv )  static void byahoo_reject_conf( gpointer w, struct byahoo_conf_invitation *inv )  {  	yahoo_conference_decline( inv->yid, NULL, inv->members, inv->name, "User rejected groupchat" ); -	serv_got_chat_left( inv->gc, inv->c->id ); +	imcb_chat_free( inv->c );  	g_free( inv->name );  	g_free( inv );  } -void ext_yahoo_got_conf_invite( int id, char *who, char *room, char *msg, YList *members ) +void ext_yahoo_got_conf_invite( int id, const char *ignored, +                                const char *who, const char *room, const char *msg, YList *members )  { -	struct gaim_connection *gc = byahoo_get_gc_by_id( id ); +	struct im_connection *ic = byahoo_get_ic_by_id( id );  	struct byahoo_conf_invitation *inv;  	char txt[1024];  	YList *m; @@ -818,117 +823,128 @@ void ext_yahoo_got_conf_invite( int id, char *who, char *room, char *msg, YList  	inv = g_malloc( sizeof( struct byahoo_conf_invitation ) );  	memset( inv, 0, sizeof( struct byahoo_conf_invitation ) );  	inv->name = g_strdup( room ); -	inv->c = serv_got_joined_chat( gc, ++byahoo_chat_id, room ); +	inv->c = imcb_chat_new( ic, (char*) room );  	inv->c->data = members;  	inv->yid = id;  	inv->members = members; -	inv->gc = gc; +	inv->ic = ic;  	for( m = members; m; m = m->next ) -		if( g_strcasecmp( m->data, gc->username ) != 0 ) -			add_chat_buddy( inv->c, m->data ); +		if( g_strcasecmp( m->data, ic->acc->user ) != 0 ) +			imcb_chat_add_buddy( inv->c, m->data );  	g_snprintf( txt, 1024, "Got an invitation to chatroom %s from %s: %s", room, who, msg ); -	do_ask_dialog( gc, txt, inv, byahoo_accept_conf, byahoo_reject_conf ); +	imcb_ask( ic, txt, inv, byahoo_accept_conf, byahoo_reject_conf );  } -void ext_yahoo_conf_userdecline( int id, char *who, char *room, char *msg ) +void ext_yahoo_conf_userdecline( int id, const char *ignored, const char *who, const char *room, const char *msg )  { -	struct gaim_connection *gc = byahoo_get_gc_by_id( id ); +	struct im_connection *ic = byahoo_get_ic_by_id( id ); -	serv_got_crap( gc, "Invite to chatroom %s rejected by %s: %s", room, who, msg ); +	imcb_log( ic, "Invite to chatroom %s rejected by %s: %s", room, who, msg );  } -void ext_yahoo_conf_userjoin( int id, char *who, char *room ) +void ext_yahoo_conf_userjoin( int id, const char *ignored, const char *who, const char *room )  { -	struct gaim_connection *gc = byahoo_get_gc_by_id( id ); -	struct conversation *c; +	struct im_connection *ic = byahoo_get_ic_by_id( id ); +	struct groupchat *c; -	for( c = gc->conversations; c && strcmp( c->title, room ) != 0; c = c->next ); +	for( c = ic->groupchats; c && strcmp( c->title, room ) != 0; c = c->next );  	if( c ) -		add_chat_buddy( c, who ); +		imcb_chat_add_buddy( c, (char*) who );  } -void ext_yahoo_conf_userleave( int id, char *who, char *room ) +void ext_yahoo_conf_userleave( int id, const char *ignored, const char *who, const char *room ) +  { -	struct gaim_connection *gc = byahoo_get_gc_by_id( id ); -	struct conversation *c; +	struct im_connection *ic = byahoo_get_ic_by_id( id ); +	struct groupchat *c; -	for( c = gc->conversations; c && strcmp( c->title, room ) != 0; c = c->next ); +	for( c = ic->groupchats; c && strcmp( c->title, room ) != 0; c = c->next );  	if( c ) -		remove_chat_buddy( c, who, "" ); +		imcb_chat_remove_buddy( c, (char*) who, "" );  } -void ext_yahoo_conf_message( int id, char *who, char *room, char *msg, int utf8 ) +void ext_yahoo_conf_message( int id, const char *ignored, const char *who, const char *room, const char *msg, int utf8 )  { -	struct gaim_connection *gc = byahoo_get_gc_by_id( id ); +	struct im_connection *ic = byahoo_get_ic_by_id( id );  	char *m = byahoo_strip( msg ); -	struct conversation *c; +	struct groupchat *c; -	for( c = gc->conversations; c && strcmp( c->title, room ) != 0; c = c->next ); +	for( c = ic->groupchats; c && strcmp( c->title, room ) != 0; c = c->next ); -	serv_got_chat_in( gc, c ? c->id : 0, who, 0, m, 0 ); +	if( c ) +		imcb_chat_msg( c, (char*) who, (char*) m, 0, 0 );  	g_free( m );  } -void ext_yahoo_chat_cat_xml( int id, char *xml ) +void ext_yahoo_chat_cat_xml( int id, const char *xml )  {  } -void ext_yahoo_chat_join( int id, char *room, char *topic, YList *members, int fd ) +void ext_yahoo_chat_join( int id, const char *who, const char *room, const char *topic, YList *members, int fd )  {  } -void ext_yahoo_chat_userjoin( int id, char *room, struct yahoo_chat_member *who ) +void ext_yahoo_chat_userjoin( int id, const char *me, const char *room, struct yahoo_chat_member *who )  { +	free(who->id); +	free(who->alias); +	free(who->location); +        free(who);  } -void ext_yahoo_chat_userleave( int id, char *room, char *who ) +void ext_yahoo_chat_userleave( int id, const char *me, const char *room, const char *who )  {  } -void ext_yahoo_chat_message( int id, char *who, char *room, char *msg, int msgtype, int utf8 ) +void ext_yahoo_chat_message( int id, const char *me, const char *who, const char *room, const char *msg, int msgtype, int utf8 )  {  } -void ext_yahoo_chat_yahoologout( int id ) +void ext_yahoo_chat_yahoologout( int id, const char *me )  {  } -void ext_yahoo_chat_yahooerror( int id ) +void ext_yahoo_chat_yahooerror( int id, const char *me )  {  } -void ext_yahoo_contact_added( int id, char *myid, char *who, char *msg ) +void ext_yahoo_contact_added( int id, const char *myid, const char *who, const char *msg )  { +	/* Groups schmoups. If I want to handle groups properly I can get the +	   buddy data from some internal libyahoo2 structure. */ +	imcb_add_buddy( byahoo_get_ic_by_id( id ), (char*) who, NULL );  } -void ext_yahoo_rejected( int id, char *who, char *msg ) +void ext_yahoo_rejected( int id, const char *who, const char *msg )  {  } -void ext_yahoo_game_notify( int id, char *who, int stat ) +void ext_yahoo_game_notify( int id, const char *me, const char *who, int stat )  {  } -void ext_yahoo_mail_notify( int id, char *from, char *subj, int cnt ) +void ext_yahoo_mail_notify( int id, const char *from, const char *subj, int cnt )  { -	struct gaim_connection *gc = byahoo_get_gc_by_id( id ); +	struct im_connection *ic = byahoo_get_ic_by_id( id ); -	if( from && subj ) -		serv_got_crap( gc, "Received e-mail message from %s with subject `%s'", from, subj ); +	if( !set_getbool( &ic->acc->set, "mail_notifications" ) ) +		; /* The user doesn't care. */ +	else if( from && subj ) +		imcb_log( ic, "Received e-mail message from %s with subject `%s'", from, subj );  	else if( cnt > 0 ) -		serv_got_crap( gc, "Received %d new e-mails", cnt ); +		imcb_log( ic, "Received %d new e-mails", cnt );  } -void ext_yahoo_webcam_invite_reply( int id, char *from, int accept ) +void ext_yahoo_webcam_invite_reply( int id, const char *me, const char *from, int accept )  {  } -void ext_yahoo_webcam_closed( int id, char *who, int reason ) +void ext_yahoo_webcam_closed( int id, const char *who, int reason )  {  } @@ -936,7 +952,7 @@ void ext_yahoo_got_search_result( int id, int found, int start, int total, YList  {  } -void ext_yahoo_webcam_viewer( int id, char *who, int connect ) +void ext_yahoo_webcam_viewer( int id, const char *who, int connect )  {  } @@ -944,7 +960,7 @@ void ext_yahoo_webcam_data_request( int id, int send )  {  } -int ext_yahoo_log( char *fmt, ... ) +int ext_yahoo_log( const char *fmt, ... )  {  	return( 0 );  } @@ -952,3 +968,13 @@ int ext_yahoo_log( char *fmt, ... )  void ext_yahoo_got_webcam_image( int id, const char * who, const unsigned char *image, unsigned int image_size, unsigned int real_size, unsigned int timestamp )  {  } + +void ext_yahoo_got_ping( int id, const char *msg) +{ +} + +void ext_yahoo_got_buddyicon (int id, const char *me, const char *who, const char *url, int checksum) {} +void ext_yahoo_got_buddyicon_checksum (int id, const char *me,const char *who, int checksum) {} + +void ext_yahoo_got_buddyicon_request(int id, const char *me, const char *who){} +void ext_yahoo_buddyicon_uploaded(int id, const char *url){} diff --git a/protocols/yahoo/yahoo2.h b/protocols/yahoo/yahoo2.h index 5ac5e4f9..e54e09fb 100644 --- a/protocols/yahoo/yahoo2.h +++ b/protocols/yahoo/yahoo2.h @@ -119,7 +119,7 @@ void yahoo_chat_keepalive(int id);  /* from is the identity you're sending from.  if NULL, the default is used */  /* utf8 is whether msg is a utf8 string or not. */ -void yahoo_send_im(int id, const char *from, const char *who, const char *msg, int utf8); +void yahoo_send_im(int id, const char *from, const char *who, const char *msg, int utf8, int picture);  /* if type is true, send typing notice, else send stopped typing notice */  void yahoo_send_typing(int id, const char *from, const char *who, int typ); @@ -127,9 +127,10 @@ void yahoo_send_typing(int id, const char *from, const char *who, int typ);  /* away says whether the custom message is an away message or a sig */  void yahoo_set_away(int id, enum yahoo_status state, const char *msg, int away); -void yahoo_add_buddy(int id, const char *who, const char *group); +void yahoo_add_buddy(int id, const char *who, const char *group, const char *msg);  void yahoo_remove_buddy(int id, const char *who, const char *group);  void yahoo_reject_buddy(int id, const char *who, const char *msg); +void yahoo_stealth_buddy(int id, const char *who, int unstealth);  /* if unignore is true, unignore, else ignore */  void yahoo_ignore_buddy(int id, const char *who, int unignore);  void yahoo_change_buddy_group(int id, const char *who, const char *old_group, const char *new_group); @@ -213,6 +214,8 @@ const char  * yahoo_get_cookie(int id, const char *which);  /* You'll have to do urlencoding yourself, but see yahoo_httplib.h first */  const char  * yahoo_get_profile_url( void ); +void yahoo_buddyicon_request(int id, const char *who); +  #include "yahoo_httplib.h"  #ifdef __cplusplus diff --git a/protocols/yahoo/yahoo2_callbacks.h b/protocols/yahoo/yahoo2_callbacks.h index 1ab8a9d7..b7f4e99b 100644 --- a/protocols/yahoo/yahoo2_callbacks.h +++ b/protocols/yahoo/yahoo2_callbacks.h @@ -30,7 +30,6 @@   */ -  #ifndef YAHOO2_CALLBACKS_H  #define YAHOO2_CALLBACKS_H @@ -66,7 +65,6 @@ typedef enum {  typedef void (*yahoo_connect_callback)(int fd, int error, void *callback_data); -  /*   * The following functions need to be implemented in the client   * interface.  They will be called by the library when each @@ -95,9 +93,7 @@ struct yahoo_callbacks {   * 	succ - enum yahoo_login_status   * 	url  - url to reactivate account if locked   */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_login_response)(int id, int succ, char *url); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_login_response)(int id, int succ, const char *url);  /* @@ -110,8 +106,6 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_login_response)(int id, int succ, char *url);  void YAHOO_CALLBACK_TYPE(ext_yahoo_got_buddies)(int id, YList * buds); - -  /*   * Name: ext_yahoo_got_ignore   * 	Called when the ignore list is got from the server @@ -122,9 +116,6 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_got_buddies)(int id, YList * buds);  void YAHOO_CALLBACK_TYPE(ext_yahoo_got_ignore)(int id, YList * igns); - - -  /*   * Name: ext_yahoo_got_identities   * 	Called when the contact list is got from the server @@ -135,9 +126,6 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_got_ignore)(int id, YList * igns);  void YAHOO_CALLBACK_TYPE(ext_yahoo_got_identities)(int id, YList * ids); - - -  /*   * Name: ext_yahoo_got_cookies   * 	Called when the cookie list is got from the server @@ -147,6 +135,14 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_got_identities)(int id, YList * ids);  void YAHOO_CALLBACK_TYPE(ext_yahoo_got_cookies)(int id); +/* + * Name: ext_yahoo_got_ping + * 	Called when the ping packet is received from the server + * Params: + * 	id   - the id that identifies the server connection + *  errormsg - optional error message + */ +void YAHOO_CALLBACK_TYPE(ext_yahoo_got_ping)(int id, const char *errormsg);  /* @@ -158,11 +154,11 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_got_cookies)(int id);   * 	stat - status code (enum yahoo_status)   * 	msg  - the message if stat == YAHOO_STATUS_CUSTOM   * 	away - whether the contact is away or not (YAHOO_STATUS_CUSTOM) - * 	       for YAHOO_STATUS_IDLE, this is the number of seconds he is idle + * 	idle - this is the number of seconds he is idle [if he is idle] + *	mobile - this is set for mobile users/buddies + *	TODO: add support for pager, chat, and game states   */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_status_changed)(int id, char *who, int stat, char *msg, int away); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_status_changed)(int id, const char *who, int stat, const char *msg, int away, int idle, int mobile);  /* @@ -170,6 +166,7 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_status_changed)(int id, char *who, int stat,   * 	Called when remote user sends you a message.   * Params:   * 	id   - the id that identifies the server connection + * 	me   - the identity the message was sent to   * 	who  - the handle of the remote user   * 	msg  - the message - NULL if stat == 2   * 	tm   - timestamp of message if offline @@ -179,9 +176,7 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_status_changed)(int id, char *who, int stat,   * 				5   * 	utf8 - whether the message is encoded as utf8 or not   */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_got_im)(int id, char *who, char *msg, long tm, int stat, int utf8); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_got_im)(int id, const char *me, const char *who, const char *msg, long tm, int stat, int utf8);  /* @@ -189,14 +184,13 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_got_im)(int id, char *who, char *msg, long tm   * 	Called when remote user sends you a conference invitation.   * Params:   * 	id   - the id that identifies the server connection + * 	me   - the identity the invitation was sent to   * 	who  - the user inviting you   * 	room - the room to join   * 	msg  - the message   *	members - the initial members of the conference (null terminated list)   */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_got_conf_invite)(int id, char *who, char *room, char *msg, YList *members); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_got_conf_invite)(int id, const char *me, const char *who, const char *room, const char *msg, YList *members);  /* @@ -204,13 +198,12 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_got_conf_invite)(int id, char *who, char *roo   * 	Called when someone declines to join the conference.   * Params:   * 	id   - the id that identifies the server connection + * 	me   - the identity in the conference   * 	who  - the user who has declined   * 	room - the room   * 	msg  - the declining message   */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_conf_userdecline)(int id, char *who, char *room, char *msg); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_conf_userdecline)(int id, const char *me, const char *who, const char *room, const char *msg);  /* @@ -218,12 +211,11 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_conf_userdecline)(int id, char *who, char *ro   * 	Called when someone joins the conference.   * Params:   * 	id   - the id that identifies the server connection + * 	me   - the identity in the conference   * 	who  - the user who has joined   * 	room - the room joined   */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_conf_userjoin)(int id, char *who, char *room); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_conf_userjoin)(int id, const char *me, const char *who, const char *room);  /* @@ -231,33 +223,21 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_conf_userjoin)(int id, char *who, char *room)   * 	Called when someone leaves the conference.   * Params:   * 	id   - the id that identifies the server connection + * 	me   - the identity in the conference   * 	who  - the user who has left   * 	room - the room left   */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_conf_userleave)(int id, char *who, char *room); - - - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_conf_userleave)(int id, const char *me, const char *who, const char *room);  /*   * Name: ext_yahoo_chat_cat_xml - * 	Called when joining the chatroom. + * 	Called when ?   * Params:   * 	id      - the id that identifies the server connection - * 	room    - the room joined, used in all other chat calls, freed by  - * 	          library after call - * 	topic   - the topic of the room, freed by library after call - *	members - the initial members of the chatroom (null terminated YList of  - *	          yahoo_chat_member's) Must be freed by the client + * 	xml     - ?   */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_cat_xml)(int id, char *xml); - - - - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_cat_xml)(int id, const char *xml);  /* @@ -265,6 +245,7 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_cat_xml)(int id, char *xml);   * 	Called when joining the chatroom.   * Params:   * 	id      - the id that identifies the server connection + * 	me   - the identity in the chatroom   * 	room    - the room joined, used in all other chat calls, freed by    * 	          library after call   * 	topic   - the topic of the room, freed by library after call @@ -272,11 +253,7 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_cat_xml)(int id, char *xml);   *	          of yahoo_chat_member's) Must be freed by the client   *	fd	- the socket where the connection is coming from (for tracking)   */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_join)(int id, char *room, char *topic, YList *members, int fd); - - - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_join)(int id, const char *me, const char *room, const char *topic, YList *members, int fd);  /* @@ -284,12 +261,11 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_join)(int id, char *room, char *topic, Y   * 	Called when someone joins the chatroom.   * Params:   * 	id   - the id that identifies the server connection + * 	me   - the identity in the chatroom   * 	room - the room joined   * 	who  - the user who has joined, Must be freed by the client   */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_userjoin)(int id, char *room, struct yahoo_chat_member *who); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_userjoin)(int id, const char *me, const char *room, struct yahoo_chat_member *who);  /* @@ -297,12 +273,11 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_userjoin)(int id, char *room, struct yah   * 	Called when someone leaves the chatroom.   * Params:   * 	id   - the id that identifies the server connection + * 	me   - the identity in the chatroom   * 	room - the room left   * 	who  - the user who has left (Just the User ID)   */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_userleave)(int id, char *room, char *who); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_userleave)(int id, const char *me, const char *room, const char *who);  /* @@ -310,6 +285,7 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_userleave)(int id, char *room, char *who   * 	Called when someone messages in the chatroom.   * Params:   * 	id   - the id that identifies the server connection + * 	me   - the identity in the chatroom   * 	room - the room   * 	who  - the user who messaged (Just the user id)   * 	msg  - the message @@ -317,7 +293,8 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_userleave)(int id, char *room, char *who   * 		   2 = /me type message   * 	utf8 - whether the message is utf8 encoded or not   */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_message)(int id, char *who, char *room, char *msg, int msgtype, int utf8); +void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_message)(int id, const char *me, const char *who, const char *room, const char *msg, int msgtype, int utf8); +  /*   * @@ -328,10 +305,12 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_message)(int id, char *who, char *room,   *	of the disconnect request before doing anything here (auto-join's etc)   * Params:   *	id   - the id that identifies this connection + * 	me   - the identity in the chatroom   * Returns:   *	nothing.   */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_yahoologout)(int id); +void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_yahoologout)(int id, const char *me); +  /*   * @@ -343,25 +322,25 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_yahoologout)(int id);   *	of the error before doing anything about it.   * Params:   *	id   - the id that identifies this connection + * 	me   - the identity in the chatroom   * Returns:   *	nothing.   */ +void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_yahooerror)(int id, const char *me); -void YAHOO_CALLBACK_TYPE(ext_yahoo_chat_yahooerror)(int id);  /*   * Name: ext_yahoo_conf_message   * 	Called when someone messages in the conference.   * Params:   * 	id   - the id that identifies the server connection + * 	me   - the identity the conf message was sent to   * 	who  - the user who messaged   * 	room - the room   * 	msg  - the message   * 	utf8 - whether the message is utf8 encoded or not   */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_conf_message)(int id, char *who, char *room, char *msg, int utf8); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_conf_message)(int id, const char *me, const char *who, const char *room, const char *msg, int utf8);  /* @@ -369,6 +348,7 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_conf_message)(int id, char *who, char *room,   * 	Called when someone sends you a file   * Params:   * 	id   - the id that identifies the server connection + * 	me   - the identity the file was sent to   * 	who  - the user who sent the file   * 	url  - the file url   * 	expires  - the expiry date of the file on the server (timestamp) @@ -376,9 +356,7 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_conf_message)(int id, char *who, char *room,   * 	fname- the file name if direct transfer   * 	fsize- the file size if direct transfer   */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_got_file)(int id, char *who, char *url, long expires, char *msg, char *fname, unsigned long fesize); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_got_file)(int id, const char *me, const char *who, const char *url, long expires, const char *msg, const char *fname, unsigned long fesize);  /* @@ -390,9 +368,7 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_got_file)(int id, char *who, char *url, long   * 	who  - who was added   * 	msg  - any message sent   */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_contact_added)(int id, char *myid, char *who, char *msg); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_contact_added)(int id, const char *myid, const char *who, const char *msg);  /* @@ -403,9 +379,7 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_contact_added)(int id, char *myid, char *who,   * 	who  - who rejected you   * 	msg  - any message sent   */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_rejected)(int id, char *who, char *msg); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_rejected)(int id, const char *who, const char *msg);  /* @@ -413,12 +387,11 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_rejected)(int id, char *who, char *msg);   * 	Called when remote user starts or stops typing.   * Params:   * 	id   - the id that identifies the server connection + * 	me   - the handle of the identity the notification is sent to   * 	who  - the handle of the remote user   * 	stat - 1 if typing, 0 if stopped typing   */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_typing_notify)(int id, char *who, int stat); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_typing_notify)(int id, const char *me, const char *who, int stat);  /* @@ -426,12 +399,11 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_typing_notify)(int id, char *who, int stat);   * 	Called when remote user starts or stops a game.   * Params:   * 	id   - the id that identifies the server connection + * 	me   - the handle of the identity the notification is sent to   * 	who  - the handle of the remote user   * 	stat - 1 if game, 0 if stopped gaming   */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_game_notify)(int id, char *who, int stat); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_game_notify)(int id, const char *me, const char *who, int stat);  /* @@ -443,9 +415,7 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_game_notify)(int id, char *who, int stat);   * 	subj - the subject of the mail - NULL if only mail count   * 	cnt  - mail count - 0 if new mail notification   */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_mail_notify)(int id, char *from, char *subj, int cnt); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_mail_notify)(int id, const char *from, const char *subj, int cnt);  /* @@ -455,17 +425,49 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_mail_notify)(int id, char *from, char *subj,   * 	id   - the id that identifies the server connection   * 	msg  - the message   */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_system_message)(int id, char *msg); - - - - - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_system_message)(int id, const char *msg); +/* + * Name: ext_yahoo_got_buddyicon + * 	Buddy icon received + * Params: + * 	id - the id that identifies the server connection + * 	me - the handle of the identity the notification is sent to + * 	who - the person the buddy icon is for + * 	url - the url to use to load the icon + * 	checksum - the checksum of the icon content + */ +void YAHOO_CALLBACK_TYPE(ext_yahoo_got_buddyicon)(int id, const char *me, const char *who, const char *url, int checksum); +/* + * Name: ext_yahoo_got_buddyicon_checksum + * 	Buddy icon checksum received + * Params: + * 	id - the id that identifies the server connection + * 	me - the handle of the identity the notification is sent to + * 	who - the yahoo id of the buddy icon checksum is for + * 	checksum - the checksum of the icon content + */ +void YAHOO_CALLBACK_TYPE(ext_yahoo_got_buddyicon_checksum)(int id, const char *me,const char *who, int checksum); +/* + * Name: ext_yahoo_got_buddyicon_request + * 	Buddy icon request received + * Params: + * 	id - the id that identifies the server connection + * 	me - the handle of the identity the notification is sent to + * 	who - the yahoo id of the buddy that requested the buddy icon + */ +void YAHOO_CALLBACK_TYPE(ext_yahoo_got_buddyicon_request)(int id, const char *me, const char *who); +/* + * Name: ext_yahoo_got_buddyicon_request + * 	Buddy icon request received + * Params: + * 	id - the id that identifies the server connection + * 	url - remote url, the uploaded buddy icon can be fetched from + */ +void YAHOO_CALLBACK_TYPE(ext_yahoo_buddyicon_uploaded)(int id, const char *url);  /*   * Name: ext_yahoo_got_webcam_image @@ -495,18 +497,15 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_got_webcam_image)(int id, const char * who,  		unsigned int timestamp); - -  /*   * Name: ext_yahoo_webcam_invite   * 	Called when you get a webcam invitation   * Params:   * 	id   - the id that identifies the server connection + * 	me   - identity the invitation is to   * 	from - who the invitation is from   */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_webcam_invite)(int id, char *from); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_webcam_invite)(int id, const char *me, const char *from);  /* @@ -514,11 +513,11 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_webcam_invite)(int id, char *from);   * 	Called when you get a response to a webcam invitation   * Params:   * 	id   - the id that identifies the server connection + * 	me   - identity the invitation response is to   * 	from - who the invitation response is from   *	accept - 0 (decline), 1 (accept)   */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_webcam_invite_reply)(int id, char *from, int accept); - +void YAHOO_CALLBACK_TYPE(ext_yahoo_webcam_invite_reply)(int id, const char *me, const char *from, int accept);  /* @@ -533,7 +532,7 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_webcam_invite_reply)(int id, char *from, int   *	         3 = user declines permission   *	         4 = user does not have webcam online   */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_webcam_closed)(int id, char *who, int reason); +void YAHOO_CALLBACK_TYPE(ext_yahoo_webcam_closed)(int id, const char *who, int reason);  /* @@ -551,7 +550,6 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_webcam_closed)(int id, char *who, int reason)  void YAHOO_CALLBACK_TYPE(ext_yahoo_got_search_result)(int id, int found, int start, int total, YList *contacts); -  /*   * Name: ext_yahoo_error   * 	Called on error. @@ -559,10 +557,9 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_got_search_result)(int id, int found, int sta   * 	id   - the id that identifies the server connection   * 	err  - the error message   * 	fatal- whether this error is fatal to the connection or not + * 	num  - Which error is this   */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_error)(int id, char *err, int fatal); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_error)(int id, const char *err, int fatal, int num);  /* @@ -573,9 +570,7 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_error)(int id, char *err, int fatal);   *	who - the viewer   *	connect - 0=disconnect 1=connect 2=request   */ -void YAHOO_CALLBACK_TYPE(ext_yahoo_webcam_viewer)(int id, char *who, int connect); - - +void YAHOO_CALLBACK_TYPE(ext_yahoo_webcam_viewer)(int id, const char *who, int connect);  /* @@ -588,8 +583,6 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_webcam_viewer)(int id, char *who, int connect  void YAHOO_CALLBACK_TYPE(ext_yahoo_webcam_data_request)(int id, int send); - -  /*   * Name: ext_yahoo_log   * 	Called to log a message. @@ -598,13 +591,7 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_webcam_data_request)(int id, int send);   * Returns:   * 	0   */ -int YAHOO_CALLBACK_TYPE(ext_yahoo_log)(char *fmt, ...); - - - - - - +int YAHOO_CALLBACK_TYPE(ext_yahoo_log)(const char *fmt, ...);  /* @@ -623,8 +610,6 @@ int YAHOO_CALLBACK_TYPE(ext_yahoo_log)(char *fmt, ...);  int YAHOO_CALLBACK_TYPE(ext_yahoo_add_handler)(int id, int fd, yahoo_input_condition cond, void *data); - -  /*   * Name: ext_yahoo_remove_handler   * 	Remove the listener for the fd. @@ -635,9 +620,6 @@ int YAHOO_CALLBACK_TYPE(ext_yahoo_add_handler)(int id, int fd, yahoo_input_condi  void YAHOO_CALLBACK_TYPE(ext_yahoo_remove_handler)(int id, int tag); - - -  /*   * Name: ext_yahoo_connect   * 	Connect to a host:port @@ -647,13 +629,7 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_remove_handler)(int id, int tag);   * Returns:   * 	a unix file descriptor to the socket   */ -int YAHOO_CALLBACK_TYPE(ext_yahoo_connect)(char *host, int port); - - - - - - +int YAHOO_CALLBACK_TYPE(ext_yahoo_connect)(const char *host, int port);  /* @@ -674,7 +650,7 @@ int YAHOO_CALLBACK_TYPE(ext_yahoo_connect)(char *host, int port);   * Returns:   * 	a unix file descriptor to the socket   */ -int YAHOO_CALLBACK_TYPE(ext_yahoo_connect_async)(int id, char *host, int port,  +int YAHOO_CALLBACK_TYPE(ext_yahoo_connect_async)(int id, const char *host, int port,   		yahoo_connect_callback callback, void *callback_data);  #ifdef USE_STRUCT_CALLBACKS @@ -685,7 +661,7 @@ int YAHOO_CALLBACK_TYPE(ext_yahoo_connect_async)(int id, char *host, int port,   * before doing anything else   */  void yahoo_register_callbacks(struct yahoo_callbacks * tyc); -	 +  #undef YAHOO_CALLBACK_TYPE  #endif @@ -695,3 +671,4 @@ void yahoo_register_callbacks(struct yahoo_callbacks * tyc);  #endif  #endif + diff --git a/protocols/yahoo/yahoo2_types.h b/protocols/yahoo/yahoo2_types.h index 1a92b267..df1756eb 100644 --- a/protocols/yahoo/yahoo2_types.h +++ b/protocols/yahoo/yahoo2_types.h @@ -29,6 +29,7 @@ extern "C" {  #endif  enum yahoo_status { +	YAHOO_STATUS_DISCONNECTED = -1,  	YAHOO_STATUS_AVAILABLE = 0,  	YAHOO_STATUS_BRB,  	YAHOO_STATUS_BUSY, @@ -42,13 +43,15 @@ enum yahoo_status {  	YAHOO_STATUS_INVISIBLE = 12,  	YAHOO_STATUS_CUSTOM = 99,  	YAHOO_STATUS_IDLE = 999, +	YAHOO_STATUS_WEBLOGIN = 0x5a55aa55,  	YAHOO_STATUS_OFFLINE = 0x5a55aa56, /* don't ask */ -	YAHOO_STATUS_NOTIFY = 0x16 +	YAHOO_STATUS_NOTIFY = 0x16 /* TYPING */  };  #define YAHOO_STATUS_GAME	0x2 		/* Games don't fit into the regular status model */  enum yahoo_login_status {  	YAHOO_LOGIN_OK = 0, +	YAHOO_LOGIN_LOGOFF = 2,  	YAHOO_LOGIN_UNAME = 3,  	YAHOO_LOGIN_PASSWD = 13,  	YAHOO_LOGIN_LOCK = 14, @@ -57,6 +60,9 @@ enum yahoo_login_status {  };  enum yahoo_error { +	E_UNKNOWN = -1, +	E_CONNECTION = -2, +	E_SYSTEM = -3,  	E_CUSTOM = 0,  	/* responses from ignore buddy */ @@ -78,6 +84,7 @@ enum yahoo_log_level {  	YAHOO_LOG_DEBUG  }; +#define YAHOO_PROTO_VER 0x000b  /* Yahoo style/color directives */  #define YAHOO_COLOR_BLACK "\033[30m" @@ -115,6 +122,12 @@ enum yahoo_webcam_direction_type {          YAHOO_WEBCAM_UPLOAD  }; +enum yahoo_stealth_visibility_type { +	YAHOO_STEALTH_DEFAULT = 0, +  	YAHOO_STEALTH_ONLINE, +  	YAHOO_STEALTH_PERM_OFFLINE +}; +  /* chat member attribs */  #define YAHOO_CHAT_MALE 0x8000  #define YAHOO_CHAT_FEMALE 0x10000 diff --git a/protocols/yahoo/yahoo_util.c b/protocols/yahoo/yahoo_util.c index 7babfa49..5375205f 100644 --- a/protocols/yahoo/yahoo_util.c +++ b/protocols/yahoo/yahoo_util.c @@ -68,13 +68,15 @@ char ** y_strsplit(char * str, char * sep, int nelem)  	char *s, *p;  	int i=0;  	int l = strlen(sep); -	if(nelem < 0) { +	if(nelem <= 0) {  		char * s;  		nelem=0; -		for(s=strstr(str, sep); s; s=strstr(s+l, sep),nelem++) -			; -		if(strcmp(str+strlen(str)-l, sep)) -			nelem++; +		if (*str) { +			for(s=strstr(str, sep); s; s=strstr(s+l, sep),nelem++) +				; +			if(strcmp(str+strlen(str)-l, sep)) +				nelem++; +		}  	}  	vector = y_new(char *, nelem + 1); @@ -86,7 +88,7 @@ char ** y_strsplit(char * str, char * sep, int nelem)  		vector[i][len] = '\0';  	} -	if(i<nelem) /* str didn't end with sep */ +	if(i<nelem && *str) /* str didn't end with sep, and str isn't empty */  		vector[i++] = strdup(p);  	vector[i] = NULL;  | 
