From 8f243add8b64f9936c49bbeafac77aa9961cf264 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 20 Sep 2006 11:36:53 +0200 Subject: Removed old Jabber module, started to fill in the new stuff. (xmltree developed outside this tree) --- protocols/jabber/jabber.c | 2392 --------------------------------------------- 1 file changed, 2392 deletions(-) delete mode 100644 protocols/jabber/jabber.c (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c deleted file mode 100644 index e765a475..00000000 --- a/protocols/jabber/jabber.c +++ /dev/null @@ -1,2392 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * gaim - * - * Some code copyright (C) 1998-1999, Mark Spencer - * libfaim code copyright 1998, 1999 Adam Fritzler - * - * 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 -#endif -#include -#include -#include -#include -#include -#include -#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, ""); - gjc->state = JCONN_STATE_OFF; - gjc->was_connected = 0; - if (gjc->ssl) { - ssl_disconnect(gjc->ssl); - gjc->ssl = NULL; - } else { - closesocket(gjc->fd); - } - gjc->fd = -1; - XML_ParserFree(gjc->parser); - gjc->parser = NULL; -} - -/* -static int gjab_getfd(gjconn gjc) -{ - if (gjc) - return gjc->fd; - else - return -1; -} - -static jid gjab_getjid(gjconn gjc) -{ - if (gjc) - return (gjc->user); - else - return NULL; -} - -static char *gjab_getsid(gjconn gjc) -{ - if (gjc) - return (gjc->sid); - else - return NULL; -} -*/ - -static char *gjab_getid(gjconn gjc) -{ - g_snprintf(gjc->idbuf, 8, "%d", gjc->id++); - return &gjc->idbuf[0]; -} - -static void gjab_send(gjconn gjc, xmlnode x) -{ - if (gjc && gjc->state != JCONN_STATE_OFF) { - char *buf = xmlnode2str(x); - if (!buf) - return; - else if (gjc->ssl) - ssl_write(gjc->ssl, buf, strlen(buf)); - else - write(gjc->fd, buf, strlen(buf)); - } -} - -static void gjab_send_raw(gjconn gjc, const char *str) -{ - if (gjc && gjc->state != JCONN_STATE_OFF) { - int len; - - /* - * JFIXME: No error detection?!?! - */ - if (gjc->ssl) - len = ssl_write(gjc->ssl, str, strlen(str)); - else - len = write(gjc->fd, str, strlen(str)); - - if(len < 0) { - /* Do NOT write to stdout/stderr directly, IRC clients - might get confused, and we don't want that... - fprintf(stderr, "DBG: Problem sending. Error: %d\n", errno); - fflush(stderr); */ - } - } -} - -static void gjab_reqroster(gjconn gjc) -{ - xmlnode x; - - x = jutil_iqnew(JPACKET__GET, NS_ROSTER); - xmlnode_put_attrib(x, "id", gjab_getid(gjc)); - - gjab_send(gjc, x); - xmlnode_free(x); -} - -static void gjab_reqauth(gjconn gjc) -{ - xmlnode x, y, z; - char *user; - - if (!gjc) - return; - - x = jutil_iqnew(JPACKET__GET, NS_AUTH); - xmlnode_put_attrib(x, "id", IQID_AUTH); - y = xmlnode_get_tag(x, "query"); - - user = gjc->user->user; - - if (user) { - z = xmlnode_insert_tag(y, "username"); - xmlnode_insert_cdata(z, user, -1); - } - - gjab_send(gjc, x); - xmlnode_free(x); -} - -static void gjab_auth(gjconn gjc) -{ - xmlnode x, y, z; - char *hash, *user; - - if (!gjc) - return; - - x = jutil_iqnew(JPACKET__SET, NS_AUTH); - xmlnode_put_attrib(x, "id", IQID_AUTH); - y = xmlnode_get_tag(x, "query"); - - user = gjc->user->user; - - if (user) { - z = xmlnode_insert_tag(y, "username"); - xmlnode_insert_cdata(z, user, -1); - } - - z = xmlnode_insert_tag(y, "resource"); - xmlnode_insert_cdata(z, gjc->user->resource, -1); - - if (gjc->sid) { - z = xmlnode_insert_tag(y, "digest"); - hash = pmalloc(x->p, strlen(gjc->sid) + strlen(gjc->pass) + 1); - strcpy(hash, gjc->sid); - strcat(hash, gjc->pass); - hash = shahash(hash); - xmlnode_insert_cdata(z, hash, 40); - } else { - z = xmlnode_insert_tag(y, "password"); - xmlnode_insert_cdata(z, gjc->pass, -1); - } - - gjab_send(gjc, x); - xmlnode_free(x); - - return; -} - -static void gjab_recv(gjconn gjc) -{ - static char buf[4096]; - int len; - - if (!gjc || gjc->state == JCONN_STATE_OFF) - return; - - if (gjc->ssl) - len = ssl_read(gjc->ssl, buf, sizeof(buf) - 1); - else - len = read(gjc->fd, buf, sizeof(buf) - 1); - - 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 */ - STATE_EVT(JCONN_STATE_OFF) - return; - } - - x = xmlnode_get_parent(gjc->current); - - if (!x) { - /* it is time to fire the event */ - p = jpacket_new(gjc->current); - - if (gjc->on_packet) - (gjc->on_packet) (gjc, p); - else - xmlnode_free(gjc->current); - } - - gjc->current = x; -} - -static gboolean jabber_callback(gpointer data, gint source, b_input_condition condition) -{ - struct gaim_connection *gc = (struct gaim_connection *)data; - struct jabber_data *jd = (struct jabber_data *)gc->proto_data; - - gjab_recv(jd->gjc); - - return TRUE; -} - -static void charData(void *userdata, const char *s, int slen) -{ - gjconn gjc = (gjconn) userdata; - - if (gjc->current) - xmlnode_insert_cdata(gjc->current, s, slen); -} - -static gboolean gjab_connected(gpointer data, gint source, b_input_condition cond) -{ - xmlnode x; - char *t, *t2; - struct gaim_connection *gc = data; - struct jabber_data *jd; - gjconn gjc; - - if (!g_slist_find(get_connections(), gc)) { - closesocket(source); - return FALSE; - } - - jd = gc->proto_data; - gjc = jd->gjc; - - if (gjc->fd != source) - gjc->fd = source; - - if (source == -1) { - STATE_EVT(JCONN_STATE_OFF) - return FALSE; - } - - gjc->state = JCONN_STATE_CONNECTED; - STATE_EVT(JCONN_STATE_CONNECTED) - - /* start stream */ - x = jutil_header(NS_CLIENT, gjc->user->server); - t = xmlnode2str(x); - /* this is ugly, we can create the string here instead of jutil_header */ - /* what do you think about it? -madcat */ - t2 = strstr(t, "/>"); - *t2++ = '>'; - *t2 = '\0'; - gjab_send_raw(gjc, ""); - gjab_send_raw(gjc, t); - xmlnode_free(x); - - gjc->state = JCONN_STATE_ON; - STATE_EVT(JCONN_STATE_ON); - - gc = GJ_GC(gjc); - gc->inpa = b_input_add(gjc->fd, GAIM_INPUT_READ, jabber_callback, gc); - - return FALSE; -} - -static gboolean gjab_connected_ssl(gpointer data, void *source, b_input_condition cond) -{ - struct gaim_connection *gc = data; - struct jabber_data *jd; - gjconn gjc; - - jd = gc->proto_data; - gjc = jd->gjc; - - if (source == NULL) { - STATE_EVT(JCONN_STATE_OFF) - return FALSE; - } - - if (!g_slist_find(get_connections(), gc)) { - ssl_disconnect(source); - return FALSE; - } - - return gjab_connected(data, gjc->fd, cond); -} - -static void gjab_start(gjconn gjc) -{ - account_t *acc; - int port = -1, ssl = 0; - char *server = NULL; - - if (!gjc || gjc->state != JCONN_STATE_OFF) - return; - - acc = GJ_GC(gjc)->acc; - server = acc->server; - port = set_getint(&acc->set, "port"); - ssl = set_getbool(&acc->set, "ssl"); - - 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; - } - - 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); - - if (ssl) { - if ((gjc->ssl = ssl_connect(server, port, gjab_connected_ssl, GJ_GC(gjc)))) - gjc->fd = ssl_getfd(gjc->ssl); - else - gjc->fd = -1; - } else { - gjc->fd = proxy_connect(server, port, gjab_connected, GJ_GC(gjc)); - } - - if (!acc->gc || (gjc->fd < 0)) { - STATE_EVT(JCONN_STATE_OFF) - 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)) - { - 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 - } - - 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) - { - if(NSCHECK(z,NS_DELAY)) - { - char *timestamp = xmlnode_get_attrib(z,"stamp"); - time_sent = iso8601_to_time(timestamp); - } - z = xmlnode_get_nextsibling(z); - } - - if (!type || !g_strcasecmp(type, "normal") || !g_strcasecmp(type, "chat")) { - - /* XXX namespaces could be handled better. (mid) */ - if ((xmlns = xmlnode_get_tag(p->x, "x"))) - type = xmlnode_get_attrib(xmlns, "xmlns"); - - from = jid_full(p->from); - /* - if ((y = xmlnode_get_tag(p->x, "html"))) { - msg = xmlnode_get_data(y); - } else - */ - if ((y = xmlnode_get_tag(p->x, "body"))) { - msg = xmlnode_get_data(y); - } - - - if (!from) - return; - - if (type && !g_strcasecmp(type, "jabber:x:conference")) { - /* do nothing */ - } else if (msg) { /* whisper */ - struct jabber_chat *jc; - g_snprintf(m, sizeof(m), "%s", msg); - if (((jc = find_existing_chat(GJ_GC(gjc), p->from)) != NULL) && jc->b) - serv_got_chat_in(GJ_GC(gjc), jc->b->id, p->from->resource, 1, m, time_sent); - else { - int flags = 0; - - if(p->from->user) { - from = g_strdup_printf("%s@%s", p->from->user, p->from->server); - } else { - /* server message? */ - from = g_strdup(p->from->server); - } - serv_got_im(GJ_GC(gjc), from, m, flags, time_sent, -1); - g_free(from); - } - } - - } else if (!g_strcasecmp(type, "error")) { - if ((y = xmlnode_get_tag(p->x, "error"))) { - type = xmlnode_get_attrib(y, "code"); - msg = xmlnode_get_data(y); - } - - if (msg) { - from = g_strdup_printf("Error %s", type ? type : ""); - do_error_dialog(GJ_GC(gjc), msg, from); - g_free(from); - } - } else if (!g_strcasecmp(type, "headline")) { - char *subject, *body, *url; - - y = xmlnode_get_tag( p->x, "body" ); - body = y ? g_strdup( xmlnode_get_data( y ) ) : NULL; - - y = xmlnode_get_tag( p->x, "subject" ); - subject = y ? g_strdup( xmlnode_get_data( y ) ) : NULL; - - url = NULL; - z = xmlnode_get_firstchild(p->x); - while( z ) - { - char *xtype = xmlnode_get_attrib( z, "xmlns" ); - - if( xtype && g_strcasecmp( xtype, "jabber:x:oob" ) == 0 && - ( y = xmlnode_get_tag( z, "url" ) ) ) - { - url = g_strdup( xmlnode_get_data( y ) ); - break; - } - - z = xmlnode_get_nextsibling( z ); - } - - g_snprintf( m, BUF_LONG, "Subject: %s\nURL: %s\nMessage:\n%s", subject ? subject : "(none)", - url ? url : "(none)", body ? body : "(none)" ); - - if( p->from->user ) - from = g_strdup_printf( "%s@%s", p->from->user, p->from->server ); - else - from = g_strdup( p->from->server ); - - serv_got_im( GJ_GC(gjc), from, m, 0, time_sent, -1 ); - - g_free( from ); - g_free( subject ); - g_free( body ); - g_free( url ); - } -} - -static void jabber_handlepresence(gjconn gjc, jpacket p) -{ - char *to, *from, *type; - struct buddy *b = NULL; - jid who; - char *buddy; - xmlnode y; - char *show; - int state = 0; - GSList *resources; - char *res; - struct conversation *cnv = NULL; - struct jabber_chat *jc = NULL; - - to = xmlnode_get_attrib(p->x, "to"); - from = xmlnode_get_attrib(p->x, "from"); - type = xmlnode_get_attrib(p->x, "type"); - - if (type && g_strcasecmp(type, "error") == 0) { - return; - } - else if ((y = xmlnode_get_tag(p->x, "show"))) { - show = xmlnode_get_data(y); - if (!show) { - state = 0; - } else if (!g_strcasecmp(show, "away")) { - state = UC_AWAY; - } else if (!g_strcasecmp(show, "chat")) { - state = UC_CHAT; - } else if (!g_strcasecmp(show, "xa")) { - state = UC_XA; - } else if (!g_strcasecmp(show, "dnd")) { - state = UC_DND; - } - } else { - state = 0; - } - - who = jid_new(gjc->p, from); - if (who->user == NULL) { - /* FIXME: transport */ - return; - } - - buddy = g_strdup_printf("%s@%s", who->user, who->server); - - /* um. we're going to check if it's a chat. if it isn't, and there are pending - * chats, create the chat. if there aren't pending chats and we don't have the - * buddy on our list, simply bail out. */ - if ((cnv = NULL) == NULL) { - static int i = 0x70; - if ((jc = find_pending_chat(GJ_GC(gjc), who)) != NULL) { - jc->b = cnv = serv_got_joined_chat(GJ_GC(gjc), i++, who->user); - jc->id = jc->b->id; - jc->state = JCS_ACTIVE; - } else if ((b = find_buddy(GJ_GC(gjc), buddy)) == NULL) { - g_free(buddy); - return; - } - } - - if (!cnv) { - resources = b->proto_data; - res = who->resource; - if (res) - while (resources) { - if (!strcmp(res, resources->data)) - break; - resources = resources->next; - } - - /* keep track of away msg same as yahoo plugin */ - jabber_track_away(gjc, p, normalize(b->name), type); - - if (type && (g_strcasecmp(type, "unavailable") == 0)) { - if (resources) { - g_free(resources->data); - b->proto_data = g_slist_remove(b->proto_data, resources->data); - } - if (!b->proto_data) { - serv_got_update(GJ_GC(gjc), buddy, 0, 0, 0, 0, 0, 0); - } - } else { - if (!resources) { - b->proto_data = g_slist_append(b->proto_data, g_strdup(res)); - } - - serv_got_update(GJ_GC(gjc), buddy, 1, 0, b->signon, b->idle, state, 0); - - } - } else { - if (who->resource) { - char *buf; - - buf = g_strdup_printf("%s@%s/%s", who->user, who->server, who->resource); - jabber_track_away(gjc, p, buf, type); - g_free(buf); - - if (type && !g_strcasecmp(type, "unavailable")) { - struct jabber_data *jd; - if (!jc && !(jc = find_existing_chat(GJ_GC(gjc), who))) { - g_free(buddy); - return; - } - jd = jc->gc->proto_data; - /* if it's not ourselves...*/ - if (strcmp(who->resource, jc->Jid->resource) && jc->b) { - remove_chat_buddy(jc->b, who->resource, NULL); - g_free(buddy); - return; - } - - jc->state = JCS_CLOSED; - serv_got_chat_left(GJ_GC(gjc), jc->id); - /* - * TBD: put back some day? - jd->chats = g_slist_remove(jd->chats, jc); - g_free(jc); - */ - } else { - if ((!jc && !(jc = find_existing_chat(GJ_GC(gjc), who))) || !jc->b) { - g_free(buddy); - return; - } - if (!find_chat_buddy(jc->b, who->resource)) { - add_chat_buddy(jc->b, who->resource); - } - } - } - } - - g_free(buddy); - - return; -} - -/* - * Used only by Jabber accept/deny add stuff just below - */ -struct jabber_add_permit { - gjconn gjc; - gchar *user; -}; - -/* - * Common part for Jabber accept/deny adds - * - * "type" says whether we'll permit/deny the subscribe request - */ -static void jabber_accept_deny_add(struct jabber_add_permit *jap, const char *type) -{ - xmlnode g = xmlnode_new_tag("presence"); - - xmlnode_put_attrib(g, "to", jap->user); - xmlnode_put_attrib(g, "type", type); - gjab_send(jap->gjc, g); - - xmlnode_free(g); -} - -/* - * Callback from "accept" in do_ask_dialog() invoked by jabber_handles10n() - */ -static void jabber_accept_add(gpointer w, struct jabber_add_permit *jap) -{ - jabber_accept_deny_add(jap, "subscribed"); - /* - * If we don't already have the buddy on *our* buddylist, - * ask if we want him or her added. - */ - if(find_buddy(GJ_GC(jap->gjc), jap->user) == NULL) { - show_got_added(GJ_GC(jap->gjc), jap->user, NULL); - } - g_free(jap->user); - g_free(jap); -} - -/* - * Callback from "deny/cancel" in do_ask_dialog() invoked by jabber_handles10n() - */ -static void jabber_deny_add(gpointer w, struct jabber_add_permit *jap) -{ - jabber_accept_deny_add(jap, "unsubscribed"); - g_free(jap->user); - g_free(jap); -} - -/* - * Handle subscription requests - */ -static void jabber_handles10n(gjconn gjc, jpacket p) -{ - xmlnode g; - char *Jid = xmlnode_get_attrib(p->x, "from"); - char *type = xmlnode_get_attrib(p->x, "type"); - - g = xmlnode_new_tag("presence"); - xmlnode_put_attrib(g, "to", Jid); - - if (!strcmp(type, "subscribe")) { - /* - * A "subscribe to us" request was received - put up the approval dialog - */ - struct jabber_add_permit *jap = g_new0(struct jabber_add_permit, 1); - gchar *msg = g_strdup_printf(_("The user %s wants to add you to his/her buddy list."), - Jid); - - jap->gjc = gjc; - jap->user = g_strdup(Jid); - do_ask_dialog(GJ_GC(gjc), msg, jap, jabber_accept_add, jabber_deny_add); - - g_free(msg); - xmlnode_free(g); /* Never needed it here anyway */ - return; - - } else if (!strcmp(type, "unsubscribe")) { - /* - * An "unsubscribe to us" was received - simply "approve" it - */ - xmlnode_put_attrib(g, "type", "unsubscribed"); - } else { - /* - * Did we attempt to subscribe to somebody and they do not exist? - */ - if (!strcmp(type, "unsubscribed")) { - xmlnode y; - char *status; - if((y = xmlnode_get_tag(p->x, "status")) && (status = xmlnode_get_data(y)) && - !strcmp(status, "Not Found")) { - char *msg = g_strdup_printf("%s: \"%s\"", _("No such user"), - xmlnode_get_attrib(p->x, "from")); - do_error_dialog(GJ_GC(gjc), msg, _("Jabber Error")); - g_free(msg); - } - } - - xmlnode_free(g); - return; - } - - gjab_send(gjc, g); - xmlnode_free(g); -} - -/* - * Pending subscription to a buddy? - */ -#define BUD_SUB_TO_PEND(sub, ask) ((!g_strcasecmp((sub), "none") || !g_strcasecmp((sub), "from")) && \ - (ask) != NULL && !g_strcasecmp((ask), "subscribe")) - -/* - * Subscribed to a buddy? - */ -#define BUD_SUBD_TO(sub, ask) ((!g_strcasecmp((sub), "to") || !g_strcasecmp((sub), "both")) && \ - ((ask) == NULL || !g_strcasecmp((ask), "subscribe"))) - -/* - * Pending unsubscription to a buddy? - */ -#define BUD_USUB_TO_PEND(sub, ask) ((!g_strcasecmp((sub), "to") || !g_strcasecmp((sub), "both")) && \ - (ask) != NULL && !g_strcasecmp((ask), "unsubscribe")) - -/* - * Unsubscribed to a buddy? - */ -#define BUD_USUBD_TO(sub, ask) ((!g_strcasecmp((sub), "none") || !g_strcasecmp((sub), "from")) && \ - ((ask) == NULL || !g_strcasecmp((ask), "unsubscribe"))) - -/* - * If a buddy is added or removed from the roster on another resource - * jabber_handlebuddy is called - * - * Called with roster item node. - */ -static void jabber_handlebuddy(gjconn gjc, xmlnode x) -{ - xmlnode g; - char *Jid, *name, *sub, *ask; - jid who; - struct buddy *b = NULL; - char *buddyname, *groupname = NULL; - - Jid = xmlnode_get_attrib(x, "jid"); - name = xmlnode_get_attrib(x, "name"); - sub = xmlnode_get_attrib(x, "subscription"); - ask = xmlnode_get_attrib(x, "ask"); - who = jid_new(gjc->p, Jid); - - /* JFIXME: jabber_handleroster() had a "FIXME: transport" at this - * equivilent point. So... - * - * We haven't allocated any memory or done anything interesting to - * this point, so we'll violate Good Coding Structure here by - * simply bailing out. - */ - if (!who || !who->user) { - return; - } - - buddyname = g_strdup_printf("%s@%s", who->user, who->server); - - if((g = xmlnode_get_tag(x, "group")) != NULL) { - groupname = xmlnode_get_data(g); - } - - /* - * Add or remove a buddy? Change buddy's alias or group? - */ - if (BUD_SUB_TO_PEND(sub, ask) || BUD_SUBD_TO(sub, ask)) { - if ((b = find_buddy(GJ_GC(gjc), buddyname)) == NULL) { - add_buddy(GJ_GC(gjc), groupname ? groupname : _("Buddies"), buddyname, - name ? name : buddyname); - } else { - /* struct group *c_grp = find_group_by_buddy(GJ_GC(gjc), buddyname); */ - - /* - * If the buddy's in a new group or his/her alias is changed... - */ - if(groupname) { - int present = b->present; /* save presence state */ - int uc = b->uc; /* and away state (?) */ - int idle = b->idle; - int signon = b->signon; - - /* - * seems rude, but it seems to be the only way... - */ - /* remove_buddy(GJ_GC(gjc), c_grp, b); */ - jabber_remove_buddy(GJ_GC(gjc), b->name, JABBER_GROUP); - - add_buddy(GJ_GC(gjc), groupname, buddyname, - name ? name : buddyname); - if(present) { - serv_got_update(GJ_GC(gjc), buddyname, 1, 0, signon, idle, uc, 0); - } - } else if(name != NULL && strcmp(b->show, name)) { - strncpy(b->show, name, BUDDY_ALIAS_MAXLEN); - b->show[BUDDY_ALIAS_MAXLEN - 1] = '\0'; /* cheap safety feature */ - serv_buddy_rename(GJ_GC(gjc), buddyname, b->show); - } - } - } else if (BUD_USUB_TO_PEND(sub, ask) || BUD_USUBD_TO(sub, ask) || !g_strcasecmp(sub, "remove")) { - jabber_remove_gaim_buddy(GJ_GC(gjc), buddyname); - } - g_free(buddyname); - -} - -static void jabber_handleroster(gjconn gjc, xmlnode querynode) -{ - xmlnode x; - - x = xmlnode_get_firstchild(querynode); - while (x) { - jabber_handlebuddy(gjc, x); - x = xmlnode_get_nextsibling(x); - } - - account_online(GJ_GC(gjc)); -} - -static void jabber_handleauthresp(gjconn gjc, jpacket p) -{ - if (jpacket_subtype(p) == JPACKET__RESULT) { - if (xmlnode_has_children(p->x)) { - xmlnode query = xmlnode_get_tag(p->x, "query"); - set_login_progress(GJ_GC(gjc), 4, _("Authenticating")); - if (!xmlnode_get_tag(query, "digest")) { - g_free(gjc->sid); - gjc->sid = NULL; - } - 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); - - 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]; - - 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; -} - -static void jabber_acc_init(account_t *acc) -{ - set_t *s; - - s = set_add( &acc->set, "port", "5222", set_eval_int, acc ); - s->flags |= ACC_SET_OFFLINE_ONLY; - - s = set_add( &acc->set, "resource", "BitlBee", NULL, acc ); - s->flags |= ACC_SET_OFFLINE_ONLY; - - 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; -} - -static void jabber_login(account_t *acc) -{ - struct gaim_connection *gc; - struct jabber_data *jd; - char *resource, *loginname; - - /* Time to move some data/things from the old syntax to the new one: */ - if (acc->server) { - char *s, *tmp_server; - int port; - - if (g_strcasecmp(acc->server, "ssl") == 0) { - set_setstr(&acc->set, "server", ""); - set_setint(&acc->set, "port", DEFAULT_PORT_SSL); - set_setstr(&acc->set, "ssl", "true"); - - g_free(acc->server); - acc->server = NULL; - } else if ((s = strchr(acc->server, ':'))) { - if (strstr(acc->server, ":ssl")) { - set_setint(&acc->set, "port", DEFAULT_PORT_SSL); - set_setstr(&acc->set, "ssl", "true"); - } - if (isdigit(s[1])) { - if (sscanf(s + 1, "%d", &port) == 1) - set_setint(&acc->set, "port", port); - } - tmp_server = g_strndup(acc->server, s - acc->server); - set_setstr(&acc->set, "server", tmp_server); - g_free(tmp_server); - } - } - - gc = new_gaim_conn(acc); - jd = gc->proto_data = g_new0(struct jabber_data, 1); - - if( strchr( acc->user, '@' ) == NULL ) - { - hide_login_progress( gc, "Invalid account name" ); - signoff( gc ); - return; - } - - resource = set_getstr(&acc->set, "resource"); - loginname = create_valid_jid(acc->user, DEFAULT_SERVER, resource); - - jd->hash = g_hash_table_new(g_str_hash, g_str_equal); - jd->chats = NULL; /* we have no chats yet */ - - set_login_progress(gc, 1, _("Connecting")); - - if (!(jd->gjc = gjab_new(loginname, acc->pass, gc))) { - g_free(loginname); - hide_login_progress(gc, _("Unable to connect")); - signoff(gc); - return; - } - - g_free(loginname); - gjab_state_handler(jd->gjc, jabber_handlestate); - gjab_packet_handler(jd->gjc, jabber_handlepacket); - jd->gjc->queries = g_hash_table_new(g_str_hash, g_str_equal); - gjab_start(jd->gjc); -} - -static gboolean jabber_destroy_hash(gpointer key, gpointer val, gpointer data) { - g_free(key); - g_free(val); - return TRUE; -} - -static gboolean jabber_free(gpointer data, gint fd, b_input_condition cond) -{ - struct jabber_data *jd = data; - - if(jd->gjc != NULL) { - gjab_delete(jd->gjc); - /* YAY for modules with their own memory pool managers!... - g_free(jd->gjc->sid); - And a less sarcastic yay for valgrind. :-) */ - jd->gjc = NULL; - } - g_free(jd); - - return FALSE; -} - -static void jabber_close(struct gaim_connection *gc) -{ - struct jabber_data *jd = gc->proto_data; - - if(jd) { - GSList *jcs = jd->chats; - - /* Free-up the jabber_chat struct allocs and the list */ - while (jcs) { - g_free(jcs->data); - jcs = jcs->next; - } - g_slist_free(jd->chats); - - /* Free-up the away status memories and the list */ - if(jd->hash != NULL) { - g_hash_table_foreach_remove(jd->hash, jabber_destroy_hash, NULL); - g_hash_table_destroy(jd->hash); - jd->hash = NULL; - } - - /* Free-up the pending queries memories and the list */ - if(jd->gjc != NULL && jd->gjc->queries != NULL) { - g_hash_table_foreach_remove(jd->gjc->queries, jabber_destroy_hash, NULL); - g_hash_table_destroy(jd->gjc->queries); - jd->gjc->queries = NULL; - } - } - if (gc->inpa) - b_event_remove(gc->inpa); - - if(jd) { - b_timeout_add(50, jabber_free, jd); - if(jd->gjc != NULL) - xmlnode_free(jd->gjc->current); - } - gc->proto_data = NULL; -} - -static int jabber_send_im(struct gaim_connection *gc, char *who, char *message, int len, int flags) -{ - xmlnode x, y; - char *realwho; - gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; - - if (!who || !message) - return 0; - - x = xmlnode_new_tag("message"); - /* Bare username and "username" not the server itself? */ - if (!strchr(who, '@') && strcmp(who, gjc->user->server) != 0) - realwho = g_strdup_printf("%s@%s", who, gjc->user->server); - else - realwho = g_strdup(who); - xmlnode_put_attrib(x, "to", realwho); - g_free(realwho); - - xmlnode_insert_tag(x, "bitlbee"); - xmlnode_put_attrib(x, "type", "chat"); - - if (message && strlen(message)) { - y = xmlnode_insert_tag(x, "body"); - xmlnode_insert_cdata(y, message, -1); - } - - gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x); - xmlnode_free(x); - return 1; -} - -/* - * 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); - } -} - -/* - * Change buddy's group on server roster - */ -static void jabber_group_change(struct gaim_connection *gc, char *name, char *old_group, char *new_group) -{ - if(strcmp(old_group, new_group)) { - jabber_roster_update(gc, name); - } -} - -static void jabber_add_buddy(struct gaim_connection *gc, char *name) -{ - xmlnode x; - char *realwho; - gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; - - if (!((struct jabber_data *)gc->proto_data)->did_import) - return; - - if (!name) - return; - - if (!strcmp(gc->username, name)) - return; - - if (!strchr(name, '@')) - realwho = g_strdup_printf("%s@%s", name, gjc->user->server); - else { - jid who; - - if((who = jid_new(gjc->p, name)) == NULL) { - char *msg = g_strdup_printf("%s: \"%s\"", _("Invalid Jabber I.D."), name); - do_error_dialog(GJ_GC(gjc), msg, _("Jabber Error")); - g_free(msg); - jabber_remove_gaim_buddy(gc, name); - return; - } - if (who->user == NULL) { - /* FIXME: transport */ - return; - } - realwho = g_strdup_printf("%s@%s", who->user, who->server); - } - - x = xmlnode_new_tag("presence"); - xmlnode_put_attrib(x, "to", realwho); - xmlnode_put_attrib(x, "type", "subscribe"); - gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x); - xmlnode_free(x); - - jabber_roster_update(gc, realwho); - - g_free(realwho); -} - -static void jabber_remove_buddy(struct gaim_connection *gc, char *name, char *group) -{ - xmlnode x; - char *realwho; - gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; - - if (!name) - return; - - if (!strchr(name, '@')) - realwho = g_strdup_printf("%s@%s", name, gjc->user->server); - 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("Jabber ID: %s
\n", realwho); - - if((status = g_hash_table_lookup(jd->hash, realwho)) == NULL) { - status = _("Unknown"); - } - *ap++ = g_strdup_printf("Status: %s
\n", status); - - *ap = NULL; - - final= g_strjoinv(NULL, str_arr); - g_strfreev(str_arr); - - g_free(realwho); - g_free(final); - -} - -static GList *jabber_away_states(struct gaim_connection *gc) { - GList *m = NULL; - - m = g_list_append(m, "Online"); - m = g_list_append(m, "Chatty"); - m = g_list_append(m, "Away"); - m = g_list_append(m, "Extended Away"); - m = g_list_append(m, "Do Not Disturb"); - - return m; -} - -static void jabber_set_away(struct gaim_connection *gc, char *state, char *message) -{ - xmlnode x, y; - struct jabber_data *jd = gc->proto_data; - gjconn gjc = jd->gjc; - - gc->away = NULL; /* never send an auto-response */ - - x = xmlnode_new_tag("presence"); - - if (!strcmp(state, GAIM_AWAY_CUSTOM)) { - /* oh goody. Gaim is telling us what to do. */ - if (message) { - /* Gaim wants us to be away */ - y = xmlnode_insert_tag(x, "show"); - xmlnode_insert_cdata(y, "away", -1); - y = xmlnode_insert_tag(x, "status"); - xmlnode_insert_cdata(y, message, -1); - gc->away = ""; - } else { - /* Gaim wants us to not be away */ - /* but for Jabber, we can just send presence with no other information. */ - } - } else { - /* state is one of our own strings. it won't be NULL. */ - if (!g_strcasecmp(state, "Online")) { - /* once again, we don't have to put anything here */ - } else if (!g_strcasecmp(state, "Chatty")) { - y = xmlnode_insert_tag(x, "show"); - xmlnode_insert_cdata(y, "chat", -1); - } else if (!g_strcasecmp(state, "Away")) { - y = xmlnode_insert_tag(x, "show"); - xmlnode_insert_cdata(y, "away", -1); - gc->away = ""; - } else if (!g_strcasecmp(state, "Extended Away")) { - y = xmlnode_insert_tag(x, "show"); - xmlnode_insert_cdata(y, "xa", -1); - gc->away = ""; - } else if (!g_strcasecmp(state, "Do Not Disturb")) { - y = xmlnode_insert_tag(x, "show"); - xmlnode_insert_cdata(y, "dnd", -1); - gc->away = ""; - } - } - - gjab_send(gjc, x); - xmlnode_free(x); -} - -static void jabber_keepalive(struct gaim_connection *gc) { - struct jabber_data *jd = (struct jabber_data *)gc->proto_data; - gjab_send_raw(jd->gjc, " \t "); -} - -/*---------------------------------------*/ -/* Jabber "set info" (vCard) support */ -/*---------------------------------------*/ - -/* - * V-Card format: - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * <ROLE/> - * <DESC/> - * <BDAY/> - * </vCard> - * - * See also: - * - * http://docs.jabber.org/proto/html/vcard-temp.html - * http://www.vcard-xml.org/dtd/vCard-XML-v2-20010520.dtd - */ - -/* - * Cross-reference user-friendly V-Card entry labels to vCard XML tags - * and attributes. - * - * Order is (or should be) unimportant. For example: we have no way of - * knowing in what order real data will arrive. - * - * Format: Label, Pre-set text, "visible" flag, "editable" flag, XML tag - * name, XML tag's parent tag "path" (relative to vCard node). - * - * List is terminated by a NULL label pointer. - * - * Entries with no label text, but with XML tag and parent tag - * entries, are used by V-Card XML construction routines to - * "automagically" construct the appropriate XML node tree. - * - * Thoughts on future direction/expansion - * - * This is a "simple" vCard. - * - * It is possible for nodes other than the "vCard" node to have - * attributes. Should that prove necessary/desirable, add an - * "attributes" pointer to the vcard_template struct, create the - * necessary tag_attr structs, and add 'em to the vcard_dflt_data - * array. - * - * The above changes will (obviously) require changes to the vCard - * construction routines. - */ - -static struct vcard_template { - char *label; /* label text pointer */ - char *text; /* entry text pointer */ - int visible; /* should entry field be "visible?" */ - int editable; /* should entry field be editable? */ - char *tag; /* tag text */ - char *ptag; /* parent tag "path" text */ - char *url; /* vCard display format if URL */ -} vcard_template_data[] = { - {N_("Full Name"), NULL, TRUE, TRUE, "FN", NULL, NULL}, - {N_("Family Name"), NULL, TRUE, TRUE, "FAMILY", "N", NULL}, - {N_("Given Name"), NULL, TRUE, TRUE, "GIVEN", "N", NULL}, - {N_("Nickname"), NULL, TRUE, TRUE, "NICKNAME", NULL, NULL}, - {N_("URL"), NULL, TRUE, TRUE, "URL", NULL, "<A HREF=\"%s\">%s</A>"}, - {N_("Street Address"), NULL, TRUE, TRUE, "STREET", "ADR", NULL}, - {N_("Extended Address"), NULL, TRUE, TRUE, "EXTADD", "ADR", NULL}, - {N_("Locality"), NULL, TRUE, TRUE, "LOCALITY", "ADR", NULL}, - {N_("Region"), NULL, TRUE, TRUE, "REGION", "ADR", NULL}, - {N_("Postal Code"), NULL, TRUE, TRUE, "PCODE", "ADR", NULL}, - {N_("Country"), NULL, TRUE, TRUE, "COUNTRY", "ADR", NULL}, - {N_("Telephone"), NULL, TRUE, TRUE, "TELEPHONE", NULL, NULL}, - {N_("Email"), NULL, TRUE, TRUE, "EMAIL", NULL, "<A HREF=\"mailto:%s\">%s</A>"}, - {N_("Organization Name"), NULL, TRUE, TRUE, "ORGNAME", "ORG", NULL}, - {N_("Organization Unit"), NULL, TRUE, TRUE, "ORGUNIT", "ORG", NULL}, - {N_("Title"), NULL, TRUE, TRUE, "TITLE", NULL, NULL}, - {N_("Role"), NULL, TRUE, TRUE, "ROLE", NULL, NULL}, - {N_("Birthday"), NULL, TRUE, TRUE, "BDAY", NULL, NULL}, - {N_("Description"), NULL, TRUE, TRUE, "DESC", NULL, NULL}, - {"", NULL, TRUE, TRUE, "N", NULL, NULL}, - {"", NULL, TRUE, TRUE, "ADR", NULL, NULL}, - {"", NULL, TRUE, TRUE, "ORG", NULL, NULL}, - {NULL, NULL, 0, 0, NULL, NULL, NULL} -}; - -/* - * Used by routines to parse an XML-encoded string into an xmlnode tree - */ -typedef struct { - XML_Parser parser; - xmlnode current; -} *xmlstr2xmlnode_parser, xmlstr2xmlnode_parser_struct; - - -/* - * Used by XML_Parse on parsing CDATA - */ -static void xmlstr2xmlnode_charData(void *userdata, const char *s, int slen) -{ - xmlstr2xmlnode_parser xmlp = (xmlstr2xmlnode_parser) userdata; - - if (xmlp->current) - xmlnode_insert_cdata(xmlp->current, s, slen); -} - -/* - * Used by XML_Parse to start or append to an xmlnode - */ -static void xmlstr2xmlnode_startElement(void *userdata, const char *name, const char **attribs) -{ - xmlnode x; - xmlstr2xmlnode_parser xmlp = (xmlstr2xmlnode_parser) userdata; - - if (xmlp->current) { - /* Append the node to the current one */ - x = xmlnode_insert_tag(xmlp->current, name); - xmlnode_put_expat_attribs(x, attribs); - - xmlp->current = x; - } else { - x = xmlnode_new_tag(name); - xmlnode_put_expat_attribs(x, attribs); - xmlp->current = x; - } -} - -/* - * Used by XML_Parse to end an xmlnode - */ -static void xmlstr2xmlnode_endElement(void *userdata, const char *name) -{ - xmlstr2xmlnode_parser xmlp = (xmlstr2xmlnode_parser) userdata; - xmlnode x; - - if (xmlp->current != NULL && (x = xmlnode_get_parent(xmlp->current)) != NULL) { - xmlp->current = x; - } -} - -/* - * Parse an XML-encoded string into an xmlnode tree - * - * Caller is responsible for freeing the returned xmlnode - */ -static xmlnode xmlstr2xmlnode(char *xmlstring) -{ - xmlstr2xmlnode_parser my_parser = g_new(xmlstr2xmlnode_parser_struct, 1); - xmlnode x = NULL; - - my_parser->parser = XML_ParserCreate(NULL); - my_parser->current = NULL; - - XML_SetUserData(my_parser->parser, (void *)my_parser); - XML_SetElementHandler(my_parser->parser, xmlstr2xmlnode_startElement, xmlstr2xmlnode_endElement); - XML_SetCharacterDataHandler(my_parser->parser, xmlstr2xmlnode_charData); - XML_Parse(my_parser->parser, xmlstring, strlen(xmlstring), 0); - - x = my_parser->current; - - XML_ParserFree(my_parser->parser); - g_free(my_parser); - - return(x); -} - -/* - * 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) -{ - xmlnode x = NULL; - - /* - * If the parent tag wasn't specified, see if we can get it - * from the vCard template struct. - */ - if(parent_tag == NULL) { - struct vcard_template *vc_tp = vcard_template_data; - - while(vc_tp->label != NULL) { - if(strcmp(vc_tp->tag, new_tag) == 0) { - parent_tag = vc_tp->ptag; - break; - } - ++vc_tp; - } - } - - /* - * If we have a parent tag... - */ - if(parent_tag != NULL ) { - /* - * Try to get the parent node for a tag - */ - if((x = xmlnode_get_tag(start, parent_tag)) == NULL) { - /* - * Descend? - */ - char *grand_parent = strcpy(g_malloc(strlen(parent_tag) + 1), parent_tag); - char *parent; - - if((parent = strrchr(grand_parent, '/')) != NULL) { - *(parent++) = '\0'; - x = insert_tag_to_parent_tag(start, grand_parent, parent); - } else { - x = xmlnode_insert_tag(start, grand_parent); - } - g_free(grand_parent); - } else { - /* - * We found *something* to be the parent node. - * Note: may be the "root" node! - */ - xmlnode y; - if((y = xmlnode_get_tag(x, new_tag)) != NULL) { - return(y); - } - } - } - - /* - * insert the new tag into its parent node - */ - return(xmlnode_insert_tag((x == NULL? start : x), new_tag)); -} - -/* - * Send vCard info to Jabber server - */ -static void jabber_set_info(struct gaim_connection *gc, char *info) -{ - 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); - - xmlnode_put_attrib(x, "id", id); - - /* - * Send only if there's actually any *information* to send - */ - if((vc_node = xmlstr2xmlnode(info)) != NULL && xmlnode_get_name(vc_node) != NULL && - g_strncasecmp(xmlnode_get_name(vc_node), "vcard", 5) == 0) { - xmlnode_insert_tag_node(x, vc_node); - gjab_send(gjc, x); - } - - xmlnode_free(x); -} - -/* - * displays a Jabber vCard - */ -static void jabber_handlevcard(gjconn gjc, xmlnode querynode, char *from) -{ - struct jabber_data *jd = GJ_GC(gjc)->proto_data; - jid who = jid_new(gjc->p, from); - char *status = NULL, *text = NULL; - GString *str = g_string_sized_new(100); - xmlnode child; - - gchar *buddy = NULL; - - 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"); - } - - g_string_sprintfa(str, "%s: %s - %s: %s", _("Jabber ID"), buddy, _("Status"), - status); - - for(child = querynode->firstchild; child; child = child->next) - { - 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")); - } - } - - serv_got_crap(GJ_GC(gjc), "%s\n%s", _("User Info"), str->str); - - g_free(buddy); - g_string_free(str, TRUE); -} - -void jabber_init() -{ - struct prpl *ret = g_new0(struct prpl, 1); - - ret->name = "jabber"; - ret->away_states = jabber_away_states; - ret->acc_init = jabber_acc_init; - ret->login = jabber_login; - ret->close = jabber_close; - ret->send_im = jabber_send_im; - ret->set_info = jabber_set_info; - ret->get_info = jabber_get_info; - ret->set_away = jabber_set_away; - ret->get_away = jabber_get_away_msg; - ret->add_buddy = jabber_add_buddy; - ret->remove_buddy = jabber_remove_buddy; - ret->keepalive = jabber_keepalive; - ret->alias_buddy = jabber_roster_update; - ret->group_buddy = jabber_group_change; - ret->handle_cmp = g_strcasecmp; - - register_protocol (ret); -} -- cgit v1.2.3 From f06894d8f55b50b632c1d81ad878f8581273ba66 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast <wilmer@gaast.net> Date: Wed, 20 Sep 2006 12:18:56 +0200 Subject: Added some pretty empty files. --- protocols/jabber/jabber.c | 147 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 protocols/jabber/jabber.c (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c new file mode 100644 index 00000000..0a091b06 --- /dev/null +++ b/protocols/jabber/jabber.c @@ -0,0 +1,147 @@ +/***************************************************************************\ +* * +* 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 <unistd.h> +#include <ctype.h> +#include <stdio.h> + +#include "xmltree.h" +#include "bitlbee.h" +#include "jabber.h" + +static void jabber_acc_init( account_t *acc ) +{ + set_t *s; + + s = set_add( &acc->set, "port", "5222", set_eval_int, acc ); + s->flags |= ACC_SET_OFFLINE_ONLY; + + s = set_add( &acc->set, "priority", "0", set_eval_resprio, acc ); + + s = set_add( &acc->set, "resource", "BitlBee", set_eval_resprio, acc ); + + 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; + + s = set_add( &acc->set, "tls", "try", set_eval_tls, acc ); + s->flags |= ACC_SET_OFFLINE_ONLY; +} + +static void jabber_login( account_t *acc ) +{ +} + +static void jabber_close( struct gaim_connection *gc ) +{ +} + +static int jabber_send_im( struct gaim_connection *gc, char *who, char *message, int len, int away ) +{ +} + +void jabber_init() +{ + struct prpl *ret = g_new0(struct prpl, 1); + + ret->name = "jabber"; + ret->login = jabber_login; + ret->acc_init = jabber_acc_init; + ret->close = jabber_close; + ret->send_im = jabber_send_im; +// ret->away_states = jabber_away_states; +// ret->get_status_string = jabber_get_status_string; +// ret->set_away = jabber_set_away; +// ret->set_info = jabber_set_info; +// ret->get_info = jabber_get_info; +// ret->add_buddy = jabber_add_buddy; +// ret->remove_buddy = jabber_remove_buddy; +// ret->chat_send = jabber_chat_send; +// ret->chat_invite = jabber_chat_invite; +// ret->chat_leave = jabber_chat_leave; +// ret->chat_open = jabber_chat_open; +// ret->keepalive = jabber_keepalive; +// ret->add_permit = jabber_add_permit; +// ret->rem_permit = jabber_rem_permit; +// ret->add_deny = jabber_add_deny; +// ret->rem_deny = jabber_rem_deny; +// ret->send_typing = jabber_send_typing; + ret->handle_cmp = g_strcasecmp; + + register_protocol(ret); +} + +static xt_status jabber_end_of_stream( struct xt_node *node, gpointer data ) +{ + return XT_ABORT; +} + +static xt_status jabber_pkt_misc( struct xt_node *node, gpointer data ) +{ + printf( "Received unknown packet:\n" ); + xt_print( node ); + + return XT_HANDLED; +} + +static const struct xt_handler_entry jabber_handlers[] = { + { "stream:stream", "<root>", jabber_end_of_stream }, + { "iq", "stream:stream", jabber_pkt_iq }, + { "message", "stream:stream", jabber_pkt_message }, + { "presence", "stream:stream", jabber_pkt_presence }, + { NULL, "stream:stream", jabber_pkt_misc }, + { NULL, NULL, NULL } +}; + +#if 0 +int main( int argc, char *argv[] ) +{ + struct xt_parser *xt = xt_new( NULL ); + struct xt_node *msg; + int i; + char buf[512]; + + msg = xt_new_node( "message", NULL, xt_new_node( "body", "blaataap-test", NULL ) ); + xt_add_child( msg, xt_new_node( "html", NULL, xt_new_node( "body", "<b>blaataap in html</b>", NULL ) ) ); + xt_add_attr( msg, "xmlns", "jabber:client" ); + xt_add_attr( xt_find_node( msg->children, "html" ), "xmlns", "html rotte zooi" ); + printf( "%s\n", xt_to_string( msg ) ); + + while( ( i = read( 0, buf, 512 ) ) > 0 ) + { + if( xt_feed( xt, buf, i ) < 1 ) + break; + } + xt->handlers = jabber_handlers; + xt_handle( xt, NULL ); + + xt_cleanup( xt, NULL ); + printf( "%d\n", xt->root ); + + xt_free( xt ); +} +#endif \ No newline at end of file -- cgit v1.2.3 From 21167d2d14c333d67445546bb69dd52dd295287d Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast <wilmer@gaast.net> Date: Wed, 20 Sep 2006 21:42:27 +0200 Subject: It can send a valid (pre-XMPP) login packet. Lots of work to do, still... --- protocols/jabber/jabber.c | 69 +++++++++++++++++++++++++++++++---------------- 1 file changed, 46 insertions(+), 23 deletions(-) (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 0a091b06..9732d6eb 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -27,6 +27,7 @@ #include <ctype.h> #include <stdio.h> +#include "ssl_client.h" #include "xmltree.h" #include "bitlbee.h" #include "jabber.h" @@ -54,14 +55,58 @@ static void jabber_acc_init( account_t *acc ) static void jabber_login( account_t *acc ) { + struct gaim_connection *gc = new_gaim_conn( acc ); + struct jabber_data *jd = g_new0( struct jabber_data, 1 ); + + jd->gc = gc; + gc->proto_data = jd; + + jd->username = g_strdup( acc->user ); + jd->server = strchr( jd->username, '@' ); + + if( jd->server == NULL ) + { + hide_login_progress( gc, "Incomplete account name (format it like <username@jabberserver.name>)" ); + signoff( gc ); + return; + } + + /* So don't think of free()ing jd->server.. :-) */ + *jd->server = 0; + jd->server ++; + + if( set_getbool( &acc->set, "ssl" ) ) + { + signoff( gc ); + /* TODO! */ + } + else + { + jd->fd = proxy_connect( jd->server, set_getint( &acc->set, "port" ), jabber_connected_plain, gc ); + } } static void jabber_close( struct gaim_connection *gc ) { + struct jabber_data *jd = gc->proto_data; + + 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 ); + + g_free( jd->username ); + g_free( jd ); } static int jabber_send_im( struct gaim_connection *gc, char *who, char *message, int len, int away ) { + return 0; } void jabber_init() @@ -95,28 +140,6 @@ void jabber_init() register_protocol(ret); } -static xt_status jabber_end_of_stream( struct xt_node *node, gpointer data ) -{ - return XT_ABORT; -} - -static xt_status jabber_pkt_misc( struct xt_node *node, gpointer data ) -{ - printf( "Received unknown packet:\n" ); - xt_print( node ); - - return XT_HANDLED; -} - -static const struct xt_handler_entry jabber_handlers[] = { - { "stream:stream", "<root>", jabber_end_of_stream }, - { "iq", "stream:stream", jabber_pkt_iq }, - { "message", "stream:stream", jabber_pkt_message }, - { "presence", "stream:stream", jabber_pkt_presence }, - { NULL, "stream:stream", jabber_pkt_misc }, - { NULL, NULL, NULL } -}; - #if 0 int main( int argc, char *argv[] ) { @@ -144,4 +167,4 @@ int main( int argc, char *argv[] ) xt_free( xt ); } -#endif \ No newline at end of file +#endif -- cgit v1.2.3 From 70f6aab8f4b6a1bbd9991e800dde91a02cc363f0 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast <wilmer@gaast.net> Date: Wed, 20 Sep 2006 22:09:19 +0200 Subject: It now requests a roster when logged in, no parsing for it yet. --- protocols/jabber/jabber.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 9732d6eb..cc7bac3d 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -100,6 +100,8 @@ static void jabber_close( struct gaim_connection *gc ) if( jd->fd >= 0 ) closesocket( jd->fd ); + xt_free( jd->xt ); + g_free( jd->username ); g_free( jd ); } -- cgit v1.2.3 From dd788bb0b18684be993cc7edf1f0da6f8e36449d Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast <wilmer@gaast.net> Date: Thu, 21 Sep 2006 09:32:39 +0200 Subject: Added enough to not make it crash on login, and it can properly receive messages now. Just try to figure out why it doesn't get typing notifications... --- protocols/jabber/jabber.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index cc7bac3d..84d7e366 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -111,6 +111,22 @@ static int jabber_send_im( struct gaim_connection *gc, char *who, char *message, return 0; } +static GList *jabber_away_states( struct gaim_connection *gc ) +{ + GList *l = NULL; + + l = g_list_append( l, (void*) "Online" ); + l = g_list_append( l, (void*) "Away" ); + l = g_list_append( l, (void*) "Extended Away" ); + l = g_list_append( l, (void*) "Do Not Disturb" ); + + return( l ); +} + +static void jabber_set_away( struct gaim_connection *gc, char *state, char *message ) +{ +} + void jabber_init() { struct prpl *ret = g_new0(struct prpl, 1); @@ -120,9 +136,9 @@ void jabber_init() ret->acc_init = jabber_acc_init; ret->close = jabber_close; ret->send_im = jabber_send_im; -// ret->away_states = jabber_away_states; + ret->away_states = jabber_away_states; // ret->get_status_string = jabber_get_status_string; -// ret->set_away = jabber_set_away; + ret->set_away = jabber_set_away; // ret->set_info = jabber_set_info; // ret->get_info = jabber_get_info; // ret->add_buddy = jabber_add_buddy; -- cgit v1.2.3 From 4a0614e65b45364d4d1f631aeaae047a92c752c5 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast <wilmer@gaast.net> Date: Thu, 21 Sep 2006 11:37:03 +0200 Subject: Added simple parsing of incoming <presence> tags, a nice </stream:stream> at the end of sessions, support for sending messages, and restored the old (and leaking) xt_print(), which I'll only use for debugging. --- protocols/jabber/jabber.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 84d7e366..132a355c 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -90,6 +90,8 @@ static void jabber_close( struct gaim_connection *gc ) { struct jabber_data *jd = gc->proto_data; + jabber_end_stream( gc ); + if( jd->r_inpa >= 0 ) b_event_remove( jd->r_inpa ); if( jd->w_inpa >= 0 ) @@ -108,7 +110,15 @@ static void jabber_close( struct gaim_connection *gc ) static int jabber_send_im( struct gaim_connection *gc, char *who, char *message, int len, int away ) { - return 0; + struct xt_node *node; + int st; + + node = xt_new_node( "body", message, NULL ); + node = jabber_make_packet( "message", "chat", who, node ); + st = jabber_write_packet( gc, node ); + xt_free_node( node ); + + return st; } static GList *jabber_away_states( struct gaim_connection *gc ) -- cgit v1.2.3 From deff0406d501264e1d91203ea8f91411a150e35f Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast <wilmer@gaast.net> Date: Thu, 21 Sep 2006 21:48:17 +0200 Subject: Implemented set_away() (VERY simple version, have to add an away state table like in the MSN module), added sending of keepalive "packets" and removed old main() code (for testing only) from jabber.c. --- protocols/jabber/jabber.c | 44 ++++++++++++-------------------------------- 1 file changed, 12 insertions(+), 32 deletions(-) (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 132a355c..13eac23e 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -121,6 +121,7 @@ static int jabber_send_im( struct gaim_connection *gc, char *who, char *message, return st; } +/* TODO: For away state handling, implement some list like the one for MSN. */ static GList *jabber_away_states( struct gaim_connection *gc ) { GList *l = NULL; @@ -135,11 +136,19 @@ static GList *jabber_away_states( struct gaim_connection *gc ) static void jabber_set_away( struct gaim_connection *gc, char *state, char *message ) { + /* For now let's just always set state to "away" and send the message, if available. */ + presence_send( gc, NULL, g_strcasecmp( state, "Online" ) == 0 ? NULL : "away", message ); +} + +static void jabber_keepalive( struct gaim_connection *gc ) +{ + /* Just any whitespace character is enough as a keepalive for XMPP sessions. */ + jabber_write( gc, "\n", 1 ); } void jabber_init() { - struct prpl *ret = g_new0(struct prpl, 1); + struct prpl *ret = g_new0( struct prpl, 1 ); ret->name = "jabber"; ret->login = jabber_login; @@ -157,7 +166,7 @@ void jabber_init() // ret->chat_invite = jabber_chat_invite; // ret->chat_leave = jabber_chat_leave; // ret->chat_open = jabber_chat_open; -// ret->keepalive = jabber_keepalive; + ret->keepalive = jabber_keepalive; // ret->add_permit = jabber_add_permit; // ret->rem_permit = jabber_rem_permit; // ret->add_deny = jabber_add_deny; @@ -165,34 +174,5 @@ void jabber_init() // ret->send_typing = jabber_send_typing; ret->handle_cmp = g_strcasecmp; - register_protocol(ret); -} - -#if 0 -int main( int argc, char *argv[] ) -{ - struct xt_parser *xt = xt_new( NULL ); - struct xt_node *msg; - int i; - char buf[512]; - - msg = xt_new_node( "message", NULL, xt_new_node( "body", "blaataap-test", NULL ) ); - xt_add_child( msg, xt_new_node( "html", NULL, xt_new_node( "body", "<b>blaataap in html</b>", NULL ) ) ); - xt_add_attr( msg, "xmlns", "jabber:client" ); - xt_add_attr( xt_find_node( msg->children, "html" ), "xmlns", "html rotte zooi" ); - printf( "%s\n", xt_to_string( msg ) ); - - while( ( i = read( 0, buf, 512 ) ) > 0 ) - { - if( xt_feed( xt, buf, i ) < 1 ) - break; - } - xt->handlers = jabber_handlers; - xt_handle( xt, NULL ); - - xt_cleanup( xt, NULL ); - printf( "%d\n", xt->root ); - - xt_free( xt ); + register_protocol( ret ); } -#endif -- cgit v1.2.3 From fe7a55434385fd858453dffdbb425a21f41e3859 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast <wilmer@gaast.net> Date: Fri, 22 Sep 2006 20:39:31 +0200 Subject: Better detection of successful IQ authentication (using packet caching), properly working SASL authentication (although only PLAIN so far). --- protocols/jabber/jabber.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 13eac23e..c8525db5 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -75,6 +75,8 @@ static void jabber_login( account_t *acc ) *jd->server = 0; jd->server ++; + jd->node_cache = xt_new_node( "cache", NULL, NULL ); + if( set_getbool( &acc->set, "ssl" ) ) { signoff( gc ); @@ -102,6 +104,10 @@ static void jabber_close( struct gaim_connection *gc ) if( jd->fd >= 0 ) closesocket( jd->fd ); + if( jd->tx_len ) + g_free( jd->txq ); + + xt_free_node( jd->node_cache ); xt_free( jd->xt ); g_free( jd->username ); -- cgit v1.2.3 From 5e202b09f2cd9faff5f316ae6804facb5342eace Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast <wilmer@gaast.net> Date: Sat, 23 Sep 2006 18:18:24 +0200 Subject: Implemented a list of away states, using this for a better set_away(), and got rid of the double <presence> tag sent because of presence_announce(). --- protocols/jabber/jabber.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index c8525db5..b3199cde 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -110,6 +110,7 @@ static void jabber_close( struct gaim_connection *gc ) xt_free_node( jd->node_cache ); xt_free( jd->xt ); + g_free( jd->away_message ); g_free( jd->username ); g_free( jd ); } @@ -127,23 +128,30 @@ static int jabber_send_im( struct gaim_connection *gc, char *who, char *message, return st; } -/* TODO: For away state handling, implement some list like the one for MSN. */ static GList *jabber_away_states( struct gaim_connection *gc ) { - GList *l = NULL; + static GList *l = NULL; + int i; - l = g_list_append( l, (void*) "Online" ); - l = g_list_append( l, (void*) "Away" ); - l = g_list_append( l, (void*) "Extended Away" ); - l = g_list_append( l, (void*) "Do Not Disturb" ); + 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 ); + return l; } -static void jabber_set_away( struct gaim_connection *gc, char *state, char *message ) +static void jabber_set_away( struct gaim_connection *gc, char *state_txt, char *message ) { - /* For now let's just always set state to "away" and send the message, if available. */ - presence_send( gc, NULL, g_strcasecmp( state, "Online" ) == 0 ? NULL : "away", message ); + struct jabber_data *jd = gc->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( gc, NULL, jd->away_state->code, jd->away_message ); } static void jabber_keepalive( struct gaim_connection *gc ) -- cgit v1.2.3 From 172a73f1a4b37fa20d1d50496a3faccb8fe6c769 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast <wilmer@gaast.net> Date: Sun, 24 Sep 2006 12:25:41 +0200 Subject: Updated <presence> stuff to handle changing the priority setting. --- protocols/jabber/jabber.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index b3199cde..ee26a007 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -151,7 +151,7 @@ static void jabber_set_away( struct gaim_connection *gc, char *state_txt, char * g_free( jd->away_message ); jd->away_message = ( message && *message ) ? g_strdup( message ) : NULL; - presence_send( gc, NULL, jd->away_state->code, jd->away_message ); + presence_send_update( gc ); } static void jabber_keepalive( struct gaim_connection *gc ) -- cgit v1.2.3 From 42127dcd26be4f6746004237eac5333ffbb94f8e Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast <wilmer@gaast.net> Date: Sun, 24 Sep 2006 13:57:45 +0200 Subject: Added support for SSL- and TLS-connections. Checking of the "tls" user setting has to be finished, plus an ssl_starttls() function for the other SSL libraries (this code will only compile with GnuTLS for now). --- protocols/jabber/jabber.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index ee26a007..a337dd68 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -79,8 +79,8 @@ static void jabber_login( account_t *acc ) if( set_getbool( &acc->set, "ssl" ) ) { - signoff( gc ); - /* TODO! */ + jd->ssl = ssl_connect( jd->server, set_getint( &acc->set, "port" ), jabber_connected_ssl, gc ); + jd->fd = ssl_getfd( jd->ssl ); } else { -- cgit v1.2.3 From cfbb3a6e5e11a8d2d162d80958d6ce997104e9d3 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast <wilmer@gaast.net> Date: Sun, 24 Sep 2006 20:08:07 +0200 Subject: Added add_buddy/remove_buddy functions. Removing a contact doesn't seem to work perfectly though. --- protocols/jabber/jabber.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index a337dd68..21633973 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -154,6 +154,18 @@ static void jabber_set_away( struct gaim_connection *gc, char *state_txt, char * presence_send_update( gc ); } +static void jabber_add_buddy( struct gaim_connection *gc, char *who ) +{ + if( jabber_add_to_roster( gc, who, NULL ) ) + presence_send_request( gc, who, "subscribe" ); +} + +static void jabber_remove_buddy( struct gaim_connection *gc, char *who, char *group ) +{ + if( jabber_remove_from_roster( gc, who ) ) + presence_send_request( gc, who, "unsubscribe" ); +} + static void jabber_keepalive( struct gaim_connection *gc ) { /* Just any whitespace character is enough as a keepalive for XMPP sessions. */ @@ -174,8 +186,8 @@ void jabber_init() ret->set_away = jabber_set_away; // 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->add_buddy = jabber_add_buddy; + ret->remove_buddy = jabber_remove_buddy; // ret->chat_send = jabber_chat_send; // ret->chat_invite = jabber_chat_invite; // ret->chat_leave = jabber_chat_leave; -- cgit v1.2.3 From 8e5e2e9a0ef549c94afc8041dc7d99358f51c9bd Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast <wilmer@gaast.net> Date: Sun, 24 Sep 2006 21:25:06 +0200 Subject: Handling of incoming authorization requests, manual block/allow. (Doesn't seem to be completely like how it works on other IM networks.) --- protocols/jabber/jabber.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 21633973..05ff8047 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -172,6 +172,24 @@ static void jabber_keepalive( struct gaim_connection *gc ) jabber_write( gc, "\n", 1 ); } +static void jabber_add_permit( struct gaim_connection *gc, char *who ) +{ + presence_send_request( gc, who, "subscribed" ); +} + +static void jabber_rem_permit( struct gaim_connection *gc, char *who ) +{ + presence_send_request( gc, who, "unsubscribed" ); +} + +static void jabber_add_deny( struct gaim_connection *gc, char *who ) +{ +} + +static void jabber_rem_deny( struct gaim_connection *gc, char *who ) +{ +} + void jabber_init() { struct prpl *ret = g_new0( struct prpl, 1 ); @@ -193,10 +211,10 @@ void jabber_init() // ret->chat_leave = jabber_chat_leave; // ret->chat_open = jabber_chat_open; ret->keepalive = jabber_keepalive; -// ret->add_permit = jabber_add_permit; -// ret->rem_permit = jabber_rem_permit; -// ret->add_deny = jabber_add_deny; -// ret->rem_deny = jabber_rem_deny; + ret->add_permit = jabber_add_permit; + ret->rem_permit = jabber_rem_permit; + ret->add_deny = jabber_add_deny; + ret->rem_deny = jabber_rem_deny; // ret->send_typing = jabber_send_typing; ret->handle_cmp = g_strcasecmp; -- cgit v1.2.3 From a214954bda17730b6251e5c5c26f6d4d23eb1ed9 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast <wilmer@gaast.net> Date: Sun, 24 Sep 2006 22:00:09 +0200 Subject: Added some experimental stuff with typing notifications that seems to show that Gaim doesn't support the official JEP-0085 standard (yet?)... And added simple garbage collection for the node_cache. Will improve it later. --- protocols/jabber/jabber.c | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 05ff8047..32bc7563 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -117,11 +117,20 @@ static void jabber_close( struct gaim_connection *gc ) static int jabber_send_im( struct gaim_connection *gc, char *who, char *message, int len, int away ) { - struct xt_node *node; + struct xt_node *node, *event; int st; + /* + event = xt_new_node( "active", NULL, NULL ); + xt_add_attr( event, "xlmns", "http://jabber.org/protocol/chatstates" ); + + event = xt_new_node( "x", NULL, xt_new_node( "composing", NULL, NULL ) ); + xt_add_attr( event, "xmlns", "jabber:x:event" ); + */ + node = xt_new_node( "body", message, NULL ); node = jabber_make_packet( "message", "chat", who, node ); + xt_add_child( node, event ); st = jabber_write_packet( gc, node ); xt_free_node( node ); @@ -168,8 +177,39 @@ static void jabber_remove_buddy( struct gaim_connection *gc, char *who, char *gr static void jabber_keepalive( struct gaim_connection *gc ) { + struct jabber_data *jd = gc->proto_data; + struct xt_node *c, *prev; + /* Just any whitespace character is enough as a keepalive for XMPP sessions. */ jabber_write( gc, "\n", 1 ); + + /* Let's abuse this keepalive for garbage collection of the node cache too. + It runs every minute, so let's mark every node with a special flag the + first time we see it, and clean it up the second time (clean up all + packets with the flag set). + + node->flags is normally only used by xmltree itself for parsing/handling, + so it should be safe to use the variable for gc. */ + + /* This horrible loop is explained in xmltree.c. Makes me wonder if maybe I + didn't choose the perfect data structure... */ + for( prev = NULL, c = jd->node_cache->children; c; prev = c, c = c ? c->next : jd->node_cache->children ) + { + if( c->flags == 0 ) + { + c->flags ++; + } + else + { + if( prev ) + prev->next = c->next; + else + jd->node_cache->children = c->next; + + xt_free_node( c ); + c = prev; + } + } } static void jabber_add_permit( struct gaim_connection *gc, char *who ) -- cgit v1.2.3 From eab2ac45071373751a3041c85b0ab69460109032 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast <wilmer@gaast.net> Date: Mon, 25 Sep 2006 09:42:39 +0200 Subject: Saner garbage collection for node cache. --- protocols/jabber/jabber.c | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 32bc7563..39a61bf3 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -178,7 +178,7 @@ static void jabber_remove_buddy( struct gaim_connection *gc, char *who, char *gr static void jabber_keepalive( struct gaim_connection *gc ) { struct jabber_data *jd = gc->proto_data; - struct xt_node *c, *prev; + struct xt_node *c, *tmp; /* Just any whitespace character is enough as a keepalive for XMPP sessions. */ jabber_write( gc, "\n", 1 ); @@ -193,22 +193,33 @@ static void jabber_keepalive( struct gaim_connection *gc ) /* This horrible loop is explained in xmltree.c. Makes me wonder if maybe I didn't choose the perfect data structure... */ - for( prev = NULL, c = jd->node_cache->children; c; prev = c, c = c ? c->next : jd->node_cache->children ) + for( c = jd->node_cache->children; c; c = c->next ) + if( !( c->flags & XT_SEEN ) ) + break; + + /* Now c points at the first unflagged node (or at NULL). Clean up + everything until that point. */ + while( jd->node_cache->children != c ) + { + /* + printf( "Cleaning up:\n" ); + xt_print( jd->node_cache->children ); + */ + + tmp = jd->node_cache->children->next; + xt_free_node( jd->node_cache->children ); + jd->node_cache->children = tmp; + } + + /* Now flag the ones that were still unflagged. */ + for( c = jd->node_cache->children; c; c = c->next ) { - if( c->flags == 0 ) - { - c->flags ++; - } - else - { - if( prev ) - prev->next = c->next; - else - jd->node_cache->children = c->next; - - xt_free_node( c ); - c = prev; - } + /* + printf( "Flagged:\n" ); + xt_print( c ); + */ + + c->flags |= XT_SEEN; } } -- cgit v1.2.3 From ebe7b36af555d644357efbc0e63393927162bf06 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast <wilmer@gaast.net> Date: Mon, 25 Sep 2006 12:10:14 +0200 Subject: Changing the resource string while online probably doesn't work. --- protocols/jabber/jabber.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 39a61bf3..7f679559 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -39,9 +39,10 @@ static void jabber_acc_init( account_t *acc ) s = set_add( &acc->set, "port", "5222", set_eval_int, acc ); s->flags |= ACC_SET_OFFLINE_ONLY; - s = set_add( &acc->set, "priority", "0", set_eval_resprio, acc ); + s = set_add( &acc->set, "priority", "0", set_eval_priority, acc ); - s = set_add( &acc->set, "resource", "BitlBee", set_eval_resprio, acc ); + s = set_add( &acc->set, "resource", "BitlBee", NULL, acc ); + s->flags |= ACC_SET_OFFLINE_ONLY; s = set_add( &acc->set, "server", NULL, set_eval_account, acc ); s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY; @@ -233,6 +234,8 @@ static void jabber_rem_permit( struct gaim_connection *gc, char *who ) presence_send_request( gc, who, "unsubscribed" ); } +/* XMPP doesn't have both a block- and and allow-list, so these two functions + will be no-ops: */ static void jabber_add_deny( struct gaim_connection *gc, char *who ) { } -- cgit v1.2.3 From 281859e83eb7c953b64a970d3156279b323617d0 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast <wilmer@gaast.net> Date: Mon, 25 Sep 2006 19:04:50 +0200 Subject: Forgot to comment out one line... --- protocols/jabber/jabber.c | 1 - 1 file changed, 1 deletion(-) (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 7f679559..df518956 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -131,7 +131,6 @@ static int jabber_send_im( struct gaim_connection *gc, char *who, char *message, node = xt_new_node( "body", message, NULL ); node = jabber_make_packet( "message", "chat", who, node ); - xt_add_child( node, event ); st = jabber_write_packet( gc, node ); xt_free_node( node ); -- cgit v1.2.3 From 6baca2a2910d0b6663b54ef302820d9ffbbf5eee Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast <wilmer@gaast.net> Date: Sun, 1 Oct 2006 11:31:41 +0200 Subject: Some initial hooks/stuff for privacy lists, and fixed a crash bug on connecting to Google Talk. --- protocols/jabber/jabber.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index df518956..8ec6b70c 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -41,6 +41,9 @@ static void jabber_acc_init( account_t *acc ) s = set_add( &acc->set, "priority", "0", set_eval_priority, acc ); + s = set_add( &acc->set, "privacy_list", NULL, NULL, acc ); + /* TODO: Add evaluator. */ + s = set_add( &acc->set, "resource", "BitlBee", NULL, acc ); s->flags |= ACC_SET_OFFLINE_ONLY; @@ -80,12 +83,12 @@ static void jabber_login( account_t *acc ) if( set_getbool( &acc->set, "ssl" ) ) { - jd->ssl = ssl_connect( jd->server, set_getint( &acc->set, "port" ), jabber_connected_ssl, gc ); + jd->ssl = ssl_connect( acc->server ? acc->server : jd->server, set_getint( &acc->set, "port" ), jabber_connected_ssl, gc ); jd->fd = ssl_getfd( jd->ssl ); } else { - jd->fd = proxy_connect( jd->server, set_getint( &acc->set, "port" ), jabber_connected_plain, gc ); + jd->fd = proxy_connect( acc->server ? acc->server : jd->server, set_getint( &acc->set, "port" ), jabber_connected_plain, gc ); } } @@ -108,6 +111,9 @@ static void jabber_close( struct gaim_connection *gc ) if( jd->tx_len ) g_free( jd->txq ); + xt_free_node( jd->privacy_list ); + g_free( jd->privacy_active ); + xt_free_node( jd->node_cache ); xt_free( jd->xt ); -- cgit v1.2.3 From 995913b4be70be6e07b8aa7661ac639e5fc0d6e7 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast <wilmer@gaast.net> Date: Mon, 2 Oct 2006 19:46:57 +0200 Subject: Added some error handling for the (not very complete yet) privacy list code. --- protocols/jabber/jabber.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 8ec6b70c..39d93d16 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -41,8 +41,7 @@ static void jabber_acc_init( account_t *acc ) s = set_add( &acc->set, "priority", "0", set_eval_priority, acc ); - s = set_add( &acc->set, "privacy_list", NULL, NULL, acc ); - /* TODO: Add evaluator. */ + s = set_add( &acc->set, "privacy_list", NULL, set_eval_privacy_list, acc ); s = set_add( &acc->set, "resource", "BitlBee", NULL, acc ); s->flags |= ACC_SET_OFFLINE_ONLY; @@ -231,12 +230,24 @@ static void jabber_keepalive( struct gaim_connection *gc ) static void jabber_add_permit( struct gaim_connection *gc, char *who ) { - presence_send_request( gc, who, "subscribed" ); + struct jabber_data *jd = gc->proto_data; + + if( jd->flags & JFLAG_PRIVACY_BROKEN ) + { + serv_got_crap( gc, "Privacy lists not supported by this server" ); + return; + } } static void jabber_rem_permit( struct gaim_connection *gc, char *who ) { - presence_send_request( gc, who, "unsubscribed" ); + struct jabber_data *jd = gc->proto_data; + + if( jd->flags & JFLAG_PRIVACY_BROKEN ) + { + serv_got_crap( gc, "Privacy lists not supported by this server" ); + return; + } } /* XMPP doesn't have both a block- and and allow-list, so these two functions -- cgit v1.2.3 From cc2cb2da3f1c0e2ad65708f4110e74e945ea9b66 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast <wilmer@gaast.net> Date: Wed, 4 Oct 2006 20:14:41 +0200 Subject: Lack of TLS support is also detected now if the server doesn't support XMPP 1.0 (properly), and restored immediate writes by splitting up the jabber_write_callback() function. --- protocols/jabber/jabber.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 39d93d16..fc415ca7 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -123,7 +123,7 @@ static void jabber_close( struct gaim_connection *gc ) static int jabber_send_im( struct gaim_connection *gc, char *who, char *message, int len, int away ) { - struct xt_node *node, *event; + struct xt_node *node; int st; /* -- cgit v1.2.3 From 090f1cbe72373b31e753af4a1442ddd53b02791b Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast <wilmer@gaast.net> Date: Sat, 7 Oct 2006 15:01:02 +0200 Subject: Never mind about those privacy lists, they're horrible and not supported by any client I know of. Also, they're already working on a (probably completely incompatible) standard: JEP-191. Maybe BitlBee will implement it too some day... --- protocols/jabber/jabber.c | 41 ----------------------------------------- 1 file changed, 41 deletions(-) (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index fc415ca7..706d31c3 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -41,8 +41,6 @@ static void jabber_acc_init( account_t *acc ) s = set_add( &acc->set, "priority", "0", set_eval_priority, acc ); - s = set_add( &acc->set, "privacy_list", NULL, set_eval_privacy_list, acc ); - s = set_add( &acc->set, "resource", "BitlBee", NULL, acc ); s->flags |= ACC_SET_OFFLINE_ONLY; @@ -110,9 +108,6 @@ static void jabber_close( struct gaim_connection *gc ) if( jd->tx_len ) g_free( jd->txq ); - xt_free_node( jd->privacy_list ); - g_free( jd->privacy_active ); - xt_free_node( jd->node_cache ); xt_free( jd->xt ); @@ -228,38 +223,6 @@ static void jabber_keepalive( struct gaim_connection *gc ) } } -static void jabber_add_permit( struct gaim_connection *gc, char *who ) -{ - struct jabber_data *jd = gc->proto_data; - - if( jd->flags & JFLAG_PRIVACY_BROKEN ) - { - serv_got_crap( gc, "Privacy lists not supported by this server" ); - return; - } -} - -static void jabber_rem_permit( struct gaim_connection *gc, char *who ) -{ - struct jabber_data *jd = gc->proto_data; - - if( jd->flags & JFLAG_PRIVACY_BROKEN ) - { - serv_got_crap( gc, "Privacy lists not supported by this server" ); - return; - } -} - -/* XMPP doesn't have both a block- and and allow-list, so these two functions - will be no-ops: */ -static void jabber_add_deny( struct gaim_connection *gc, char *who ) -{ -} - -static void jabber_rem_deny( struct gaim_connection *gc, char *who ) -{ -} - void jabber_init() { struct prpl *ret = g_new0( struct prpl, 1 ); @@ -281,10 +244,6 @@ void jabber_init() // ret->chat_leave = jabber_chat_leave; // ret->chat_open = jabber_chat_open; ret->keepalive = jabber_keepalive; - ret->add_permit = jabber_add_permit; - ret->rem_permit = jabber_rem_permit; - ret->add_deny = jabber_add_deny; - ret->rem_deny = jabber_rem_deny; // ret->send_typing = jabber_send_typing; ret->handle_cmp = g_strcasecmp; -- cgit v1.2.3 From 36e9f62a6e6fdb1217b3b819320ac5a94025c448 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast <wilmer@gaast.net> Date: Sat, 7 Oct 2006 19:46:28 +0200 Subject: Added SRV lookups to automatically find out the correct server for a domain. --- protocols/jabber/jabber.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 706d31c3..2c0f7945 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -58,6 +58,8 @@ static void jabber_login( account_t *acc ) { struct gaim_connection *gc = new_gaim_conn( acc ); struct jabber_data *jd = g_new0( struct jabber_data, 1 ); + struct ns_srv_reply *srv = NULL; + char *connect_to; jd->gc = gc; gc->proto_data = jd; @@ -78,15 +80,29 @@ static void jabber_login( account_t *acc ) jd->node_cache = xt_new_node( "cache", NULL, NULL ); + /* Figure out the hostname to connect to. */ + if( 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; + + /* 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( acc->server ? acc->server : jd->server, set_getint( &acc->set, "port" ), jabber_connected_ssl, gc ); + jd->ssl = ssl_connect( connect_to, set_getint( &acc->set, "port" ), jabber_connected_ssl, gc ); jd->fd = ssl_getfd( jd->ssl ); } else { - jd->fd = proxy_connect( acc->server ? acc->server : jd->server, set_getint( &acc->set, "port" ), jabber_connected_plain, gc ); + jd->fd = proxy_connect( connect_to, srv ? srv->port : set_getint( &acc->set, "port" ), jabber_connected_plain, gc ); } + + g_free( srv ); } static void jabber_close( struct gaim_connection *gc ) -- cgit v1.2.3 From 038d17f834219505cbbdae469b2b150117467dd0 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast <wilmer@gaast.net> Date: Sun, 8 Oct 2006 18:11:16 +0200 Subject: Implemented a better node cache using a GLib hash, and preparing to add event handlers that can be set when sending a packet to handle the reply to this specific packet. This should allow me to make the iq handler a lot cleaner. --- protocols/jabber/jabber.c | 63 ++++++++++++++--------------------------------- 1 file changed, 19 insertions(+), 44 deletions(-) (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 2c0f7945..32d1d99d 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -78,7 +78,7 @@ static void jabber_login( account_t *acc ) *jd->server = 0; jd->server ++; - jd->node_cache = xt_new_node( "cache", NULL, NULL ); + jd->node_cache = g_hash_table_new_full( g_str_hash, g_str_equal, NULL, jabber_cache_entry_free ); /* Figure out the hostname to connect to. */ if( acc->server ) @@ -124,7 +124,8 @@ static void jabber_close( struct gaim_connection *gc ) if( jd->tx_len ) g_free( jd->txq ); - xt_free_node( jd->node_cache ); + g_hash_table_destroy( jd->node_cache ); + xt_free( jd->xt ); g_free( jd->away_message ); @@ -165,6 +166,18 @@ static GList *jabber_away_states( struct gaim_connection *gc ) return l; } +static void jabber_get_info( struct gaim_connection *gc, char *who ) +{ + struct xt_node *node; + + node = xt_new_node( "query", NULL, NULL ); + xt_add_attr( node, "xmlns", "http://jabber.org/protocol/disco#info" ); + node = jabber_make_packet( "iq", "get", who, node ); + jabber_cache_add( gc, node ); + + jabber_write_packet( gc, node ); +} + static void jabber_set_away( struct gaim_connection *gc, char *state_txt, char *message ) { struct jabber_data *jd = gc->proto_data; @@ -193,50 +206,12 @@ static void jabber_remove_buddy( struct gaim_connection *gc, char *who, char *gr static void jabber_keepalive( struct gaim_connection *gc ) { - struct jabber_data *jd = gc->proto_data; - struct xt_node *c, *tmp; - /* Just any whitespace character is enough as a keepalive for XMPP sessions. */ jabber_write( gc, "\n", 1 ); - /* Let's abuse this keepalive for garbage collection of the node cache too. - It runs every minute, so let's mark every node with a special flag the - first time we see it, and clean it up the second time (clean up all - packets with the flag set). - - node->flags is normally only used by xmltree itself for parsing/handling, - so it should be safe to use the variable for gc. */ - - /* This horrible loop is explained in xmltree.c. Makes me wonder if maybe I - didn't choose the perfect data structure... */ - for( c = jd->node_cache->children; c; c = c->next ) - if( !( c->flags & XT_SEEN ) ) - break; - - /* Now c points at the first unflagged node (or at NULL). Clean up - everything until that point. */ - while( jd->node_cache->children != c ) - { - /* - printf( "Cleaning up:\n" ); - xt_print( jd->node_cache->children ); - */ - - tmp = jd->node_cache->children->next; - xt_free_node( jd->node_cache->children ); - jd->node_cache->children = tmp; - } - - /* Now flag the ones that were still unflagged. */ - for( c = jd->node_cache->children; c; c = c->next ) - { - /* - printf( "Flagged:\n" ); - xt_print( c ); - */ - - c->flags |= XT_SEEN; - } + /* This runs the garbage collection every minute, which means every packet + is in the cache for about a minute (which should be enough AFAIK). */ + jabber_cache_clean( gc ); } void jabber_init() @@ -252,7 +227,7 @@ void jabber_init() // ret->get_status_string = jabber_get_status_string; ret->set_away = jabber_set_away; // ret->set_info = jabber_set_info; -// ret->get_info = jabber_get_info; + ret->get_info = jabber_get_info; ret->add_buddy = jabber_add_buddy; ret->remove_buddy = jabber_remove_buddy; // ret->chat_send = jabber_chat_send; -- cgit v1.2.3 From 861c199fb60fecf5dab96e0ed9d4b0cf0c57822f Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast <wilmer@gaast.net> Date: Sun, 8 Oct 2006 20:41:11 +0200 Subject: Moved handling of all IQ packets to event handlers. Cleaned up a LOT of mess in iq.c! --- protocols/jabber/jabber.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 32d1d99d..b508cb45 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -173,7 +173,7 @@ static void jabber_get_info( struct gaim_connection *gc, char *who ) node = xt_new_node( "query", NULL, NULL ); xt_add_attr( node, "xmlns", "http://jabber.org/protocol/disco#info" ); node = jabber_make_packet( "iq", "get", who, node ); - jabber_cache_add( gc, node ); + // jabber_cache_add( gc, node, ); jabber_write_packet( gc, node ); } -- cgit v1.2.3 From 6a1128d1333cf79f1ef9fb1f55b1b8fec67caf2a Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast <wilmer@gaast.net> Date: Mon, 9 Oct 2006 20:19:05 +0200 Subject: The module now keeps track of all resources available for a buddy. This means the buddy won't show up offline when one resource goes down (while there are still others available). It also remembers away state information for every separate resource. Later this system will be used to keep track of client capability information (Typing notices, yay...) and who knows what else. --- protocols/jabber/jabber.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index b508cb45..266022ba 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -79,6 +79,7 @@ static void jabber_login( account_t *acc ) jd->server ++; 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 ) @@ -168,10 +169,23 @@ static GList *jabber_away_states( struct gaim_connection *gc ) static void jabber_get_info( struct gaim_connection *gc, char *who ) { + struct jabber_buddy *bud; struct xt_node *node; + bud = jabber_buddy_by_jid( gc, who ); + while( bud ) + { + serv_got_crap( gc, "Buddy %s/%s (%d) information:\nAway state: %s\nAway message: %s", + bud->handle, bud->resource, bud->priority, + bud->away_state ? bud->away_state->full_name : "(none)", + bud->away_message ? : "(none)" ); + bud = bud->next; + } + +// node = xt_new_node( "vCard", NULL, NULL ); +// xt_add_attr( node, "xmlns", "vcard-temp" ); node = xt_new_node( "query", NULL, NULL ); - xt_add_attr( node, "xmlns", "http://jabber.org/protocol/disco#info" ); + xt_add_attr( node, "xmlns", "jabber:iq:version" ); node = jabber_make_packet( "iq", "get", who, node ); // jabber_cache_add( gc, node, ); -- cgit v1.2.3 From a21a8ac4fbd5a234bc8d31d9d487c74a81383c8a Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast <wilmer@gaast.net> Date: Tue, 10 Oct 2006 14:05:42 +0200 Subject: Added resource selection (based on priority or time of last message) to budd_by_jid(), added a full_jid property to easily address that resource without having to rebuild the full JID every time and implemented typing notification shite. --- protocols/jabber/jabber.c | 72 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 63 insertions(+), 9 deletions(-) (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 266022ba..91f88350 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -44,6 +44,8 @@ static void jabber_acc_init( account_t *acc ) s = set_add( &acc->set, "resource", "BitlBee", NULL, acc ); s->flags |= ACC_SET_OFFLINE_ONLY; + s = set_add( &acc->set, "resource_select", "priority", NULL, acc ); + s = set_add( &acc->set, "server", NULL, set_eval_account, acc ); s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY; @@ -136,19 +138,33 @@ static void jabber_close( struct gaim_connection *gc ) static int jabber_send_im( struct gaim_connection *gc, char *who, char *message, int len, int away ) { + struct jabber_data *jd = gc->proto_data; + struct jabber_buddy *bud; struct xt_node *node; int st; - /* - event = xt_new_node( "active", NULL, NULL ); - xt_add_attr( event, "xlmns", "http://jabber.org/protocol/chatstates" ); - - event = xt_new_node( "x", NULL, xt_new_node( "composing", NULL, NULL ) ); - xt_add_attr( event, "xmlns", "jabber:x:event" ); - */ + bud = jabber_buddy_by_jid( gc, who ); node = xt_new_node( "body", message, NULL ); - node = jabber_make_packet( "message", "chat", who, node ); + node = jabber_make_packet( "message", "chat", bud->full_jid, node ); + + if( ( jd->flags & JFLAG_WANT_TYPING ) && + ( ( bud->flags & JBFLAG_DOES_JEP85 ) || + !( bud->flags & JBFLAG_PROBED_JEP85 ) ) ) + { + 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 JEP85, + include a probe in this packet now. */ + act = xt_new_node( "active", NULL, NULL ); + xt_add_attr( act, "xmlns", "http://jabber.org/protocol/chatstates" ); + xt_add_child( node, act ); + + /* Just make sure we do this only once. */ + bud->flags |= JBFLAG_PROBED_JEP85; + } + st = jabber_write_packet( gc, node ); xt_free_node( node ); @@ -228,6 +244,44 @@ static void jabber_keepalive( struct gaim_connection *gc ) jabber_cache_clean( gc ); } +static int jabber_send_typing( struct gaim_connection *gc, char *who, int typing ) +{ + struct jabber_data *jd = gc->proto_data; + struct jabber_buddy *bud; + + /* Enable typing notification related code from now. */ + jd->flags |= JFLAG_WANT_TYPING; + + bud = jabber_buddy_by_jid( gc, who ); + if( bud->flags & JBFLAG_DOES_JEP85 ) + { + /* We're only allowed to send this stuff if we know the other + side supports it. */ + + struct xt_node *node; + char *type; + int st; + + if( typing == 0 ) + type = "active"; + else if( typing == 2 ) + type = "paused"; + else /* if( typing == 1 ) */ + type = "composing"; + + node = xt_new_node( type, NULL, NULL ); + xt_add_attr( node, "xmlns", "http://jabber.org/protocol/chatstates" ); + node = jabber_make_packet( "message", "chat", bud->full_jid, node ); + + st = jabber_write_packet( gc, node ); + xt_free_node( node ); + + return st; + } + + return 1; +} + void jabber_init() { struct prpl *ret = g_new0( struct prpl, 1 ); @@ -249,7 +303,7 @@ void jabber_init() // ret->chat_leave = jabber_chat_leave; // ret->chat_open = jabber_chat_open; ret->keepalive = jabber_keepalive; -// ret->send_typing = jabber_send_typing; + ret->send_typing = jabber_send_typing; ret->handle_cmp = g_strcasecmp; register_protocol( ret ); -- cgit v1.2.3 From 7e83adca0e875710627588bf28ddb60fb61bd43b Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast <wilmer@gaast.net> Date: Fri, 13 Oct 2006 00:14:00 +0200 Subject: Fixed get_info(), now that buddy_by_jid() doesn't just return the first resource in the list anymore. --- protocols/jabber/jabber.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 91f88350..26d7bbab 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -185,10 +185,14 @@ static GList *jabber_away_states( struct gaim_connection *gc ) static void jabber_get_info( struct gaim_connection *gc, char *who ) { + struct jabber_data *jd = gc->proto_data; struct jabber_buddy *bud; - struct xt_node *node; - bud = jabber_buddy_by_jid( gc, who ); + if( strchr( who, '/' ) ) + bud = jabber_buddy_by_jid( gc, who ); + else + bud = g_hash_table_lookup( jd->buddies, who ); + while( bud ) { serv_got_crap( gc, "Buddy %s/%s (%d) information:\nAway state: %s\nAway message: %s", @@ -197,15 +201,6 @@ static void jabber_get_info( struct gaim_connection *gc, char *who ) bud->away_message ? : "(none)" ); bud = bud->next; } - -// node = xt_new_node( "vCard", NULL, NULL ); -// xt_add_attr( node, "xmlns", "vcard-temp" ); - node = xt_new_node( "query", NULL, NULL ); - xt_add_attr( node, "xmlns", "jabber:iq:version" ); - node = jabber_make_packet( "iq", "get", who, node ); - // jabber_cache_add( gc, node, ); - - jabber_write_packet( gc, node ); } static void jabber_set_away( struct gaim_connection *gc, char *state_txt, char *message ) -- cgit v1.2.3 From 788a1afa9628aeaf9d69fc53f49131a4330253cf Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast <wilmer@gaast.net> Date: Sun, 15 Oct 2006 22:24:01 +0200 Subject: Proper cleanup of jabber buddy structures when removing a buddy from the list, proper checking (and handling) of events related to buddies that aren't "hashed" yet, limit checks on priorityto setting, renamed JEP85 to XEP85, support for more XEP85 states. --- protocols/jabber/jabber.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 26d7bbab..abc3837b 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -146,23 +146,23 @@ static int jabber_send_im( struct gaim_connection *gc, char *who, char *message, bud = jabber_buddy_by_jid( gc, who ); node = xt_new_node( "body", message, NULL ); - node = jabber_make_packet( "message", "chat", bud->full_jid, node ); + node = jabber_make_packet( "message", "chat", bud ? bud->full_jid : who, node ); - if( ( jd->flags & JFLAG_WANT_TYPING ) && - ( ( bud->flags & JBFLAG_DOES_JEP85 ) || - !( bud->flags & JBFLAG_PROBED_JEP85 ) ) ) + if( ( jd->flags & JFLAG_WANT_TYPING ) && bud && + ( ( 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 JEP85, + (and didn't probe before) if this resource supports XEP85, include a probe in this packet now. */ act = xt_new_node( "active", NULL, NULL ); xt_add_attr( act, "xmlns", "http://jabber.org/protocol/chatstates" ); xt_add_child( node, act ); /* Just make sure we do this only once. */ - bud->flags |= JBFLAG_PROBED_JEP85; + bud->flags |= JBFLAG_PROBED_XEP85; } st = jabber_write_packet( gc, node ); @@ -225,6 +225,9 @@ static void jabber_add_buddy( struct gaim_connection *gc, char *who ) static void jabber_remove_buddy( struct gaim_connection *gc, char *who, char *group ) { + /* We should always do this part. Clean up our administration a little bit. */ + jabber_buddy_remove_bare( gc, who ); + if( jabber_remove_from_roster( gc, who ) ) presence_send_request( gc, who, "unsubscribe" ); } @@ -247,8 +250,14 @@ static int jabber_send_typing( struct gaim_connection *gc, char *who, int typing /* Enable typing notification related code from now. */ jd->flags |= JFLAG_WANT_TYPING; - bud = jabber_buddy_by_jid( gc, who ); - if( bud->flags & JBFLAG_DOES_JEP85 ) + if( ( bud = jabber_buddy_by_jid( gc, who ) ) == NULL ) + { + /* Sending typing notifications to unknown buddies is + unsupported for now. Shouldn't be a problem, I think. */ + return 0; + } + + if( bud->flags & JBFLAG_DOES_XEP85 ) { /* We're only allowed to send this stuff if we know the other side supports it. */ -- cgit v1.2.3 From 1991be623c6c53d2f61f0b15405d41d144c21c8f Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast <wilmer@gaast.net> Date: Wed, 18 Oct 2006 19:47:08 +0200 Subject: get_info() now displays vCard information too. --- protocols/jabber/jabber.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index abc3837b..f460aff2 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -201,6 +201,8 @@ static void jabber_get_info( struct gaim_connection *gc, char *who ) bud->away_message ? : "(none)" ); bud = bud->next; } + + jabber_get_vcard( gc, bud ? bud->handle : who ); } static void jabber_set_away( struct gaim_connection *gc, char *state_txt, char *message ) -- cgit v1.2.3 From 3b3cd693845539938baf5e26c80234f03ebf870c Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast <wilmer@gaast.net> Date: Fri, 20 Oct 2006 21:58:09 +0200 Subject: Added backwards compatibility with the old "account add" syntax for Jabber accounts. Very ugly code, so it won't stay long. ;-) Plus checking of the ssl_connect() return value, because of course it can return NULL too... Have to add general *_connect() error checking to jabber_login() soon! --- protocols/jabber/jabber.c | 72 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 3 deletions(-) (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index f460aff2..3a2cb246 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -61,7 +61,7 @@ static void jabber_login( account_t *acc ) struct gaim_connection *gc = new_gaim_conn( acc ); struct jabber_data *jd = g_new0( struct jabber_data, 1 ); struct ns_srv_reply *srv = NULL; - char *connect_to; + char *connect_to, *s; jd->gc = gc; gc->proto_data = jd; @@ -80,11 +80,77 @@ static void jabber_login( account_t *acc ) *jd->server = 0; jd->server ++; + if( ( s = strchr( jd->server, '/' ) ) ) + { + *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; + } + + /* This code isn't really pretty. Backwards compatibility never is... */ + s = acc->server; + while( s ) + { + static int had_port = 0; + + 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 ) ) + { + int i; + + /* The first character is a digit. It could be an + IP address though. Only accept this as a port# + if there are only digits. */ + for( i = 0; isdigit( s[i] ); i ++ ); + + /* If the first non-digit character is a colon or + the end of the string, save the port number + where it should be. */ + if( s[i] == ':' || s[i] == 0 ) + { + sscanf( s, "%d", &i ); + set_setint( &acc->set, "port", i ); + + /* See above. */ + *s = 0; + s ++; + } + + had_port = 1; + } + + s = strchr( s, ':' ); + if( s ) + { + *s = 0; + s ++; + } + } + 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 ) + 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 ) ) ) @@ -98,7 +164,7 @@ static void jabber_login( account_t *acc ) if( set_getbool( &acc->set, "ssl" ) ) { jd->ssl = ssl_connect( connect_to, set_getint( &acc->set, "port" ), jabber_connected_ssl, gc ); - jd->fd = ssl_getfd( jd->ssl ); + jd->fd = jd->ssl ? ssl_getfd( jd->ssl ) : -1; } else { -- cgit v1.2.3 From 35f6677c07770f0323872e4edddefb7b752e50bd Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast <wilmer@gaast.net> Date: Sat, 21 Oct 2006 22:48:44 +0200 Subject: Proper detections of errors from *_connect() and added a "Connecting" message in jabber_login(). --- protocols/jabber/jabber.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 3a2cb246..fd8b6128 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -158,6 +158,8 @@ static void jabber_login( account_t *acc ) else connect_to = jd->server; + set_login_progress( gc, "Connecting" ); + /* For non-SSL connections we can try to use the port # from the SRV reply, but let's not do that when using SSL, SSL usually runs on non-standard ports... */ @@ -170,8 +172,13 @@ static void jabber_login( account_t *acc ) { jd->fd = proxy_connect( connect_to, srv ? srv->port : set_getint( &acc->set, "port" ), jabber_connected_plain, gc ); } - g_free( srv ); + + if( jd->fd == -1 ) + { + hide_login_progress( gc, "Could not connect to server" ); + signoff( gc ); + } } static void jabber_close( struct gaim_connection *gc ) -- cgit v1.2.3 From 4b0d8055fe3fc08cdaa7696f1c4af1e0e471a67e Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast <wilmer@gaast.net> Date: Sat, 21 Oct 2006 23:12:30 +0200 Subject: Can't hurt to at least try one compile before running bzr commit... --- protocols/jabber/jabber.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index fd8b6128..e4bdc463 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -158,7 +158,7 @@ static void jabber_login( account_t *acc ) else connect_to = jd->server; - set_login_progress( gc, "Connecting" ); + set_login_progress( gc, 0, "Connecting" ); /* For non-SSL connections we can try to use the port # from the SRV reply, but let's not do that when using SSL, SSL usually runs on -- cgit v1.2.3 From abbd8ede1eb5eeb9b82e09357e0b38949bc95b8d Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast <wilmer@gaast.net> Date: Sat, 28 Oct 2006 22:54:40 +0200 Subject: Added handling of roster pushes. This means your local buddy list will stay synchronized with other clients logged into your account at the same time. --- protocols/jabber/jabber.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index e4bdc463..855a6a3b 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -229,7 +229,10 @@ static int jabber_send_im( struct gaim_connection *gc, char *who, char *message, /* 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. */ + 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", "http://jabber.org/protocol/chatstates" ); xt_add_child( node, act ); -- cgit v1.2.3 From 47d3ac46306965e9db66096eef8c60c8e7985950 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast <wilmer@gaast.net> Date: Tue, 31 Oct 2006 09:25:41 +0100 Subject: Added #defines for XML namespaces. --- protocols/jabber/jabber.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 855a6a3b..2ef76444 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -234,7 +234,7 @@ static int jabber_send_im( struct gaim_connection *gc, char *who, char *message, 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", "http://jabber.org/protocol/chatstates" ); + xt_add_attr( act, "xmlns", XMLNS_CHATSTATES ); xt_add_child( node, act ); /* Just make sure we do this only once. */ @@ -352,7 +352,7 @@ static int jabber_send_typing( struct gaim_connection *gc, char *who, int typing type = "composing"; node = xt_new_node( type, NULL, NULL ); - xt_add_attr( node, "xmlns", "http://jabber.org/protocol/chatstates" ); + xt_add_attr( node, "xmlns", XMLNS_CHATSTATES ); node = jabber_make_packet( "message", "chat", bud->full_jid, node ); st = jabber_write_packet( gc, node ); -- cgit v1.2.3 From 0d3f30f5449cf1730c006314f3dd60843e911ad1 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast <wilmer@gaast.net> Date: Mon, 13 Nov 2006 00:06:08 +0100 Subject: Improved handling of JIDs: Bare JIDs are allowed (*sigh*) and case insensitivity. Probably not complete yet... --- protocols/jabber/jabber.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'protocols/jabber/jabber.c') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 2ef76444..a60cd4aa 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -216,12 +216,12 @@ static int jabber_send_im( struct gaim_connection *gc, char *who, char *message, struct xt_node *node; int st; - bud = jabber_buddy_by_jid( gc, who ); + bud = jabber_buddy_by_jid( gc, who, 0 ); node = xt_new_node( "body", message, NULL ); node = jabber_make_packet( "message", "chat", bud ? bud->full_jid : who, node ); - if( ( jd->flags & JFLAG_WANT_TYPING ) && bud && + if( bud && ( jd->flags & JFLAG_WANT_TYPING ) && ( ( bud->flags & JBFLAG_DOES_XEP85 ) || !( bud->flags & JBFLAG_PROBED_XEP85 ) ) ) { @@ -265,20 +265,24 @@ static void jabber_get_info( struct gaim_connection *gc, char *who ) struct jabber_buddy *bud; if( strchr( who, '/' ) ) - bud = jabber_buddy_by_jid( gc, who ); + bud = jabber_buddy_by_jid( gc, who, 0 ); else - bud = g_hash_table_lookup( jd->buddies, who ); + { + char *s = jabber_normalize( who ); + bud = g_hash_table_lookup( jd->buddies, s ); + g_free( s ); + } while( bud ) { - serv_got_crap( gc, "Buddy %s/%s (%d) information:\nAway state: %s\nAway message: %s", - bud->handle, bud->resource, bud->priority, + serv_got_crap( gc, "Buddy %s (%d) information:\nAway state: %s\nAway message: %s", + bud->full_jid, bud->priority, bud->away_state ? bud->away_state->full_name : "(none)", bud->away_message ? : "(none)" ); bud = bud->next; } - jabber_get_vcard( gc, bud ? bud->handle : who ); + jabber_get_vcard( gc, bud ? bud->full_jid : who ); } static void jabber_set_away( struct gaim_connection *gc, char *state_txt, char *message ) @@ -328,7 +332,7 @@ static int jabber_send_typing( struct gaim_connection *gc, char *who, int typing /* Enable typing notification related code from now. */ jd->flags |= JFLAG_WANT_TYPING; - if( ( bud = jabber_buddy_by_jid( gc, who ) ) == NULL ) + if( ( bud = jabber_buddy_by_jid( gc, who, 0 ) ) == NULL ) { /* Sending typing notifications to unknown buddies is unsupported for now. Shouldn't be a problem, I think. */ -- cgit v1.2.3