aboutsummaryrefslogtreecommitdiffstats
path: root/protocols
diff options
context:
space:
mode:
Diffstat (limited to 'protocols')
-rw-r--r--protocols/Makefile6
-rw-r--r--protocols/http_client.c421
-rw-r--r--protocols/http_client.h56
-rw-r--r--protocols/jabber/Makefile6
-rw-r--r--protocols/jabber/asciitab.h62
-rw-r--r--protocols/jabber/conference.c375
-rw-r--r--protocols/jabber/expat.c54
-rw-r--r--protocols/jabber/hashtable.c142
-rw-r--r--protocols/jabber/hashtable.h69
-rw-r--r--protocols/jabber/iasciitab.h63
-rw-r--r--protocols/jabber/io.c566
-rw-r--r--protocols/jabber/iq.c594
-rw-r--r--protocols/jabber/jabber.c2650
-rw-r--r--protocols/jabber/jabber.h549
-rw-r--r--protocols/jabber/jabber_util.c710
-rw-r--r--protocols/jabber/jid.c170
-rw-r--r--protocols/jabber/jpacket.c159
-rw-r--r--protocols/jabber/jutil.c122
-rw-r--r--protocols/jabber/latin1tab.h62
-rw-r--r--protocols/jabber/lib.h343
-rw-r--r--protocols/jabber/libxode.h398
-rw-r--r--protocols/jabber/log.c44
-rw-r--r--protocols/jabber/log.h36
-rw-r--r--protocols/jabber/message.c118
-rw-r--r--protocols/jabber/nametab.h150
-rw-r--r--protocols/jabber/pool.c247
-rw-r--r--protocols/jabber/presence.c261
-rw-r--r--protocols/jabber/sasl.c348
-rw-r--r--protocols/jabber/str.c215
-rw-r--r--protocols/jabber/utf8tab.h63
-rw-r--r--protocols/jabber/xmldef.h34
-rw-r--r--protocols/jabber/xmlnode.c705
-rw-r--r--protocols/jabber/xmlparse.c2640
-rw-r--r--protocols/jabber/xmlparse.h476
-rw-r--r--protocols/jabber/xmlrole.c1104
-rw-r--r--protocols/jabber/xmlrole.h111
-rw-r--r--protocols/jabber/xmltok.c1518
-rw-r--r--protocols/jabber/xmltok.h307
-rw-r--r--protocols/jabber/xmltok_impl.c1737
-rw-r--r--protocols/jabber/xmltok_impl.h71
-rw-r--r--protocols/jabber/xmltok_ns.c117
-rw-r--r--protocols/md5.c392
-rw-r--r--protocols/md5.h85
-rw-r--r--protocols/msn/Makefile4
-rw-r--r--protocols/msn/msn.c303
-rw-r--r--protocols/msn/msn.h42
-rw-r--r--protocols/msn/msn_util.c139
-rw-r--r--protocols/msn/ns.c298
-rw-r--r--protocols/msn/passport.c265
-rw-r--r--protocols/msn/passport.h92
-rw-r--r--protocols/msn/sb.c219
-rw-r--r--protocols/nogaim.c831
-rw-r--r--protocols/nogaim.h357
-rw-r--r--protocols/oscar/Makefile4
-rw-r--r--protocols/oscar/aim.h4
-rw-r--r--protocols/oscar/chat.c6
-rw-r--r--protocols/oscar/chatnav.c10
-rw-r--r--protocols/oscar/icq.c2
-rw-r--r--protocols/oscar/im.c12
-rw-r--r--protocols/oscar/info.c9
-rw-r--r--protocols/oscar/msgcookie.c15
-rw-r--r--protocols/oscar/oscar.c1018
-rw-r--r--protocols/oscar/rxhandlers.c4
-rw-r--r--protocols/oscar/rxqueue.c2
-rw-r--r--protocols/oscar/search.c2
-rw-r--r--protocols/oscar/service.c8
-rw-r--r--protocols/oscar/txqueue.c8
-rw-r--r--protocols/proxy.c600
-rw-r--r--protocols/proxy.h60
-rw-r--r--protocols/sha.c173
-rw-r--r--protocols/sha.h21
-rw-r--r--protocols/ssl_bogus.c57
-rw-r--r--protocols/ssl_client.h42
-rw-r--r--protocols/ssl_gnutls.c210
-rw-r--r--protocols/ssl_nss.c188
-rw-r--r--protocols/ssl_openssl.c226
-rw-r--r--protocols/yahoo/Makefile4
-rw-r--r--protocols/yahoo/libyahoo2.c668
-rw-r--r--protocols/yahoo/yahoo.c544
-rw-r--r--protocols/yahoo/yahoo2.h7
-rw-r--r--protocols/yahoo/yahoo2_callbacks.h229
-rw-r--r--protocols/yahoo/yahoo2_types.h15
-rw-r--r--protocols/yahoo/yahoo_util.c14
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],"&amp;",5);
- j += 5;
- break;
- case '\'':
- memcpy(&temp[j],"&apos;",6);
- j += 6;
- break;
- case '\"':
- memcpy(&temp[j],"&quot;",6);
- j += 6;
- break;
- case '<':
- memcpy(&temp[j],"&lt;",4);
- j += 4;
- break;
- case '>':
- memcpy(&temp[j],"&gt;",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;