From e35d1a121d5fb2da3698fbe4a365fe38d0097665 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 22 Apr 2007 13:44:27 -0700 Subject: Read-only support for Jabber conferences (non-anonymous rooms only). Just don't use this, you're really not going to like it. :-) --- protocols/jabber/Makefile | 2 +- protocols/jabber/conference.c | 193 +++++++++++++++++++++++++++++++++++++++++ protocols/jabber/jabber.c | 22 ++++- protocols/jabber/jabber.h | 26 +++++- protocols/jabber/jabber_util.c | 35 +++++++- protocols/jabber/message.c | 13 ++- protocols/jabber/presence.c | 29 ++++++- protocols/jabber/xmltree.c | 2 + protocols/msn/sb.c | 2 +- protocols/nogaim.c | 21 +++-- protocols/nogaim.h | 6 +- protocols/oscar/oscar.c | 2 +- protocols/yahoo/yahoo.c | 14 +-- 13 files changed, 329 insertions(+), 38 deletions(-) create mode 100644 protocols/jabber/conference.c (limited to 'protocols') diff --git a/protocols/jabber/Makefile b/protocols/jabber/Makefile index 3c9e4949..1d5368b1 100644 --- a/protocols/jabber/Makefile +++ b/protocols/jabber/Makefile @@ -9,7 +9,7 @@ -include ../../Makefile.settings # [SH] Program variables -objects = io.o iq.o jabber.o jabber_util.o message.o presence.o sasl.o xmltree.o +objects = conference.o io.o iq.o jabber.o jabber_util.o message.o presence.o sasl.o xmltree.o CFLAGS += -Wall LFLAGS += -r diff --git a/protocols/jabber/conference.c b/protocols/jabber/conference.c new file mode 100644 index 00000000..ffc4f844 --- /dev/null +++ b/protocols/jabber/conference.c @@ -0,0 +1,193 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Jabber module - Conference rooms * +* * +* Copyright 2007 Wilmer van der Gaast * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License along * +* with this program; if not, write to the Free Software Foundation, Inc., * +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * +* * +\***************************************************************************/ + +#include "jabber.h" + +struct groupchat *jabber_chat_join( struct im_connection *ic, char *room, char *nick, char *password ) +{ + struct jabber_chat *jc; + struct xt_node *node; + struct groupchat *c; + char *roomjid; + + roomjid = g_strdup_printf( "%s/%s", room, nick ); + node = xt_new_node( "x", NULL, NULL ); + xt_add_attr( node, "xmlns", XMLNS_MUC ); + node = jabber_make_packet( "presence", NULL, roomjid, node ); + + if( !jabber_write_packet( ic, node ) ) + { + g_free( roomjid ); + xt_free_node( node ); + return NULL; + } + xt_free_node( node ); + + jc = g_new0( struct jabber_chat, 1 ); + jc->name = jabber_normalize( room ); + + if( ( jc->me = jabber_buddy_add( ic, roomjid ) ) == NULL ) + { + g_free( roomjid ); + g_free( jc->name ); + g_free( jc ); + return NULL; + } + g_free( roomjid ); + + c = imcb_chat_new( ic, room ); + c->data = jc; + + return c; +} + +int jabber_chat_leave( struct groupchat *c, const char *reason ) +{ + struct im_connection *ic = c->ic; + struct jabber_chat *jc = c->data; + struct xt_node *node; + + node = xt_new_node( "x", NULL, NULL ); + xt_add_attr( node, "xmlns", XMLNS_MUC ); + node = jabber_make_packet( "presence", "unavailable", jc->me->full_jid, node ); + + if( !jabber_write_packet( ic, node ) ) + { + xt_free_node( node ); + return 0; + } + xt_free_node( node ); + + /* Remove all participants from jc->buddies and clean up our data. */ + jabber_buddy_remove_bare( ic, jc->name ); + g_free( jc->name ); + g_free( jc ); + + /* And the generic stuff. */ + imcb_chat_free( c ); + + return 1; +} + +/* Not really the same syntax as the normal pkt_ functions, but this isn't + called by the xmltree parser exactly and this way I can add some extra + parameters so we won't have to repeat too many things done by the caller + already. */ +void jabber_chat_pkt_presence( struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node ) +{ + struct groupchat *chat; + struct xt_node *c; + char *type = xt_find_attr( node, "type" ); + struct jabber_chat *jc; + char *s; + + if( ( chat = jabber_chat_by_name( ic, bud->bare_jid ) ) == NULL ) + { + /* How could this happen?? We could do kill( self, 11 ) + now or just wait for the OS to do it. :-) */ + return; + } + + jc = chat->data; + + if( type == NULL && !( bud->flags & JBFLAG_IS_CHATROOM ) ) + { + bud->flags |= JBFLAG_IS_CHATROOM; + /* If this one wasn't set yet, this buddy just joined the chat. + Slightly hackish way of finding out eh? ;-) */ + + /* This is pretty messy... */ + for( c = node->children; ( c = xt_find_node( c, "x" ) ); c = c->next ) + if( ( s = xt_find_attr( c, "xmlns" ) ) && + ( strcmp( s, XMLNS_MUC_USER ) == 0 ) ) + { + c = xt_find_node( c->children, "item" ); + if( ( s = xt_find_attr( c, "jid" ) ) ) + { + /* Yay, found what we need. :-) */ + bud->orig_jid = g_strdup( s ); + break; + } + } + + /* Won't handle this for now. */ + if( bud->orig_jid == NULL ) + return; + + s = strchr( bud->orig_jid, '/' ); + if( s ) *s = 0; /* Should NEVER be NULL, but who knows... */ + imcb_chat_add_buddy( chat, bud->orig_jid ); + if( s ) *s = '/'; + } + else if( type ) /* This only gets called if type=="unavailable" */ + { + /* Won't handle this for now. */ + if( bud->orig_jid == NULL ) + return; + s = strchr( bud->orig_jid, '/' ); + if( s ) *s = 0; /* Should NEVER be NULL, but who knows... */ + imcb_chat_remove_buddy( chat, bud->orig_jid, NULL ); + if( s ) *s = '/'; + + if( bud == jc->me ) + { + g_free( jc->name ); + g_free( jc ); + imcb_chat_free( chat ); + } + } +} + +void jabber_chat_pkt_message( struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node ) +{ + struct xt_node *body = xt_find_node( node->children, "body" ); + struct groupchat *chat; + char *s; + + if( bud == NULL ) + { + s = xt_find_attr( node, "from" ); /* pkt_message() already NULL-checked this one. */ + if( strchr( s, '/' ) == NULL ) + /* This is fine, the groupchat itself isn't in jd->buddies. */ + imcb_log( ic, "System message from groupchat %s: %s", s, body? body->text : "NULL" ); + else + /* This, however, isn't fine! */ + imcb_log( ic, "Groupchat message from unknown participant %s: %s", s, body ? body->text : "NULL" ); + + return; + } + else if( ( chat = jabber_chat_by_name( ic, bud->bare_jid ) ) == NULL ) + { + /* How could this happen?? We could do kill( self, 11 ) + now or just wait for the OS to do it. :-) */ + return; + } + + if( body && body->text_len > 0 ) + { + s = strchr( bud->orig_jid, '/' ); + if( s ) *s = 0; + imcb_chat_msg( chat, bud->orig_jid, body->text, 0, 0 ); + if( s ) *s = '/'; + } +} diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index edad5dbd..f9473015 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -323,6 +323,24 @@ static void jabber_remove_buddy( struct im_connection *ic, char *who, char *grou presence_send_request( ic, who, "unsubscribe" ); } +static struct groupchat *jabber_chat_join_( struct im_connection *ic, char *room, char *nick, char *password ) +{ + if( strchr( room, '@' ) == NULL ) + imcb_error( ic, "Invalid room name: %s", room ); + else if( jabber_chat_by_name( ic, room ) ) + imcb_error( ic, "Already present in chat `%s'", room ); + else + return jabber_chat_join( ic, room, nick, password ); + + return NULL; +} + +static void jabber_chat_leave_( struct groupchat *c ) +{ + if( c ) + jabber_chat_leave( c, NULL ); +} + static void jabber_keepalive( struct im_connection *ic ) { /* Just any whitespace character is enough as a keepalive for XMPP sessions. */ @@ -395,8 +413,8 @@ void jabber_initmodule() ret->remove_buddy = jabber_remove_buddy; // ret->chat_msg = jabber_chat_msg; // ret->chat_invite = jabber_chat_invite; -// ret->chat_leave = jabber_chat_leave; -// ret->chat_open = jabber_chat_open; + ret->chat_leave = jabber_chat_leave_; + ret->chat_join = jabber_chat_join_; ret->keepalive = jabber_keepalive; ret->send_typing = jabber_send_typing; ret->handle_cmp = g_strcasecmp; diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h index 42f57ae1..dd771910 100644 --- a/protocols/jabber/jabber.h +++ b/protocols/jabber/jabber.h @@ -49,6 +49,8 @@ typedef enum sure it gets sent only once. */ JBFLAG_DOES_XEP85 = 2, /* Set this when the resource seems to support XEP85 (typing notification shite). */ + JBFLAG_IS_CHATROOM = 4, /* It's convenient to use this JID thingy for + groupchat state info too. */ } jabber_buddy_flags_t; #define JABBER_PORT_DEFAULT "5222" @@ -100,6 +102,9 @@ struct jabber_buddy char *full_jid; char *resource; + /* Groupchat-only */ + char *orig_jid; + int priority; struct jabber_away_state *away_state; char *away_message; @@ -110,6 +115,13 @@ struct jabber_buddy struct jabber_buddy *next; }; +struct jabber_chat +{ + int flags; + char *name; + struct jabber_buddy *me; +}; + /* Prefixes to use for packet IDs (mainly for IQ packets ATM). Usually the first one should be used, but when storing a packet in the cache, a "special" kind of ID is assigned to make it easier later to figure out @@ -133,6 +145,8 @@ struct jabber_buddy #define XMLNS_VCARD "vcard-temp" /* XEP-0054 */ #define XMLNS_CHATSTATES "http://jabber.org/protocol/chatstates" /* 0085 */ #define XMLNS_DISCOVER "http://jabber.org/protocol/disco#info" /* 0030 */ +#define XMLNS_MUC "http://jabber.org/protocol/muc" /* XEP-0045 */ +#define XMLNS_MUC_USER "http://jabber.org/protocol/muc#user"/* XEP-0045 */ /* iq.c */ xt_status jabber_pkt_iq( struct xt_node *node, gpointer data ); @@ -163,18 +177,20 @@ void jabber_cache_clean( struct im_connection *ic ); const struct jabber_away_state *jabber_away_state_by_code( char *code ); const struct jabber_away_state *jabber_away_state_by_name( char *name ); void jabber_buddy_ask( struct im_connection *ic, char *handle ); -char *jabber_normalize( char *orig ); +char *jabber_normalize( const char *orig ); typedef enum { GET_BUDDY_CREAT = 1, /* Try to create it, if necessary. */ - GET_BUDDY_EXACT = 2, /* Get an exact message (only makes sense with bare JIDs). */ + GET_BUDDY_EXACT = 2, /* Get an exact match (only makes sense with bare JIDs). */ + GET_BUDDY_FIRST = 4, /* No selection, simply get the first resource for this JID. */ } get_buddy_flags_t; struct jabber_buddy *jabber_buddy_add( struct im_connection *ic, char *full_jid ); struct jabber_buddy *jabber_buddy_by_jid( struct im_connection *ic, char *jid, get_buddy_flags_t flags ); int jabber_buddy_remove( struct im_connection *ic, char *full_jid ); int jabber_buddy_remove_bare( struct im_connection *ic, char *bare_jid ); +struct groupchat *jabber_chat_by_name( struct im_connection *ic, const char *name ); extern const struct jabber_away_state jabber_away_state_list[]; @@ -192,4 +208,10 @@ xt_status sasl_pkt_challenge( struct xt_node *node, gpointer data ); xt_status sasl_pkt_result( struct xt_node *node, gpointer data ); gboolean sasl_supported( struct im_connection *ic ); +/* conference.c */ +struct groupchat *jabber_chat_join( struct im_connection *ic, char *room, char *nick, char *password ); +int jabber_chat_leave( struct groupchat *c, const char *reason ); +void jabber_chat_pkt_presence( struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node ); +void jabber_chat_pkt_message( struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node ); + #endif diff --git a/protocols/jabber/jabber_util.c b/protocols/jabber/jabber_util.c index 3c0e71f4..86ddf7bc 100644 --- a/protocols/jabber/jabber_util.c +++ b/protocols/jabber/jabber_util.c @@ -47,7 +47,7 @@ char *set_eval_priority( set_t *set, char *value ) convenient, they have one disadvantage: If I would just call p_s_u() now to send the new prio setting, it would send the old setting because the set->value gets changed - when the eval returns a non-NULL value. + after the (this) eval returns a non-NULL value. So now I can choose between implementing post-set functions next to evals, or just do this little hack: */ @@ -128,7 +128,7 @@ struct xt_node *jabber_make_error_packet( struct xt_node *orig, char *err_cond, /* Cache a node/packet for later use. Mainly useful for IQ packets if you need them when you receive the response. Use this BEFORE sending the packet so - it'll get a new id= tag, and do NOT free() the packet after writing it! */ + it'll get a new id= tag, and do NOT free() the packet after sending it! */ void jabber_cache_add( struct im_connection *ic, struct xt_node *node, jabber_cache_event func ) { struct jabber_data *jd = ic->proto_data; @@ -251,7 +251,7 @@ void jabber_buddy_ask( struct im_connection *ic, char *handle ) } /* Returns a new string. Don't leak it! */ -char *jabber_normalize( char *orig ) +char *jabber_normalize( const char *orig ) { int len, i; char *new; @@ -352,6 +352,8 @@ struct jabber_buddy *jabber_buddy_by_jid( struct im_connection *ic, char *jid_, if( ( s = strchr( jid, '/' ) ) ) { + int none_found = 0; + *s = 0; if( ( bud = g_hash_table_lookup( jd->buddies, jid ) ) ) { @@ -369,8 +371,16 @@ struct jabber_buddy *jabber_buddy_by_jid( struct im_connection *ic, char *jid_, break; } } + else + { + /* This hack is there to make sure that O_CREAT will + work if there's already another resouce present + for this JID, even if it's an unknown buddy. This + is done to handle conferences properly. */ + none_found = 1; + } - if( bud == NULL && ( flags & GET_BUDDY_CREAT ) && imcb_find_buddy( ic, jid ) ) + if( bud == NULL && ( flags & GET_BUDDY_CREAT ) && ( imcb_find_buddy( ic, jid ) || !none_found ) ) { *s = '/'; bud = jabber_buddy_add( ic, jid ); @@ -530,3 +540,20 @@ int jabber_buddy_remove_bare( struct im_connection *ic, char *bare_jid_ ) return 0; } } + +struct groupchat *jabber_chat_by_name( struct im_connection *ic, const char *name ) +{ + char *normalized = jabber_normalize( name ); + struct groupchat *ret; + struct jabber_chat *jc; + + for( ret = ic->groupchats; ret; ret = ret->next ) + { + jc = ret->data; + if( strcmp( normalized, jc->name ) == 0 ) + break; + } + g_free( normalized ); + + return ret; +} diff --git a/protocols/jabber/message.c b/protocols/jabber/message.c index 19edbdfd..8a4ecaf4 100644 --- a/protocols/jabber/message.c +++ b/protocols/jabber/message.c @@ -29,24 +29,29 @@ xt_status jabber_pkt_message( struct xt_node *node, gpointer data ) char *from = xt_find_attr( node, "from" ); char *type = xt_find_attr( node, "type" ); struct xt_node *body = xt_find_node( node->children, "body" ), *c; + struct jabber_buddy *bud = NULL; char *s; + if( !from ) + return XT_HANDLED; /* Consider this packet corrupted. */ + + bud = jabber_buddy_by_jid( ic, from, GET_BUDDY_EXACT ); + if( type && strcmp( type, "error" ) == 0 ) { /* Handle type=error packet. */ } - else if( type && strcmp( type, "groupchat" ) == 0 ) + else if( type && from && strcmp( type, "groupchat" ) == 0 ) { - /* TODO! */ + jabber_chat_pkt_message( ic, bud, node ); } else /* "chat", "normal", "headline", no-type or whatever. Should all be pretty similar. */ { - struct jabber_buddy *bud = NULL; GString *fullmsg = g_string_new( "" ); if( ( s = strchr( from, '/' ) ) ) { - if( ( bud = jabber_buddy_by_jid( ic, from, GET_BUDDY_EXACT ) ) ) + if( bud ) bud->last_act = time( NULL ); else *s = 0; /* We need to generate a bare JID now. */ diff --git a/protocols/jabber/presence.c b/protocols/jabber/presence.c index ef92740a..096b4fd5 100644 --- a/protocols/jabber/presence.c +++ b/protocols/jabber/presence.c @@ -30,11 +30,20 @@ xt_status jabber_pkt_presence( struct xt_node *node, gpointer data ) char *type = xt_find_attr( node, "type" ); /* NULL should mean the person is online. */ struct xt_node *c; struct jabber_buddy *bud; + int is_chat = 0; char *s; if( !from ) return XT_HANDLED; + if( ( s = strchr( from, '/' ) ) ) + { + *s = 0; + if( jabber_chat_by_name( ic, from ) ) + is_chat = 1; + *s = '/'; + } + if( type == NULL ) { int is_away = 0; @@ -71,23 +80,35 @@ xt_status jabber_pkt_presence( struct xt_node *node, gpointer data ) else bud->priority = 0; - if( bud == jabber_buddy_by_jid( ic, bud->bare_jid, 0 ) ) + if( is_chat ) + jabber_chat_pkt_presence( ic, bud, node ); + else if( bud == jabber_buddy_by_jid( ic, bud->bare_jid, 0 ) ) imcb_buddy_status( ic, bud->bare_jid, OPT_LOGGED_IN | is_away, ( is_away && bud->away_state ) ? bud->away_state->full_name : NULL, bud->away_message ); } else if( strcmp( type, "unavailable" ) == 0 ) { - if( jabber_buddy_by_jid( ic, from, GET_BUDDY_EXACT ) == NULL ) + if( ( bud = jabber_buddy_by_jid( ic, from, GET_BUDDY_EXACT ) ) == NULL ) { if( set_getbool( &ic->irc->set, "debug" ) ) imcb_log( ic, "WARNING: Received presence information from unknown JID: %s", from ); return XT_HANDLED; } + /* Handle this before we delete the JID. */ + if( is_chat ) + { + jabber_chat_pkt_presence( ic, bud, node ); + } + jabber_buddy_remove( ic, from ); - if( ( s = strchr( from, '/' ) ) ) + if( is_chat ) + { + /* Nothing else to do for now? */ + } + else if( ( s = strchr( from, '/' ) ) ) { *s = 0; @@ -95,6 +116,8 @@ xt_status jabber_pkt_presence( struct xt_node *node, gpointer data ) available anymore. */ if( jabber_buddy_by_jid( ic, from, 0 ) == NULL ) imcb_buddy_status( ic, from, 0, NULL, NULL ); + /* FIXME: If this resource was not away and another resource is, + we should definitely send an update here. */ *s = '/'; } diff --git a/protocols/jabber/xmltree.c b/protocols/jabber/xmltree.c index 7a165a1e..c8bef362 100644 --- a/protocols/jabber/xmltree.c +++ b/protocols/jabber/xmltree.c @@ -187,6 +187,8 @@ int xt_handle( struct xt_parser *xt, struct xt_node *node, int depth ) /* If there's no parent, the handler should mention as a parent. */ g_strcasecmp( xt->handlers[i].parent, "" ) == 0 ) ) ) { + xt_print( node ); + st = xt->handlers[i].func( node, xt->data ); if( st == XT_ABORT ) diff --git a/protocols/msn/sb.c b/protocols/msn/sb.c index 1693cb95..cb9e2cab 100644 --- a/protocols/msn/sb.c +++ b/protocols/msn/sb.c @@ -231,7 +231,7 @@ void msn_sb_destroy( struct msn_switchboard *sb ) if( sb->chat ) { - imcb_chat_removed( sb->chat ); + imcb_chat_free( sb->chat ); } if( sb->handler ) diff --git a/protocols/nogaim.c b/protocols/nogaim.c index a70d6eca..f3dbb0b8 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -553,8 +553,8 @@ void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, irc_kill( ic->irc, u ); u->online = 0; - /* Remove him/her from the conversations to prevent PART messages after he/she QUIT already */ - for( c = ic->conversations; c; c = c->next ) + /* Remove him/her from the groupchats to prevent PART messages after he/she QUIT already */ + for( c = ic->groupchats; c; c = c->next ) remove_chat_buddy_silent( c, (char*) handle ); } @@ -684,10 +684,10 @@ void imcb_buddy_typing( struct im_connection *ic, char *handle, u_int32_t flags } } -void imcb_chat_removed( struct groupchat *c ) +void imcb_chat_free( struct groupchat *c ) { struct im_connection *ic = c->ic; - struct groupchat *l = NULL; + struct groupchat *l; GList *ir; if( set_getbool( &ic->irc->set, "debug" ) ) @@ -707,10 +707,13 @@ void imcb_chat_removed( struct groupchat *c ) /* irc_part( ic->irc, u, c->channel ); */ } + /* Find the previous chat in the linked list. */ + for( l = ic->groupchats; l && l->next != c; l = l->next ); + if( l ) l->next = c->next; else - ic->conversations = c->next; + ic->groupchats = c->next; for( ir = c->in_room; ir; ir = ir->next ) g_free( ir->data ); @@ -748,13 +751,13 @@ struct groupchat *imcb_chat_new( struct im_connection *ic, char *handle ) /* This one just creates the conversation structure, user won't see anything yet */ - if( ic->conversations ) + if( ic->groupchats ) { - for( c = ic->conversations; c->next; c = c->next ); + for( c = ic->groupchats; c->next; c = c->next ); c = c->next = g_new0( struct groupchat, 1 ); } else - ic->conversations = c = g_new0( struct groupchat, 1 ); + ic->groupchats = c = g_new0( struct groupchat, 1 ); c->ic = ic; c->title = g_strdup( handle ); @@ -862,7 +865,7 @@ struct groupchat *chat_by_channel( char *channel ) for( l = connections; l; l = l->next ) { ic = l->data; - for( c = ic->conversations; c && g_strcasecmp( c->channel, channel ) != 0; c = c->next ); + for( c = ic->groupchats; c && g_strcasecmp( c->channel, channel ) != 0; c = c->next ); if( c ) return c; } diff --git a/protocols/nogaim.h b/protocols/nogaim.h index 59f9e870..b26cf73e 100644 --- a/protocols/nogaim.h +++ b/protocols/nogaim.h @@ -90,17 +90,15 @@ struct im_connection /* BitlBee */ irc_t *irc; - struct groupchat *conversations; + struct groupchat *groupchats; }; struct groupchat { struct im_connection *ic; - /* stuff used just for chat */ GList *in_room; GList *ignored; - /* BitlBee */ struct groupchat *next; char *channel; char *title; @@ -207,7 +205,7 @@ G_MODULE_EXPORT struct groupchat *imcb_chat_new( struct im_connection *ic, char G_MODULE_EXPORT void imcb_chat_add_buddy( struct groupchat *b, char *handle ); G_MODULE_EXPORT void imcb_chat_remove_buddy( struct groupchat *b, char *handle, char *reason ); G_MODULE_EXPORT void imcb_chat_msg( struct groupchat *c, char *who, char *msg, u_int32_t flags, time_t sent_at ); -G_MODULE_EXPORT void imcb_chat_removed( struct groupchat *c ); +G_MODULE_EXPORT void imcb_chat_free( struct groupchat *c ); struct groupchat *chat_by_channel( char *channel ); /* Actions, or whatever. */ diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c index 0c175df6..b72c683a 100644 --- a/protocols/oscar/oscar.c +++ b/protocols/oscar/oscar.c @@ -2512,7 +2512,7 @@ void oscar_chat_kill(struct im_connection *ic, struct chat_connection *cc) struct oscar_data *od = (struct oscar_data *)ic->proto_data; /* Notify the conversation window that we've left the chat */ - imcb_chat_removed(cc->cnv); + imcb_chat_free(cc->cnv); /* Destroy the chat_connection */ od->oscar_chats = g_slist_remove(od->oscar_chats, cc); diff --git a/protocols/yahoo/yahoo.c b/protocols/yahoo/yahoo.c index 69fc29bb..28a72877 100644 --- a/protocols/yahoo/yahoo.c +++ b/protocols/yahoo/yahoo.c @@ -144,8 +144,8 @@ static void byahoo_logout( struct im_connection *ic ) struct byahoo_data *yd = (struct byahoo_data *) ic->proto_data; GSList *l; - while( ic->conversations ) - imcb_chat_removed( ic->conversations ); + while( ic->groupchats ) + imcb_chat_free( ic->groupchats ); for( l = yd->buddygroups; l; l = l->next ) { @@ -317,7 +317,7 @@ static void byahoo_chat_leave( struct groupchat *c ) struct byahoo_data *yd = (struct byahoo_data *) c->ic->proto_data; yahoo_conference_logoff( yd->y2_id, NULL, c->data, c->title ); - imcb_chat_removed( c ); + imcb_chat_free( c ); } static struct groupchat *byahoo_chat_with( struct im_connection *ic, char *who ) @@ -797,7 +797,7 @@ static void byahoo_accept_conf( gpointer w, struct byahoo_conf_invitation *inv ) static void byahoo_reject_conf( gpointer w, struct byahoo_conf_invitation *inv ) { yahoo_conference_decline( inv->yid, NULL, inv->members, inv->name, "User rejected groupchat" ); - imcb_chat_removed( inv->c ); + imcb_chat_free( inv->c ); g_free( inv->name ); g_free( inv ); } @@ -840,7 +840,7 @@ void ext_yahoo_conf_userjoin( int id, const char *ignored, const char *who, cons struct im_connection *ic = byahoo_get_ic_by_id( id ); struct groupchat *c; - for( c = ic->conversations; c && strcmp( c->title, room ) != 0; c = c->next ); + for( c = ic->groupchats; c && strcmp( c->title, room ) != 0; c = c->next ); if( c ) imcb_chat_add_buddy( c, (char*) who ); @@ -852,7 +852,7 @@ void ext_yahoo_conf_userleave( int id, const char *ignored, const char *who, con struct im_connection *ic = byahoo_get_ic_by_id( id ); struct groupchat *c; - for( c = ic->conversations; c && strcmp( c->title, room ) != 0; c = c->next ); + for( c = ic->groupchats; c && strcmp( c->title, room ) != 0; c = c->next ); if( c ) imcb_chat_remove_buddy( c, (char*) who, "" ); @@ -864,7 +864,7 @@ void ext_yahoo_conf_message( int id, const char *ignored, const char *who, const char *m = byahoo_strip( msg ); struct groupchat *c; - for( c = ic->conversations; c && strcmp( c->title, room ) != 0; c = c->next ); + for( c = ic->groupchats; c && strcmp( c->title, room ) != 0; c = c->next ); if( c ) imcb_chat_msg( c, (char*) who, (char*) m, 0, 0 ); -- cgit v1.2.3 From 43671b964b636520a54e343542c5958b30e9f589 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 22 Apr 2007 16:39:37 -0700 Subject: You can send messages too now. But it's still very kludgy and doesn't work with anonymous rooms (ie about 95% of all available Jabber chatrooms?). --- protocols/jabber/conference.c | 29 +++++++++++++++++-------- protocols/jabber/jabber.c | 9 ++++++-- protocols/jabber/jabber.h | 3 +++ protocols/jabber/jabber_util.c | 49 ++++++++++++++++++++++++++++++++++++++++++ protocols/jabber/message.c | 3 ++- protocols/jabber/xmltree.c | 2 +- 6 files changed, 82 insertions(+), 13 deletions(-) (limited to 'protocols') diff --git a/protocols/jabber/conference.c b/protocols/jabber/conference.c index ffc4f844..397fad85 100644 --- a/protocols/jabber/conference.c +++ b/protocols/jabber/conference.c @@ -61,6 +61,25 @@ struct groupchat *jabber_chat_join( struct im_connection *ic, char *room, char * return c; } +int jabber_chat_msg( struct groupchat *c, char *message, int flags ) +{ + struct im_connection *ic = c->ic; + struct jabber_chat *jc = c->data; + struct xt_node *node; + + node = xt_new_node( "body", message, NULL ); + node = jabber_make_packet( "message", "groupchat", jc->name, node ); + + if( !jabber_write_packet( ic, node ) ) + { + xt_free_node( node ); + return 0; + } + xt_free_node( node ); + + return 1; +} + int jabber_chat_leave( struct groupchat *c, const char *reason ) { struct im_connection *ic = c->ic; @@ -78,14 +97,6 @@ int jabber_chat_leave( struct groupchat *c, const char *reason ) } xt_free_node( node ); - /* Remove all participants from jc->buddies and clean up our data. */ - jabber_buddy_remove_bare( ic, jc->name ); - g_free( jc->name ); - g_free( jc ); - - /* And the generic stuff. */ - imcb_chat_free( c ); - return 1; } @@ -187,7 +198,7 @@ void jabber_chat_pkt_message( struct im_connection *ic, struct jabber_buddy *bud { s = strchr( bud->orig_jid, '/' ); if( s ) *s = 0; - imcb_chat_msg( chat, bud->orig_jid, body->text, 0, 0 ); + imcb_chat_msg( chat, bud->orig_jid, body->text, 0, jabber_get_timestamp( node ) ); if( s ) *s = '/'; } } diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index f9473015..6c0f6240 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -335,6 +335,12 @@ static struct groupchat *jabber_chat_join_( struct im_connection *ic, char *room return NULL; } +static void jabber_chat_msg_( struct groupchat *c, char *message, int flags ) +{ + if( c && message ) + jabber_chat_msg( c, message, flags ); +} + static void jabber_chat_leave_( struct groupchat *c ) { if( c ) @@ -405,13 +411,12 @@ void jabber_initmodule() ret->logout = jabber_logout; ret->buddy_msg = jabber_buddy_msg; ret->away_states = jabber_away_states; -// ret->get_status_string = jabber_get_status_string; ret->set_away = jabber_set_away; // ret->set_info = jabber_set_info; ret->get_info = jabber_get_info; ret->add_buddy = jabber_add_buddy; ret->remove_buddy = jabber_remove_buddy; -// ret->chat_msg = jabber_chat_msg; + ret->chat_msg = jabber_chat_msg_; // ret->chat_invite = jabber_chat_invite; ret->chat_leave = jabber_chat_leave_; ret->chat_join = jabber_chat_join_; diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h index dd771910..57e24b5f 100644 --- a/protocols/jabber/jabber.h +++ b/protocols/jabber/jabber.h @@ -143,6 +143,7 @@ struct jabber_chat #define XMLNS_VERSION "jabber:iq:version" /* XEP-0092 */ #define XMLNS_TIME "jabber:iq:time" /* XEP-0090 */ #define XMLNS_VCARD "vcard-temp" /* XEP-0054 */ +#define XMLNS_DELAY "jabber:x:delay" /* XEP-0091 */ #define XMLNS_CHATSTATES "http://jabber.org/protocol/chatstates" /* 0085 */ #define XMLNS_DISCOVER "http://jabber.org/protocol/disco#info" /* 0030 */ #define XMLNS_MUC "http://jabber.org/protocol/muc" /* XEP-0045 */ @@ -191,6 +192,7 @@ struct jabber_buddy *jabber_buddy_by_jid( struct im_connection *ic, char *jid, g int jabber_buddy_remove( struct im_connection *ic, char *full_jid ); int jabber_buddy_remove_bare( struct im_connection *ic, char *bare_jid ); struct groupchat *jabber_chat_by_name( struct im_connection *ic, const char *name ); +time_t jabber_get_timestamp( struct xt_node *xt ); extern const struct jabber_away_state jabber_away_state_list[]; @@ -210,6 +212,7 @@ gboolean sasl_supported( struct im_connection *ic ); /* conference.c */ struct groupchat *jabber_chat_join( struct im_connection *ic, char *room, char *nick, char *password ); +int jabber_chat_msg( struct groupchat *ic, char *message, int flags ); int jabber_chat_leave( struct groupchat *c, const char *reason ); void jabber_chat_pkt_presence( struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node ); void jabber_chat_pkt_message( struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node ); diff --git a/protocols/jabber/jabber_util.c b/protocols/jabber/jabber_util.c index 86ddf7bc..091e6c7d 100644 --- a/protocols/jabber/jabber_util.c +++ b/protocols/jabber/jabber_util.c @@ -557,3 +557,52 @@ struct groupchat *jabber_chat_by_name( struct im_connection *ic, const char *nam return ret; } + +time_t jabber_get_timestamp( struct xt_node *xt ) +{ + struct tm tp, utc; + struct xt_node *c; + time_t res, tres; + char *s = NULL; + + for( c = xt->children; ( c = xt_find_node( c, "x" ) ); c = c->next ) + { + if( ( s = xt_find_attr( c, "xmlns" ) ) && strcmp( s, XMLNS_DELAY ) == 0 ) + break; + } + + if( !c || !( s = xt_find_attr( c, "stamp" ) ) ) + return 0; + + memset( &tp, 0, sizeof( tp ) ); + if( sscanf( s, "%4d%2d%2dT%2d:%2d:%2d", &tp.tm_year, &tp.tm_mon, &tp.tm_mday, + &tp.tm_hour, &tp.tm_min, &tp.tm_sec ) != 6 ) + return 0; + + tp.tm_year -= 1900; + tp.tm_mon --; + tp.tm_isdst = -1; /* GRRRRRRRRRRR */ + + res = mktime( &tp ); + /* Problem is, mktime() just gave us the GMT timestamp for the + given local time... While the given time WAS NOT local. So + we should fix this now. + + Now I could choose between messing with environment variables + (kludgy) or using timegm() (not portable)... Or doing the + following, which I actually prefer... */ + gmtime_r( &res, &utc ); + utc.tm_isdst = -1; /* Once more: GRRRRRRRRRRRRRRRRRR!!! */ + if( utc.tm_hour == tp.tm_hour && utc.tm_min == tp.tm_min ) + /* Sweet! We're in UTC right now... */ + return res; + + tres = mktime( &utc ); + res += res - tres; + + /* Yes, this is a hack. And it will go wrong around DST changes. + BUT this is more likely to be threadsafe than messing with + environment variables, and possibly more portable... */ + + return res; +} diff --git a/protocols/jabber/message.c b/protocols/jabber/message.c index 8a4ecaf4..198fc3b9 100644 --- a/protocols/jabber/message.c +++ b/protocols/jabber/message.c @@ -80,7 +80,8 @@ xt_status jabber_pkt_message( struct xt_node *node, gpointer data ) fullmsg = g_string_append( fullmsg, body->text ); if( fullmsg->len > 0 ) - imcb_buddy_msg( ic, bud ? bud->bare_jid : from, fullmsg->str, 0, 0 ); + imcb_buddy_msg( ic, bud ? bud->bare_jid : from, fullmsg->str, + 0, jabber_get_timestamp( node ) ); g_string_free( fullmsg, TRUE ); diff --git a/protocols/jabber/xmltree.c b/protocols/jabber/xmltree.c index c8bef362..9e16b939 100644 --- a/protocols/jabber/xmltree.c +++ b/protocols/jabber/xmltree.c @@ -187,7 +187,7 @@ int xt_handle( struct xt_parser *xt, struct xt_node *node, int depth ) /* If there's no parent, the handler should mention as a parent. */ g_strcasecmp( xt->handlers[i].parent, "" ) == 0 ) ) ) { - xt_print( node ); +// xt_print( node ); st = xt->handlers[i].func( node, xt->data ); -- cgit v1.2.3 From 0e7ab64dfb66192a875c37322ca6f8a364ec5bc8 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 22 Apr 2007 19:58:44 -0700 Subject: Got rid of one HORRIBLE stupidity called chat_by_channel(), which still used the GLOBAL IM connections list, allowing user A to interfere with user B's groupchats if running in daemon mode. I can't believe this was still there... --- protocols/jabber/conference.c | 4 ++-- protocols/nogaim.c | 18 ------------------ protocols/nogaim.h | 1 - 3 files changed, 2 insertions(+), 21 deletions(-) (limited to 'protocols') diff --git a/protocols/jabber/conference.c b/protocols/jabber/conference.c index 397fad85..c16236b3 100644 --- a/protocols/jabber/conference.c +++ b/protocols/jabber/conference.c @@ -101,7 +101,7 @@ int jabber_chat_leave( struct groupchat *c, const char *reason ) } /* Not really the same syntax as the normal pkt_ functions, but this isn't - called by the xmltree parser exactly and this way I can add some extra + called by the xmltree parser directly and this way I can add some extra parameters so we won't have to repeat too many things done by the caller already. */ void jabber_chat_pkt_presence( struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node ) @@ -150,7 +150,7 @@ void jabber_chat_pkt_presence( struct im_connection *ic, struct jabber_buddy *bu imcb_chat_add_buddy( chat, bud->orig_jid ); if( s ) *s = '/'; } - else if( type ) /* This only gets called if type=="unavailable" */ + else if( type ) /* This only gets called if type is NULL or "unavailable" */ { /* Won't handle this for now. */ if( bud->orig_jid == NULL ) diff --git a/protocols/nogaim.c b/protocols/nogaim.c index f3dbb0b8..5b1c4346 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -855,24 +855,6 @@ static int remove_chat_buddy_silent( struct groupchat *b, char *handle ) /* Misc. BitlBee stuff which shouldn't really be here */ -struct groupchat *chat_by_channel( char *channel ) -{ - struct im_connection *ic; - struct groupchat *c; - GSList *l; - - /* This finds the connection which has a conversation which belongs to this channel */ - for( l = connections; l; l = l->next ) - { - ic = l->data; - for( c = ic->groupchats; c && g_strcasecmp( c->channel, channel ) != 0; c = c->next ); - if( c ) - return c; - } - - return NULL; -} - char *set_eval_away_devoice( set_t *set, char *value ) { irc_t *irc = set->data; diff --git a/protocols/nogaim.h b/protocols/nogaim.h index b26cf73e..4eb5cea1 100644 --- a/protocols/nogaim.h +++ b/protocols/nogaim.h @@ -206,7 +206,6 @@ G_MODULE_EXPORT void imcb_chat_add_buddy( struct groupchat *b, char *handle ); G_MODULE_EXPORT void imcb_chat_remove_buddy( struct groupchat *b, char *handle, char *reason ); G_MODULE_EXPORT void imcb_chat_msg( struct groupchat *c, char *who, char *msg, u_int32_t flags, time_t sent_at ); G_MODULE_EXPORT void imcb_chat_free( struct groupchat *c ); -struct groupchat *chat_by_channel( char *channel ); /* Actions, or whatever. */ int imc_set_away( struct im_connection *ic, char *away ); -- cgit v1.2.3 From 2d317bbe8def887fb796b2daaa958c59d8f4c070 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 22 Apr 2007 22:18:47 -0700 Subject: Fixes: handling of being kicked, now sending tags to all conferences the user's in. --- protocols/jabber/conference.c | 2 ++ protocols/jabber/presence.c | 11 +++++++++++ protocols/jabber/xmltree.c | 2 +- protocols/nogaim.c | 9 ++++++--- 4 files changed, 20 insertions(+), 4 deletions(-) (limited to 'protocols') diff --git a/protocols/jabber/conference.c b/protocols/jabber/conference.c index c16236b3..f0d8f050 100644 --- a/protocols/jabber/conference.c +++ b/protocols/jabber/conference.c @@ -162,6 +162,8 @@ void jabber_chat_pkt_presence( struct im_connection *ic, struct jabber_buddy *bu if( bud == jc->me ) { + jabber_buddy_remove_bare( ic, jc->name ); + g_free( jc->name ); g_free( jc ); imcb_chat_free( chat ); diff --git a/protocols/jabber/presence.c b/protocols/jabber/presence.c index 096b4fd5..1310fce3 100644 --- a/protocols/jabber/presence.c +++ b/protocols/jabber/presence.c @@ -167,6 +167,7 @@ int presence_send_update( struct im_connection *ic ) struct xt_node *node; char *show = jd->away_state->code; char *status = jd->away_message; + struct groupchat *c; int st; node = jabber_make_packet( "presence", NULL, NULL, NULL ); @@ -178,6 +179,16 @@ int presence_send_update( struct im_connection *ic ) st = jabber_write_packet( ic, node ); + /* Have to send this update to all groupchats too, the server won't + do this automatically. */ + for( c = ic->groupchats; c && st; c = c->next ) + { + struct jabber_chat *jc = c->data; + + xt_add_attr( node, "to", jc->me->full_jid ); + st = jabber_write_packet( ic, node ); + } + xt_free_node( node ); return st; } diff --git a/protocols/jabber/xmltree.c b/protocols/jabber/xmltree.c index 9e16b939..c8bef362 100644 --- a/protocols/jabber/xmltree.c +++ b/protocols/jabber/xmltree.c @@ -187,7 +187,7 @@ int xt_handle( struct xt_parser *xt, struct xt_node *node, int depth ) /* If there's no parent, the handler should mention as a parent. */ g_strcasecmp( xt->handlers[i].parent, "" ) == 0 ) ) ) { -// xt_print( node ); + xt_print( node ); st = xt->handlers[i].func( node, xt->data ); diff --git a/protocols/nogaim.c b/protocols/nogaim.c index 5b1c4346..5a9f5b3e 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -806,6 +806,7 @@ void imcb_chat_add_buddy( struct groupchat *b, char *handle ) } } +/* This function is one BIG hack... :-( EREWRITE */ void imcb_chat_remove_buddy( struct groupchat *b, char *handle, char *reason ) { user_t *u; @@ -817,6 +818,9 @@ void imcb_chat_remove_buddy( struct groupchat *b, char *handle, char *reason ) /* It might be yourself! */ if( g_strcasecmp( handle, b->ic->acc->user ) == 0 ) { + if( b->joined == 0 ) + return; + u = user_find( b->ic->irc, b->ic->irc->nick ); b->joined = 0; me = 1; @@ -826,9 +830,8 @@ void imcb_chat_remove_buddy( struct groupchat *b, char *handle, char *reason ) u = user_findhandle( b->ic, handle ); } - if( remove_chat_buddy_silent( b, handle ) ) - if( ( b->joined || me ) && u ) - irc_part( b->ic->irc, u, b->channel ); + if( me || ( remove_chat_buddy_silent( b, handle ) && b->joined && u ) ) + irc_part( b->ic->irc, u, b->channel ); } static int remove_chat_buddy_silent( struct groupchat *b, char *handle ) -- cgit v1.2.3 From 6286f80d6dc1dc4cb8106b4e209a8578d7cebe56 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 25 Apr 2007 21:41:34 -0700 Subject: Prepared the Jabber module for anonymous rooms, but the BitlBee core doesn't deal with it very well, and I don't really know yet how I'll solve this... :-( --- protocols/jabber/conference.c | 31 +++++++++++++++++-------------- protocols/jabber/jabber.h | 6 ++++-- protocols/jabber/jabber_util.c | 3 +++ protocols/nogaim.h | 1 + 4 files changed, 25 insertions(+), 16 deletions(-) (limited to 'protocols') diff --git a/protocols/jabber/conference.c b/protocols/jabber/conference.c index f0d8f050..dde2b8b5 100644 --- a/protocols/jabber/conference.c +++ b/protocols/jabber/conference.c @@ -136,28 +136,31 @@ void jabber_chat_pkt_presence( struct im_connection *ic, struct jabber_buddy *bu if( ( s = xt_find_attr( c, "jid" ) ) ) { /* Yay, found what we need. :-) */ - bud->orig_jid = g_strdup( s ); + bud->ext_jid = g_strdup( s ); break; } } - /* Won't handle this for now. */ - if( bud->orig_jid == NULL ) - return; + /* Make up some other handle, if necessary. */ + if( bud->ext_jid == NULL ) + { + /* Don't want the nick to be at the end, so let's + think of some slightly different notation to use + for anonymous groupchat participants in BitlBee. */ + bud->ext_jid = g_strdup_printf( "%s=%s", bud->resource, bud->bare_jid ); + bud->flags |= JBFLAG_IS_ANONYMOUS; + } - s = strchr( bud->orig_jid, '/' ); + s = strchr( bud->ext_jid, '/' ); if( s ) *s = 0; /* Should NEVER be NULL, but who knows... */ - imcb_chat_add_buddy( chat, bud->orig_jid ); + imcb_chat_add_buddy( chat, bud->ext_jid ); if( s ) *s = '/'; } else if( type ) /* This only gets called if type is NULL or "unavailable" */ { - /* Won't handle this for now. */ - if( bud->orig_jid == NULL ) - return; - s = strchr( bud->orig_jid, '/' ); - if( s ) *s = 0; /* Should NEVER be NULL, but who knows... */ - imcb_chat_remove_buddy( chat, bud->orig_jid, NULL ); + s = strchr( bud->ext_jid, '/' ); + if( s ) *s = 0; + imcb_chat_remove_buddy( chat, bud->ext_jid, NULL ); if( s ) *s = '/'; if( bud == jc->me ) @@ -198,9 +201,9 @@ void jabber_chat_pkt_message( struct im_connection *ic, struct jabber_buddy *bud if( body && body->text_len > 0 ) { - s = strchr( bud->orig_jid, '/' ); + s = strchr( bud->ext_jid, '/' ); if( s ) *s = 0; - imcb_chat_msg( chat, bud->orig_jid, body->text, 0, jabber_get_timestamp( node ) ); + imcb_chat_msg( chat, bud->ext_jid, body->text, 0, jabber_get_timestamp( node ) ); if( s ) *s = '/'; } } diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h index 57e24b5f..ba61920c 100644 --- a/protocols/jabber/jabber.h +++ b/protocols/jabber/jabber.h @@ -51,6 +51,8 @@ typedef enum XEP85 (typing notification shite). */ JBFLAG_IS_CHATROOM = 4, /* It's convenient to use this JID thingy for groupchat state info too. */ + JBFLAG_IS_ANONYMOUS = 8, /* For anonymous chatrooms, when we don't have + have a real JID. */ } jabber_buddy_flags_t; #define JABBER_PORT_DEFAULT "5222" @@ -102,8 +104,8 @@ struct jabber_buddy char *full_jid; char *resource; - /* Groupchat-only */ - char *orig_jid; + char *ext_jid; /* The JID to use in BitlBee. The real JID if possible, */ + /* otherwise something similar to the conference JID. */ int priority; struct jabber_away_state *away_state; diff --git a/protocols/jabber/jabber_util.c b/protocols/jabber/jabber_util.c index 091e6c7d..4dae3287 100644 --- a/protocols/jabber/jabber_util.c +++ b/protocols/jabber/jabber_util.c @@ -450,6 +450,7 @@ int jabber_buddy_remove( struct im_connection *ic, char *full_jid_ ) { g_hash_table_remove( jd->buddies, bud->bare_jid ); g_free( bud->bare_jid ); + g_free( bud->ext_jid ); g_free( bud->full_jid ); g_free( bud->away_message ); g_free( bud ); @@ -482,6 +483,7 @@ int jabber_buddy_remove( struct im_connection *ic, char *full_jid_ ) item, because we're removing the first. */ g_hash_table_replace( jd->buddies, bi->bare_jid, bi->next ); + g_free( bi->ext_jid ); g_free( bi->full_jid ); g_free( bi->away_message ); g_free( bi ); @@ -525,6 +527,7 @@ int jabber_buddy_remove_bare( struct im_connection *ic, char *bare_jid_ ) while( bud ) { next = bud->next; + g_free( bud->ext_jid ); g_free( bud->full_jid ); g_free( bud->away_message ); g_free( bud ); diff --git a/protocols/nogaim.h b/protocols/nogaim.h index 4eb5cea1..6bbee6f7 100644 --- a/protocols/nogaim.h +++ b/protocols/nogaim.h @@ -60,6 +60,7 @@ #define OPT_LOGGING_OUT 0x00000002 #define OPT_AWAY 0x00000004 #define OPT_DOES_HTML 0x00000010 +#define OPT_LOCALBUDDY 0x00000020 /* For nicks local to one groupchat */ #define OPT_TYPING 0x00000100 /* Some pieces of code make assumptions */ #define OPT_THINKING 0x00000200 /* about these values... Stupid me! */ -- cgit v1.2.3 From bb95d43e263530805224005ca246addb6bb199fa Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 4 Jun 2007 12:32:37 +0100 Subject: Added a real XML-console to the Jabber module! Add the handle "xmlconsole" (without any @server part) to your contact list and you'll see all XMPP traffic going in and out, and messages sent to the buddy will be sent as packets to the server. --- protocols/jabber/io.c | 29 +++++++++++++++++++++++++++++ protocols/jabber/jabber.c | 21 +++++++++++++++++++++ protocols/jabber/jabber.h | 23 +++++++++++++---------- protocols/jabber/xmltree.c | 2 -- 4 files changed, 63 insertions(+), 12 deletions(-) (limited to 'protocols') diff --git a/protocols/jabber/io.c b/protocols/jabber/io.c index 67deb3a6..edde5a8d 100644 --- a/protocols/jabber/io.c +++ b/protocols/jabber/io.c @@ -44,6 +44,15 @@ int jabber_write( struct im_connection *ic, char *buf, int len ) struct jabber_data *jd = ic->proto_data; gboolean ret; + if( jd->flags & JFLAG_XMLCONSOLE ) + { + char *msg; + + msg = g_strdup_printf( "TX: %s", buf ); + imcb_buddy_msg( ic, JABBER_XMLCONSOLE_HANDLE, msg, 0, 0 ); + g_free( msg ); + } + if( jd->tx_len == 0 ) { /* If the queue is empty, allocate a new buffer. */ @@ -483,7 +492,27 @@ static xt_status jabber_pkt_misc( struct xt_node *node, gpointer data ) return XT_HANDLED; } +static xt_status jabber_xmlconsole( struct xt_node *node, gpointer data ) +{ + struct im_connection *ic = data; + struct jabber_data *jd = ic->proto_data; + + if( jd->flags & JFLAG_XMLCONSOLE ) + { + char *msg, *pkt; + + pkt = xt_to_string( node ); + msg = g_strdup_printf( "RX: %s", pkt ); + imcb_buddy_msg( ic, JABBER_XMLCONSOLE_HANDLE, msg, 0, 0 ); + g_free( msg ); + g_free( pkt ); + } + + return XT_NEXT; +} + static const struct xt_handler_entry jabber_handlers[] = { + { NULL, "stream:stream", jabber_xmlconsole }, { "stream:stream", "", jabber_end_of_stream }, { "message", "stream:stream", jabber_pkt_message }, { "presence", "stream:stream", jabber_pkt_presence }, diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 6c0f6240..b70af944 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -225,6 +225,9 @@ static int jabber_buddy_msg( struct im_connection *ic, char *who, char *message, struct xt_node *node; int st; + if( g_strcasecmp( who, JABBER_XMLCONSOLE_HANDLE ) == 0 ) + return jabber_write( ic, message, strlen( message ) ); + bud = jabber_buddy_by_jid( ic, who, 0 ); node = xt_new_node( "body", message, NULL ); @@ -310,12 +313,30 @@ static void jabber_set_away( struct im_connection *ic, char *state_txt, char *me static void jabber_add_buddy( struct im_connection *ic, char *who, char *group ) { + struct jabber_data *jd = ic->proto_data; + + if( g_strcasecmp( who, JABBER_XMLCONSOLE_HANDLE ) == 0 ) + { + jd->flags |= JFLAG_XMLCONSOLE; + imcb_add_buddy( ic, JABBER_XMLCONSOLE_HANDLE, NULL ); + return; + } + if( jabber_add_to_roster( ic, who, NULL ) ) presence_send_request( ic, who, "subscribe" ); } static void jabber_remove_buddy( struct im_connection *ic, char *who, char *group ) { + struct jabber_data *jd = ic->proto_data; + + if( g_strcasecmp( who, JABBER_XMLCONSOLE_HANDLE ) == 0 ) + { + jd->flags &= ~JFLAG_XMLCONSOLE; + /* FIXME imcb_remove_buddy( ic, JABBER_XMLCONSOLE_HANDLE, NULL ); */ + return; + } + /* We should always do this part. Clean up our administration a little bit. */ jabber_buddy_remove_bare( ic, who ); diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h index ba61920c..2fb01fdc 100644 --- a/protocols/jabber/jabber.h +++ b/protocols/jabber/jabber.h @@ -31,16 +31,17 @@ typedef enum { - JFLAG_STREAM_STARTED = 1, /* Set when we detected the beginning of the stream + JFLAG_STREAM_STARTED = 1, /* Set when we detected the beginning of the stream and want to do auth. */ - JFLAG_AUTHENTICATED = 2, /* Set when we're successfully authenticatd. */ - JFLAG_STREAM_RESTART = 4, /* Set when we want to restart the stream (after + JFLAG_AUTHENTICATED = 2, /* Set when we're successfully authenticatd. */ + JFLAG_STREAM_RESTART = 4, /* Set when we want to restart the stream (after SASL or TLS). */ - JFLAG_WAIT_SESSION = 8, /* Set if we sent a tag and need a reply + JFLAG_WAIT_SESSION = 8, /* Set if we sent a tag and need a reply before we continue. */ - JFLAG_WAIT_BIND = 16, /* ... for tag. */ - JFLAG_WANT_TYPING = 32, /* Set if we ever sent a typing notification, this + JFLAG_WAIT_BIND = 16, /* ... for tag. */ + JFLAG_WANT_TYPING = 32, /* Set if we ever sent a typing notification, this activates all XEP-85 related code. */ + JFLAG_XMLCONSOLE = 64, /* If the user added an xmlconsole buddy. */ } jabber_flags_t; typedef enum @@ -55,10 +56,6 @@ typedef enum have a real JID. */ } jabber_buddy_flags_t; -#define JABBER_PORT_DEFAULT "5222" -#define JABBER_PORT_MIN 5220 -#define JABBER_PORT_MAX 5229 - struct jabber_data { struct im_connection *ic; @@ -124,6 +121,12 @@ struct jabber_chat struct jabber_buddy *me; }; +#define JABBER_XMLCONSOLE_HANDLE "xmlconsole" + +#define JABBER_PORT_DEFAULT "5222" +#define JABBER_PORT_MIN 5220 +#define JABBER_PORT_MAX 5229 + /* Prefixes to use for packet IDs (mainly for IQ packets ATM). Usually the first one should be used, but when storing a packet in the cache, a "special" kind of ID is assigned to make it easier later to figure out diff --git a/protocols/jabber/xmltree.c b/protocols/jabber/xmltree.c index c8bef362..7a165a1e 100644 --- a/protocols/jabber/xmltree.c +++ b/protocols/jabber/xmltree.c @@ -187,8 +187,6 @@ int xt_handle( struct xt_parser *xt, struct xt_node *node, int depth ) /* If there's no parent, the handler should mention as a parent. */ g_strcasecmp( xt->handlers[i].parent, "" ) == 0 ) ) ) { - xt_print( node ); - st = xt->handlers[i].func( node, xt->data ); if( st == XT_ABORT ) -- cgit v1.2.3 From 54f2f55f983f4b6bb8a58772bbd1137580e3307f Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 4 Jun 2007 12:45:33 +0100 Subject: Now anonymous rooms should really work. This makes sure the self-join will actually be recognized properly. This is running on my work machine for a few days already. --- protocols/jabber/conference.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'protocols') diff --git a/protocols/jabber/conference.c b/protocols/jabber/conference.c index dde2b8b5..a97590ba 100644 --- a/protocols/jabber/conference.c +++ b/protocols/jabber/conference.c @@ -144,10 +144,14 @@ void jabber_chat_pkt_presence( struct im_connection *ic, struct jabber_buddy *bu /* Make up some other handle, if necessary. */ if( bud->ext_jid == NULL ) { - /* Don't want the nick to be at the end, so let's - think of some slightly different notation to use - for anonymous groupchat participants in BitlBee. */ - bud->ext_jid = g_strdup_printf( "%s=%s", bud->resource, bud->bare_jid ); + if( bud == jc->me ) + bud->ext_jid = g_strdup( ic->acc->user ); + else + /* Don't want the nick to be at the end, so let's + think of some slightly different notation to use + for anonymous groupchat participants in BitlBee. */ + bud->ext_jid = g_strdup_printf( "%s=%s", bud->resource, bud->bare_jid ); + bud->flags |= JBFLAG_IS_ANONYMOUS; } -- cgit v1.2.3 From d06eabf19ec3f849d8bab22c13d43e4eba9a48ee Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 4 Jun 2007 14:22:05 +0100 Subject: Added imcb_buddy_nick_hint so the Jabber conference module can suggest sane nicknames for chatroom participants. There'll probably be a lot of underscores now, but this is by far the cleanest way to implement this, I think. At least now whispers will work properly. Also using this function call to set names for ICQ contacts in a slightly saner way. --- protocols/jabber/conference.c | 3 +++ protocols/jabber/iq.c | 6 +++++- protocols/nogaim.c | 47 +++++++++++++++++++++++-------------------- protocols/nogaim.h | 1 + protocols/oscar/oscar.c | 1 + 5 files changed, 35 insertions(+), 23 deletions(-) (limited to 'protocols') diff --git a/protocols/jabber/conference.c b/protocols/jabber/conference.c index a97590ba..b77e037b 100644 --- a/protocols/jabber/conference.c +++ b/protocols/jabber/conference.c @@ -159,6 +159,9 @@ void jabber_chat_pkt_presence( struct im_connection *ic, struct jabber_buddy *bu if( s ) *s = 0; /* Should NEVER be NULL, but who knows... */ imcb_chat_add_buddy( chat, bud->ext_jid ); if( s ) *s = '/'; + + if( bud != jc->me ) + imcb_buddy_nick_hint( ic, bud->ext_jid, bud->resource ); } else if( type ) /* This only gets called if type is NULL or "unavailable" */ { diff --git a/protocols/jabber/iq.c b/protocols/jabber/iq.c index 2aa9d432..62e6a183 100644 --- a/protocols/jabber/iq.c +++ b/protocols/jabber/iq.c @@ -372,7 +372,11 @@ static xt_status jabber_parse_roster( struct im_connection *ic, struct xt_node * imcb_add_buddy( ic, jid, ( group && group->text_len ) ? group->text : NULL ); - imcb_rename_buddy( ic, jid, name ); + if( name ) + { + imcb_rename_buddy( ic, jid, name ); + imcb_buddy_nick_hint( ic, jid, name ); + } } else if( strcmp( sub, "remove" ) == 0 ) { diff --git a/protocols/nogaim.c b/protocols/nogaim.c index 5a9f5b3e..71cebacd 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -427,7 +427,6 @@ struct buddy *imcb_find_buddy( struct im_connection *ic, char *handle ) void imcb_rename_buddy( struct im_connection *ic, char *handle, char *realname ) { user_t *u = user_findhandle( ic, handle ); - char *s, newnick[MAX_NICK_LENGTH+1]; if( !u || !realname ) return; @@ -439,30 +438,34 @@ void imcb_rename_buddy( struct im_connection *ic, char *handle, char *realname ) if( ( ic->flags & OPT_LOGGED_IN ) && set_getbool( &ic->irc->set, "display_namechanges" ) ) imcb_log( ic, "User `%s' changed name to `%s'", u->nick, u->realname ); - - if( !u->online && !nick_saved( ic->acc, handle ) ) - { - /* Detect numeric handles: */ - for( s = u->user; isdigit( *s ); s++ ); - - if( *s == 0 ) - { - /* If we reached the end of the string, it only contained numbers. - Seems to be an ICQ# then, so hopefully realname contains - something more useful. */ - strcpy( newnick, realname ); - - /* Some processing to make sure this string is a valid IRC nickname. */ - nick_strip( newnick ); - if( set_getbool( &ic->irc->set, "lcnicks" ) ) - nick_lc( newnick ); - - u->nick = g_strdup( newnick ); - } - } } } +/* Mainly meant for ICQ (and now also for Jabber conferences) to allow IM + modules to suggest a nickname for a handle. */ +void imcb_buddy_nick_hint( struct im_connection *ic, char *handle, char *nick ) +{ + user_t *u = user_findhandle( ic, handle ); + char newnick[MAX_NICK_LENGTH+1]; + + if( !u->online && !nick_saved( ic->acc, handle ) ) + { + /* Only do this if the person isn't online yet (which should + be the case if we just added it) and if the user hasn't + assigned a nickname to this buddy already. */ + + strcpy( newnick, nick ); + + /* Some processing to make sure this string is a valid IRC nickname. */ + nick_strip( newnick ); + if( set_getbool( &ic->irc->set, "lcnicks" ) ) + nick_lc( newnick ); + + nick_dedupe( ic->acc, handle, newnick ); + + u->nick = g_strdup( newnick ); + } +} /* prpl.c */ diff --git a/protocols/nogaim.h b/protocols/nogaim.h index 6bbee6f7..74a63306 100644 --- a/protocols/nogaim.h +++ b/protocols/nogaim.h @@ -193,6 +193,7 @@ G_MODULE_EXPORT void imcb_add_buddy( struct im_connection *ic, char *handle, cha G_MODULE_EXPORT void imcb_remove_buddy( struct im_connection *ic, char *handle, char *group ); G_MODULE_EXPORT struct buddy *imcb_find_buddy( struct im_connection *ic, char *handle ); G_MODULE_EXPORT void imcb_rename_buddy( struct im_connection *ic, char *handle, char *realname ); +G_MODULE_EXPORT void imcb_buddy_nick_hint( struct im_connection *ic, char *handle, char *nick ); /* Buddy activity */ G_MODULE_EXPORT void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, const char *state, const char *message ); diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c index b72c683a..39d14811 100644 --- a/protocols/oscar/oscar.c +++ b/protocols/oscar/oscar.c @@ -2021,6 +2021,7 @@ static int gaim_ssi_parselist(aim_session_t *sess, aim_frame_t *fr, ...) { imcb_add_buddy(ic, curitem->name, NULL); if (realname) { + imcb_buddy_nick_hint(ic, curitem->name, realname); imcb_rename_buddy(ic, curitem->name, realname); g_free(realname); } -- cgit v1.2.3 From e0e2a71ed3e7937ed5da85af95be016a8441547b Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 4 Jun 2007 14:36:51 +0100 Subject: Fixed retarded use of strcpy() and no longer using Jabber fullnames for nickname generation. IM fullnames and IRC nicknames are just *different*. --- protocols/jabber/iq.c | 3 --- protocols/nogaim.c | 5 +++-- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'protocols') diff --git a/protocols/jabber/iq.c b/protocols/jabber/iq.c index 62e6a183..0050fb5b 100644 --- a/protocols/jabber/iq.c +++ b/protocols/jabber/iq.c @@ -373,10 +373,7 @@ static xt_status jabber_parse_roster( struct im_connection *ic, struct xt_node * group->text : NULL ); if( name ) - { imcb_rename_buddy( ic, jid, name ); - imcb_buddy_nick_hint( ic, jid, name ); - } } else if( strcmp( sub, "remove" ) == 0 ) { diff --git a/protocols/nogaim.c b/protocols/nogaim.c index 71cebacd..06bd8e4b 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -448,13 +448,14 @@ void imcb_buddy_nick_hint( struct im_connection *ic, char *handle, char *nick ) user_t *u = user_findhandle( ic, handle ); char newnick[MAX_NICK_LENGTH+1]; - if( !u->online && !nick_saved( ic->acc, handle ) ) + if( u && !u->online && !nick_saved( ic->acc, handle ) ) { /* Only do this if the person isn't online yet (which should be the case if we just added it) and if the user hasn't assigned a nickname to this buddy already. */ - strcpy( newnick, nick ); + strncpy( newnick, nick, MAX_NICK_LENGTH ); + newnick[MAX_NICK_LENGTH] = 0; /* Some processing to make sure this string is a valid IRC nickname. */ nick_strip( newnick ); -- cgit v1.2.3 From c570c86bd6c08c77d851ac81a9603dcd13c7804a Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 4 Jun 2007 16:56:09 +0100 Subject: Calling imcb_add_buddy() before setting the nickname. This is the only way to set the nickname in time before BitlBee sends the JOIN. --- protocols/jabber/conference.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'protocols') diff --git a/protocols/jabber/conference.c b/protocols/jabber/conference.c index b77e037b..09a63cbc 100644 --- a/protocols/jabber/conference.c +++ b/protocols/jabber/conference.c @@ -155,13 +155,16 @@ void jabber_chat_pkt_presence( struct im_connection *ic, struct jabber_buddy *bu bud->flags |= JBFLAG_IS_ANONYMOUS; } + if( bud != jc->me ) + { + imcb_add_buddy( ic, bud->ext_jid, NULL ); + imcb_buddy_nick_hint( ic, bud->ext_jid, bud->resource ); + } + s = strchr( bud->ext_jid, '/' ); if( s ) *s = 0; /* Should NEVER be NULL, but who knows... */ imcb_chat_add_buddy( chat, bud->ext_jid ); if( s ) *s = '/'; - - if( bud != jc->me ) - imcb_buddy_nick_hint( ic, bud->ext_jid, bud->resource ); } else if( type ) /* This only gets called if type is NULL or "unavailable" */ { -- cgit v1.2.3 From 7e9dc74b15901b182be2a1d20bafdba696e4f5f2 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Thu, 14 Jun 2007 00:30:59 +0100 Subject: Fixed the duplicate-nick problem. Very very very stupid bug... :-( --- protocols/nogaim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'protocols') diff --git a/protocols/nogaim.c b/protocols/nogaim.c index 06bd8e4b..6c564c8c 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -464,7 +464,7 @@ void imcb_buddy_nick_hint( struct im_connection *ic, char *handle, char *nick ) nick_dedupe( ic->acc, handle, newnick ); - u->nick = g_strdup( newnick ); + user_rename( ic->irc, u->nick, newnick ); } } -- cgit v1.2.3 From 43d8cc5909aa45aee0b3368e70275469b0f8de22 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Thu, 14 Jun 2007 00:31:18 +0100 Subject: Fixed a memory management problem that caused some strange nickname issues. --- protocols/nogaim.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'protocols') diff --git a/protocols/nogaim.c b/protocols/nogaim.c index 6c564c8c..a1a97dc3 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -446,7 +446,7 @@ void imcb_rename_buddy( struct im_connection *ic, char *handle, char *realname ) void imcb_buddy_nick_hint( struct im_connection *ic, char *handle, char *nick ) { user_t *u = user_findhandle( ic, handle ); - char newnick[MAX_NICK_LENGTH+1]; + char newnick[MAX_NICK_LENGTH+1], *orig_nick; if( u && !u->online && !nick_saved( ic->acc, handle ) ) { @@ -464,7 +464,11 @@ void imcb_buddy_nick_hint( struct im_connection *ic, char *handle, char *nick ) nick_dedupe( ic->acc, handle, newnick ); - user_rename( ic->irc, u->nick, newnick ); + /* u->nick will be freed halfway the process, so it can't be + passed as an argument. */ + orig_nick = g_strdup( u->nick ); + user_rename( ic->irc, orig_nick, newnick ); + g_free( orig_nick ); } } -- cgit v1.2.3 From 998b1035a6c8349b3661861eeb5d9d1f4082ba0a Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Thu, 14 Jun 2007 00:31:39 +0100 Subject: Added imcb_remove_buddy() so deletions in Jabber roster pushes actually work. This also solves the issue of underscores appearing and disappearing in their nicknames when people leave/join a chat. --- protocols/jabber/conference.c | 4 +++- protocols/jabber/iq.c | 5 +---- protocols/jabber/jabber.c | 2 +- protocols/nogaim.c | 8 ++++++++ 4 files changed, 13 insertions(+), 6 deletions(-) (limited to 'protocols') diff --git a/protocols/jabber/conference.c b/protocols/jabber/conference.c index 09a63cbc..1b392655 100644 --- a/protocols/jabber/conference.c +++ b/protocols/jabber/conference.c @@ -166,11 +166,13 @@ void jabber_chat_pkt_presence( struct im_connection *ic, struct jabber_buddy *bu imcb_chat_add_buddy( chat, bud->ext_jid ); if( s ) *s = '/'; } - else if( type ) /* This only gets called if type is NULL or "unavailable" */ + else if( type ) /* type can only be NULL or "unavailable" in this function */ { s = strchr( bud->ext_jid, '/' ); if( s ) *s = 0; imcb_chat_remove_buddy( chat, bud->ext_jid, NULL ); + if( bud != jc->me && bud->flags & JBFLAG_IS_ANONYMOUS ) + imcb_remove_buddy( ic, bud->ext_jid, NULL ); if( s ) *s = '/'; if( bud == jc->me ) diff --git a/protocols/jabber/iq.c b/protocols/jabber/iq.c index 0050fb5b..e5c5dde2 100644 --- a/protocols/jabber/iq.c +++ b/protocols/jabber/iq.c @@ -377,11 +377,8 @@ static xt_status jabber_parse_roster( struct im_connection *ic, struct xt_node * } else if( strcmp( sub, "remove" ) == 0 ) { - /* Don't have any API call for this yet! So let's - just try to handle this as well as we can. */ jabber_buddy_remove_bare( ic, jid ); - imcb_buddy_status( ic, jid, 0, NULL, NULL ); - /* FIXME! */ + imcb_remove_buddy( ic, jid, NULL ); } } diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index b70af944..ad28c93c 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -333,7 +333,7 @@ static void jabber_remove_buddy( struct im_connection *ic, char *who, char *grou if( g_strcasecmp( who, JABBER_XMLCONSOLE_HANDLE ) == 0 ) { jd->flags &= ~JFLAG_XMLCONSOLE; - /* FIXME imcb_remove_buddy( ic, JABBER_XMLCONSOLE_HANDLE, NULL ); */ + imcb_remove_buddy( ic, JABBER_XMLCONSOLE_HANDLE, NULL ); return; } diff --git a/protocols/nogaim.c b/protocols/nogaim.c index a1a97dc3..4f04993c 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -441,6 +441,14 @@ void imcb_rename_buddy( struct im_connection *ic, char *handle, char *realname ) } } +void imcb_remove_buddy( struct im_connection *ic, char *handle, char *group ) +{ + user_t *u; + + if( ( u = user_findhandle( ic, handle ) ) ) + user_del( ic->irc, u->nick ); +} + /* Mainly meant for ICQ (and now also for Jabber conferences) to allow IM modules to suggest a nickname for a handle. */ void imcb_buddy_nick_hint( struct im_connection *ic, char *handle, char *nick ) -- cgit v1.2.3 From a3d5766eba9b1225d41cede5d817a48c3a3e0b7d Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 20 Jun 2007 00:28:45 +0100 Subject: Not calling imcb_remove_buddy() right after removing the XML console buddy anymore. --- protocols/jabber/jabber.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'protocols') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index ad28c93c..f09583ec 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -333,7 +333,11 @@ static void jabber_remove_buddy( struct im_connection *ic, char *who, char *grou if( g_strcasecmp( who, JABBER_XMLCONSOLE_HANDLE ) == 0 ) { jd->flags &= ~JFLAG_XMLCONSOLE; + /* Not necessary for now. And for now the code isn't too + happy if the buddy is completely gone right after calling + this function already. imcb_remove_buddy( ic, JABBER_XMLCONSOLE_HANDLE, NULL ); + */ return; } -- cgit v1.2.3 From 40ef702d3e500eb38d7410114ace54e8a70b151e Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 1 Jul 2007 14:08:47 +0100 Subject: Less copy-pasting in the service discovery reply and added MUC support to that list. And adding some const stuff in the xmltree functions. --- protocols/jabber/iq.c | 27 +++++++++++++-------------- protocols/jabber/xmltree.c | 8 ++++---- protocols/jabber/xmltree.h | 8 ++++---- 3 files changed, 21 insertions(+), 22 deletions(-) (limited to 'protocols') diff --git a/protocols/jabber/iq.c b/protocols/jabber/iq.c index e5c5dde2..4738817a 100644 --- a/protocols/jabber/iq.c +++ b/protocols/jabber/iq.c @@ -98,26 +98,25 @@ xt_status jabber_pkt_iq( struct xt_node *node, gpointer data ) } else if( strcmp( s, XMLNS_DISCOVER ) == 0 ) { + const char *features[] = { XMLNS_VERSION, + XMLNS_TIME, + XMLNS_CHATSTATES, + XMLNS_MUC, + NULL }; + const char **f; + c = xt_new_node( "identity", NULL, NULL ); xt_add_attr( c, "category", "client" ); xt_add_attr( c, "type", "pc" ); xt_add_attr( c, "name", "BitlBee" ); xt_add_child( reply, c ); - c = xt_new_node( "feature", NULL, NULL ); - xt_add_attr( c, "var", XMLNS_VERSION ); - xt_add_child( reply, c ); - - c = xt_new_node( "feature", NULL, NULL ); - xt_add_attr( c, "var", XMLNS_TIME ); - xt_add_child( reply, c ); - - c = xt_new_node( "feature", NULL, NULL ); - xt_add_attr( c, "var", XMLNS_CHATSTATES ); - xt_add_child( reply, c ); - - /* Later this can be useful to announce things like - MUC support. */ + for( f = features; *f; f ++ ) + { + c = xt_new_node( "feature", NULL, NULL ); + xt_add_attr( c, "var", *f ); + xt_add_child( reply, c ); + } } else { diff --git a/protocols/jabber/xmltree.c b/protocols/jabber/xmltree.c index 7a165a1e..b1edd55d 100644 --- a/protocols/jabber/xmltree.c +++ b/protocols/jabber/xmltree.c @@ -441,7 +441,7 @@ void xt_free( struct xt_parser *xt ) /* To find a node's child with a specific name, pass the node's children list, not the node itself! The reason you have to do this by hand: So that you can also use this function as a find-next. */ -struct xt_node *xt_find_node( struct xt_node *node, char *name ) +struct xt_node *xt_find_node( struct xt_node *node, const char *name ) { while( node ) { @@ -454,7 +454,7 @@ struct xt_node *xt_find_node( struct xt_node *node, char *name ) return node; } -char *xt_find_attr( struct xt_node *node, char *key ) +char *xt_find_attr( struct xt_node *node, const char *key ) { int i; @@ -523,7 +523,7 @@ void xt_add_child( struct xt_node *parent, struct xt_node *child ) } } -void xt_add_attr( struct xt_node *node, char *key, char *value ) +void xt_add_attr( struct xt_node *node, const char *key, const char *value ) { int i; @@ -550,7 +550,7 @@ void xt_add_attr( struct xt_node *node, char *key, char *value ) node->attr[i].value = g_strdup( value ); } -int xt_remove_attr( struct xt_node *node, char *key ) +int xt_remove_attr( struct xt_node *node, const char *key ) { int i, last; diff --git a/protocols/jabber/xmltree.h b/protocols/jabber/xmltree.h index 70850c1d..b8b61641 100644 --- a/protocols/jabber/xmltree.h +++ b/protocols/jabber/xmltree.h @@ -86,12 +86,12 @@ void xt_print( struct xt_node *node ); struct xt_node *xt_dup( struct xt_node *node ); void xt_free_node( struct xt_node *node ); void xt_free( struct xt_parser *xt ); -struct xt_node *xt_find_node( struct xt_node *node, char *name ); -char *xt_find_attr( struct xt_node *node, char *key ); +struct xt_node *xt_find_node( struct xt_node *node, const char *name ); +char *xt_find_attr( struct xt_node *node, const char *key ); struct xt_node *xt_new_node( char *name, char *text, struct xt_node *children ); void xt_add_child( struct xt_node *parent, struct xt_node *child ); -void xt_add_attr( struct xt_node *node, char *key, char *value ); -int xt_remove_attr( struct xt_node *node, char *key ); +void xt_add_attr( struct xt_node *node, const char *key, const char *value ); +int xt_remove_attr( struct xt_node *node, const char *key ); #endif -- cgit v1.2.3 From 2758cfed0abcb529975af34fdb4d2603febbf1a3 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 1 Jul 2007 16:22:42 +0100 Subject: Properly updating away state info if one resource goes down while another one's still there. Not sending offline notifications is great, but updating the away state info is even better. :-) --- protocols/jabber/presence.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'protocols') diff --git a/protocols/jabber/presence.c b/protocols/jabber/presence.c index 1310fce3..63d4f66a 100644 --- a/protocols/jabber/presence.c +++ b/protocols/jabber/presence.c @@ -30,7 +30,7 @@ xt_status jabber_pkt_presence( struct xt_node *node, gpointer data ) char *type = xt_find_attr( node, "type" ); /* NULL should mean the person is online. */ struct xt_node *c; struct jabber_buddy *bud; - int is_chat = 0; + int is_chat = 0, is_away = 0; char *s; if( !from ) @@ -46,8 +46,6 @@ xt_status jabber_pkt_presence( struct xt_node *node, gpointer data ) if( type == NULL ) { - int is_away = 0; - if( !( bud = jabber_buddy_by_jid( ic, from, GET_BUDDY_EXACT | GET_BUDDY_CREAT ) ) ) { if( set_getbool( &ic->irc->set, "debug" ) ) @@ -112,12 +110,23 @@ xt_status jabber_pkt_presence( struct xt_node *node, gpointer data ) { *s = 0; - /* Only count this as offline if there's no other resource - available anymore. */ - if( jabber_buddy_by_jid( ic, from, 0 ) == NULL ) + /* If another resource is still available, send its presence + information. */ + if( ( bud = jabber_buddy_by_jid( ic, from, 0 ) ) ) + { + if( bud->away_state && ( *bud->away_state->code == 0 || + strcmp( bud->away_state->code, "chat" ) == 0 ) ) + is_away = OPT_AWAY; + + imcb_buddy_status( ic, bud->bare_jid, OPT_LOGGED_IN | is_away, + ( is_away && bud->away_state ) ? bud->away_state->full_name : NULL, + bud->away_message ); + } + else + { + /* Otherwise, count him/her as offline now. */ imcb_buddy_status( ic, from, 0, NULL, NULL ); - /* FIXME: If this resource was not away and another resource is, - we should definitely send an update here. */ + } *s = '/'; } -- cgit v1.2.3 From b9f8b870f7b884747b747be91ce0ac797a7c6e82 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 1 Jul 2007 17:29:21 +0100 Subject: Better handling of private messages via groupchats. --- protocols/jabber/conference.c | 8 +++++--- protocols/jabber/jabber.c | 6 +++++- protocols/jabber/jabber.h | 1 + protocols/jabber/jabber_util.c | 37 ++++++++++++++++++++++++++++++++++++- protocols/jabber/message.c | 11 +++++++---- 5 files changed, 54 insertions(+), 9 deletions(-) (limited to 'protocols') diff --git a/protocols/jabber/conference.c b/protocols/jabber/conference.c index 1b392655..d8c18df7 100644 --- a/protocols/jabber/conference.c +++ b/protocols/jabber/conference.c @@ -127,7 +127,9 @@ void jabber_chat_pkt_presence( struct im_connection *ic, struct jabber_buddy *bu /* If this one wasn't set yet, this buddy just joined the chat. Slightly hackish way of finding out eh? ;-) */ - /* This is pretty messy... */ + /* This is pretty messy... Here it sets ext_jid to the real + JID of the participant. Works for non-anonymized channels. + Might break if someone joins a chat twice, though. */ for( c = node->children; ( c = xt_find_node( c, "x" ) ); c = c->next ) if( ( s = xt_find_attr( c, "xmlns" ) ) && ( strcmp( s, XMLNS_MUC_USER ) == 0 ) ) @@ -136,7 +138,7 @@ void jabber_chat_pkt_presence( struct im_connection *ic, struct jabber_buddy *bu if( ( s = xt_find_attr( c, "jid" ) ) ) { /* Yay, found what we need. :-) */ - bud->ext_jid = g_strdup( s ); + bud->ext_jid = jabber_normalize( s ); break; } } @@ -145,7 +147,7 @@ void jabber_chat_pkt_presence( struct im_connection *ic, struct jabber_buddy *bu if( bud->ext_jid == NULL ) { if( bud == jc->me ) - bud->ext_jid = g_strdup( ic->acc->user ); + bud->ext_jid = jabber_normalize( ic->acc->user ); else /* Don't want the nick to be at the end, so let's think of some slightly different notation to use diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index f09583ec..e1cef48b 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -223,12 +223,16 @@ static int jabber_buddy_msg( struct im_connection *ic, char *who, char *message, struct jabber_data *jd = ic->proto_data; struct jabber_buddy *bud; struct xt_node *node; + char *s; int st; if( g_strcasecmp( who, JABBER_XMLCONSOLE_HANDLE ) == 0 ) return jabber_write( ic, message, strlen( message ) ); - bud = jabber_buddy_by_jid( ic, who, 0 ); + if( ( s = strchr( who, '=' ) ) && jabber_chat_by_name( ic, s + 1 ) ) + bud = jabber_buddy_by_ext_jid( ic, who, 0 ); + else + bud = jabber_buddy_by_jid( ic, who, 0 ); node = xt_new_node( "body", message, NULL ); node = jabber_make_packet( "message", "chat", bud ? bud->full_jid : who, node ); diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h index 2fb01fdc..51550af8 100644 --- a/protocols/jabber/jabber.h +++ b/protocols/jabber/jabber.h @@ -194,6 +194,7 @@ typedef enum struct jabber_buddy *jabber_buddy_add( struct im_connection *ic, char *full_jid ); struct jabber_buddy *jabber_buddy_by_jid( struct im_connection *ic, char *jid, get_buddy_flags_t flags ); +struct jabber_buddy *jabber_buddy_by_ext_jid( struct im_connection *ic, char *jid, get_buddy_flags_t flags ); int jabber_buddy_remove( struct im_connection *ic, char *full_jid ); int jabber_buddy_remove_bare( struct im_connection *ic, char *bare_jid ); struct groupchat *jabber_chat_by_name( struct im_connection *ic, const char *name ); diff --git a/protocols/jabber/jabber_util.c b/protocols/jabber/jabber_util.c index 4dae3287..53f97ff0 100644 --- a/protocols/jabber/jabber_util.c +++ b/protocols/jabber/jabber_util.c @@ -319,6 +319,8 @@ struct jabber_buddy *jabber_buddy_add( struct im_connection *ic, char *full_jid_ } else { + /* Keep in mind that full_jid currently isn't really + a full JID... */ new->bare_jid = g_strdup( full_jid ); g_hash_table_insert( jd->buddies, new->bare_jid, new ); } @@ -332,7 +334,8 @@ struct jabber_buddy *jabber_buddy_add( struct im_connection *ic, char *full_jid_ else { /* Let's waste some more bytes of RAM instead of to make - memory management a total disaster here.. */ + memory management a total disaster here. And it saves + me one g_free() call in this function. :-P */ new->full_jid = full_jid; } @@ -427,6 +430,38 @@ struct jabber_buddy *jabber_buddy_by_jid( struct im_connection *ic, char *jid_, } } +/* I'm keeping a separate ext_jid attribute to save a JID that makes sense + to export to BitlBee. This is mainly for groupchats right now. It's + a bit of a hack, but I just think having the user nickname in the hostname + part of the hostmask doesn't look nice on IRC. Normally you can convert + a normal JID to ext_jid by swapping the part before and after the / and + replacing the / with a =. But there should be some stripping (@s are + allowed in Jabber nicks...). */ +struct jabber_buddy *jabber_buddy_by_ext_jid( struct im_connection *ic, char *jid_, get_buddy_flags_t flags ) +{ + struct jabber_buddy *bud; + char *s, *jid; + + jid = jabber_normalize( jid_ ); + + if( ( s = strchr( jid, '=' ) ) == NULL ) + return NULL; + + for( bud = jabber_buddy_by_jid( ic, s + 1, GET_BUDDY_FIRST ); bud; bud = bud->next ) + { + /* Hmmm, could happen if not all people in the chat are anonymized? */ + if( bud->ext_jid == NULL ) + continue; + + if( strcmp( bud->ext_jid, jid ) == 0 ) + break; + } + + g_free( jid ); + + return bud; +} + /* Remove one specific full JID from our list. Use this when a buddy goes off-line (because (s)he can still be online from a different location. XXX: See above, we should accept bare JIDs too... */ diff --git a/protocols/jabber/message.c b/protocols/jabber/message.c index 198fc3b9..52ee3a53 100644 --- a/protocols/jabber/message.c +++ b/protocols/jabber/message.c @@ -52,7 +52,10 @@ xt_status jabber_pkt_message( struct xt_node *node, gpointer data ) if( ( s = strchr( from, '/' ) ) ) { if( bud ) + { bud->last_act = time( NULL ); + from = bud->ext_jid ? : bud->bare_jid; + } else *s = 0; /* We need to generate a bare JID now. */ } @@ -80,7 +83,7 @@ xt_status jabber_pkt_message( struct xt_node *node, gpointer data ) fullmsg = g_string_append( fullmsg, body->text ); if( fullmsg->len > 0 ) - imcb_buddy_msg( ic, bud ? bud->bare_jid : from, fullmsg->str, + imcb_buddy_msg( ic, from, fullmsg->str, 0, jabber_get_timestamp( node ) ); g_string_free( fullmsg, TRUE ); @@ -89,18 +92,18 @@ xt_status jabber_pkt_message( struct xt_node *node, gpointer data ) if( xt_find_node( node->children, "composing" ) ) { bud->flags |= JBFLAG_DOES_XEP85; - imcb_buddy_typing( ic, bud ? bud->bare_jid : from, OPT_TYPING ); + imcb_buddy_typing( ic, from, OPT_TYPING ); } /* No need to send a "stopped typing" signal when there's a message. */ else if( xt_find_node( node->children, "active" ) && ( body == NULL ) ) { bud->flags |= JBFLAG_DOES_XEP85; - imcb_buddy_typing( ic, bud ? bud->bare_jid : from, 0 ); + imcb_buddy_typing( ic, from, 0 ); } else if( xt_find_node( node->children, "paused" ) ) { bud->flags |= JBFLAG_DOES_XEP85; - imcb_buddy_typing( ic, bud ? bud->bare_jid : from, OPT_THINKING ); + imcb_buddy_typing( ic, from, OPT_THINKING ); } if( s ) -- cgit v1.2.3 From 9c9b37cbfa27a038bc57624cb9001f8db019290c Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 1 Jul 2007 20:58:23 +0100 Subject: Keeping an original (not normalized) copy of the user's nickname. This fixes a bug reported by James Teh in the monster ticket #20. There's no proper garbage collection yet in the Jabber conference code, really have to do that soon. :-( --- protocols/jabber/conference.c | 7 +++++-- protocols/jabber/jabber.h | 1 + protocols/jabber/presence.c | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) (limited to 'protocols') diff --git a/protocols/jabber/conference.c b/protocols/jabber/conference.c index d8c18df7..d236f0bb 100644 --- a/protocols/jabber/conference.c +++ b/protocols/jabber/conference.c @@ -53,7 +53,10 @@ struct groupchat *jabber_chat_join( struct im_connection *ic, char *room, char * g_free( jc ); return NULL; } - g_free( roomjid ); + + /* roomjid isn't normalized yet, and we need an original version + of the nick to send a proper presence update. */ + jc->my_full_jid = roomjid; c = imcb_chat_new( ic, room ); c->data = jc; @@ -88,7 +91,7 @@ int jabber_chat_leave( struct groupchat *c, const char *reason ) node = xt_new_node( "x", NULL, NULL ); xt_add_attr( node, "xmlns", XMLNS_MUC ); - node = jabber_make_packet( "presence", "unavailable", jc->me->full_jid, node ); + node = jabber_make_packet( "presence", "unavailable", jc->my_full_jid, node ); if( !jabber_write_packet( ic, node ) ) { diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h index 51550af8..bc639fea 100644 --- a/protocols/jabber/jabber.h +++ b/protocols/jabber/jabber.h @@ -118,6 +118,7 @@ struct jabber_chat { int flags; char *name; + char *my_full_jid; /* Separate copy because of case sensitivity. */ struct jabber_buddy *me; }; diff --git a/protocols/jabber/presence.c b/protocols/jabber/presence.c index 63d4f66a..e53978ea 100644 --- a/protocols/jabber/presence.c +++ b/protocols/jabber/presence.c @@ -194,7 +194,7 @@ int presence_send_update( struct im_connection *ic ) { struct jabber_chat *jc = c->data; - xt_add_attr( node, "to", jc->me->full_jid ); + xt_add_attr( node, "to", jc->my_full_jid ); st = jabber_write_packet( ic, node ); } -- cgit v1.2.3 From c3774175d29802202afb226a2661d0c3c52fb7b1 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 2 Jul 2007 10:30:48 +0100 Subject: Cleaning up groupchats when shutting down the Jabber connection. The cleaning up of groupchats isn't done very well yet, but this will at least keep things sane. --- protocols/jabber/jabber.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'protocols') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index e1cef48b..9df1dc74 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -196,6 +196,9 @@ static void jabber_logout( struct im_connection *ic ) jabber_end_stream( ic ); + while( ic->groupchats ) + imcb_chat_free( ic->groupchats ); + if( jd->r_inpa >= 0 ) b_event_remove( jd->r_inpa ); if( jd->w_inpa >= 0 ) -- cgit v1.2.3 From 1962ac169c14c7b24e276caac0976b8983496fd5 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 2 Jul 2007 22:07:43 +0100 Subject: Fixed nick hint function to only set the nick if it's different from the current one (otherwise the dedupe function will dedupe the nick against itself). --- protocols/nogaim.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'protocols') diff --git a/protocols/nogaim.c b/protocols/nogaim.c index 4f04993c..22d82ecb 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -470,13 +470,19 @@ void imcb_buddy_nick_hint( struct im_connection *ic, char *handle, char *nick ) if( set_getbool( &ic->irc->set, "lcnicks" ) ) nick_lc( newnick ); - nick_dedupe( ic->acc, handle, newnick ); - - /* u->nick will be freed halfway the process, so it can't be - passed as an argument. */ - orig_nick = g_strdup( u->nick ); - user_rename( ic->irc, orig_nick, newnick ); - g_free( orig_nick ); + if( strcmp( u->nick, newnick ) != 0 ) + { + /* Only do this if newnick is different from the current one. + If rejoining a channel, maybe we got this nick already + (and dedupe would only add an underscore. */ + nick_dedupe( ic->acc, handle, newnick ); + + /* u->nick will be freed halfway the process, so it can't be + passed as an argument. */ + orig_nick = g_strdup( u->nick ); + user_rename( ic->irc, orig_nick, newnick ); + g_free( orig_nick ); + } } } -- cgit v1.2.3 From 5d7dc007a418be0c897000e888e747047729c756 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 2 Jul 2007 22:24:04 +0100 Subject: Stripping of unwanted characters (@ and =) in channel nicknames. --- protocols/jabber/conference.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'protocols') diff --git a/protocols/jabber/conference.c b/protocols/jabber/conference.c index d236f0bb..24b5631a 100644 --- a/protocols/jabber/conference.c +++ b/protocols/jabber/conference.c @@ -150,13 +150,23 @@ void jabber_chat_pkt_presence( struct im_connection *ic, struct jabber_buddy *bu if( bud->ext_jid == NULL ) { if( bud == jc->me ) + { bud->ext_jid = jabber_normalize( ic->acc->user ); + } else + { + int i; + /* Don't want the nick to be at the end, so let's think of some slightly different notation to use for anonymous groupchat participants in BitlBee. */ bud->ext_jid = g_strdup_printf( "%s=%s", bud->resource, bud->bare_jid ); - + + /* And strip any unwanted characters. */ + for( i = 0; bud->resource[i]; i ++ ) + if( bud->ext_jid[i] == '=' || bud->ext_jid[i] == '@' ) + bud->ext_jid[i] = '_'; + } bud->flags |= JBFLAG_IS_ANONYMOUS; } -- cgit v1.2.3 From 9da0bbfd42609f0f3864b5a16a3c1c378b7217c9 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 2 Jul 2007 23:12:03 +0100 Subject: Added (and using) jabber_chat_free() for better memory management, fixed channel name generation code in root_commands.c and fixed one memory leak in jabber_buddy_remove_bare(). --- protocols/jabber/conference.c | 21 ++++++++++++++------- protocols/jabber/jabber.c | 2 +- protocols/jabber/jabber.h | 1 + protocols/jabber/jabber_util.c | 19 +++++++++++-------- 4 files changed, 27 insertions(+), 16 deletions(-) (limited to 'protocols') diff --git a/protocols/jabber/conference.c b/protocols/jabber/conference.c index 24b5631a..f49dbd1c 100644 --- a/protocols/jabber/conference.c +++ b/protocols/jabber/conference.c @@ -64,6 +64,19 @@ struct groupchat *jabber_chat_join( struct im_connection *ic, char *room, char * return c; } +void jabber_chat_free( struct groupchat *c ) +{ + struct jabber_chat *jc = c->data; + + jabber_buddy_remove_bare( c->ic, jc->name ); + + g_free( jc->my_full_jid ); + g_free( jc->name ); + g_free( jc ); + + imcb_chat_free( c ); +} + int jabber_chat_msg( struct groupchat *c, char *message, int flags ) { struct im_connection *ic = c->ic; @@ -191,13 +204,7 @@ void jabber_chat_pkt_presence( struct im_connection *ic, struct jabber_buddy *bu if( s ) *s = '/'; if( bud == jc->me ) - { - jabber_buddy_remove_bare( ic, jc->name ); - - g_free( jc->name ); - g_free( jc ); - imcb_chat_free( chat ); - } + jabber_chat_free( chat ); } } diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 9df1dc74..9176cd68 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -197,7 +197,7 @@ static void jabber_logout( struct im_connection *ic ) jabber_end_stream( ic ); while( ic->groupchats ) - imcb_chat_free( ic->groupchats ); + jabber_chat_free( ic->groupchats ); if( jd->r_inpa >= 0 ) b_event_remove( jd->r_inpa ); diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h index bc639fea..90c1e9f6 100644 --- a/protocols/jabber/jabber.h +++ b/protocols/jabber/jabber.h @@ -219,6 +219,7 @@ gboolean sasl_supported( struct im_connection *ic ); /* conference.c */ struct groupchat *jabber_chat_join( struct im_connection *ic, char *room, char *nick, char *password ); +void jabber_chat_free( struct groupchat *c ); int jabber_chat_msg( struct groupchat *ic, char *message, int flags ); int jabber_chat_leave( struct groupchat *c, const char *reason ); void jabber_chat_pkt_presence( struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node ); diff --git a/protocols/jabber/jabber_util.c b/protocols/jabber/jabber_util.c index 53f97ff0..5b91c5ed 100644 --- a/protocols/jabber/jabber_util.c +++ b/protocols/jabber/jabber_util.c @@ -541,26 +541,31 @@ int jabber_buddy_remove( struct im_connection *ic, char *full_jid_ ) /* Remove a buddy completely; removes all resources that belong to the specified bare JID. Use this when removing someone from the contact list, for example. */ -int jabber_buddy_remove_bare( struct im_connection *ic, char *bare_jid_ ) +int jabber_buddy_remove_bare( struct im_connection *ic, char *bare_jid ) { struct jabber_data *jd = ic->proto_data; struct jabber_buddy *bud, *next; - char *bare_jid; - if( strchr( bare_jid_, '/' ) ) + if( strchr( bare_jid, '/' ) ) return 0; - bare_jid = jabber_normalize( bare_jid_ ); - - if( ( bud = g_hash_table_lookup( jd->buddies, bare_jid ) ) ) + if( ( bud = jabber_buddy_by_jid( ic, bare_jid, GET_BUDDY_FIRST ) ) ) { /* Most important: Remove the hash reference. We don't know this buddy anymore. */ g_hash_table_remove( jd->buddies, bud->bare_jid ); + g_free( bud->bare_jid ); /* Deallocate the linked list of resources. */ while( bud ) { + /* ext_jid && anonymous means that this buddy is + specific to one groupchat (the one we're + currently cleaning up) so it can be deleted + completely. */ + if( bud->ext_jid && bud->flags & JBFLAG_IS_ANONYMOUS ) + imcb_remove_buddy( ic, bud->ext_jid, NULL ); + next = bud->next; g_free( bud->ext_jid ); g_free( bud->full_jid ); @@ -569,12 +574,10 @@ int jabber_buddy_remove_bare( struct im_connection *ic, char *bare_jid_ ) bud = next; } - g_free( bare_jid ); return 1; } else { - g_free( bare_jid ); return 0; } } -- cgit v1.2.3 From c9c7ca771d3b06ab448a72bdcddfdacd5be815c0 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 11 Jul 2007 15:22:00 +0100 Subject: Fixed imc_logout() (assigning u too early). Stupid me. --- protocols/nogaim.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'protocols') diff --git a/protocols/nogaim.c b/protocols/nogaim.c index 22d82ecb..7dc777ef 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -288,7 +288,7 @@ void cancel_auto_reconnect( account_t *a ) void imc_logout( struct im_connection *ic, int allow_reconnect ) { irc_t *irc = ic->irc; - user_t *t, *u = irc->users; + user_t *t, *u; account_t *a; /* Nested calls might happen sometimes, this is probably the best @@ -305,6 +305,7 @@ void imc_logout( struct im_connection *ic, int allow_reconnect ) ic->acc->prpl->logout( ic ); b_event_remove( ic->inpa ); + u = irc->users; while( u ) { if( u->ic == ic ) -- cgit v1.2.3 From 85023c65b697d2dab932acbda31258ae5270dbe6 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 15 Jul 2007 16:47:34 +0100 Subject: Added imcb_clean_handle() to sanitize handles properly (without putting IRC-specific stuff into the Jabber module). Only using this in the MUC code for now because this only works if the IM module can somehow convert the cleaned up handle back to the original one. --- protocols/jabber/conference.c | 3 +++ protocols/nogaim.c | 33 ++++++++++++++++++++++++++++++++- protocols/nogaim.h | 1 + 3 files changed, 36 insertions(+), 1 deletion(-) (limited to 'protocols') diff --git a/protocols/jabber/conference.c b/protocols/jabber/conference.c index f49dbd1c..3fc9ee70 100644 --- a/protocols/jabber/conference.c +++ b/protocols/jabber/conference.c @@ -179,6 +179,9 @@ void jabber_chat_pkt_presence( struct im_connection *ic, struct jabber_buddy *bu for( i = 0; bud->resource[i]; i ++ ) if( bud->ext_jid[i] == '=' || bud->ext_jid[i] == '@' ) bud->ext_jid[i] = '_'; + + /* Some program-specific restrictions. */ + imcb_clean_handle( ic, bud->ext_jid ); } bud->flags |= JBFLAG_IS_ANONYMOUS; } diff --git a/protocols/nogaim.c b/protocols/nogaim.c index 7dc777ef..4b0b738b 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -98,7 +98,6 @@ void register_protocol (struct prpl *p) protocols = g_list_append(protocols, p); } - struct prpl *find_protocol(const char *name) { GList *gl; @@ -1113,3 +1112,35 @@ void imc_rem_block( struct im_connection *ic, char *handle ) ic->acc->prpl->rem_deny( ic, handle ); } + +void imcb_clean_handle( struct im_connection *ic, char *handle ) +{ + /* Accepts a handle and does whatever is necessary to make it + BitlBee-friendly. Currently this means removing everything + outside 33-127 (ASCII printable excl spaces), @ (only one + is allowed) and ! and : */ + char out[strlen(handle)+1]; + int s, d; + + s = d = 0; + while( handle[s] ) + { + if( handle[s] > ' ' && handle[s] != '!' && handle[s] != ':' && + ( handle[s] & 0x80 ) == 0 ) + { + if( handle[s] == '@' ) + { + /* See if we got an @ already? */ + out[d] = 0; + if( strchr( out, '@' ) ) + continue; + } + + out[d++] = handle[s]; + } + s ++; + } + out[d] = handle[s]; + + strcpy( handle, out ); +} diff --git a/protocols/nogaim.h b/protocols/nogaim.h index 74a63306..6aa057ff 100644 --- a/protocols/nogaim.h +++ b/protocols/nogaim.h @@ -200,6 +200,7 @@ G_MODULE_EXPORT void imcb_buddy_status( struct im_connection *ic, const char *ha /* Not implemented yet! */ G_MODULE_EXPORT void imcb_buddy_times( struct im_connection *ic, const char *handle, time_t login, time_t idle ); G_MODULE_EXPORT void imcb_buddy_msg( struct im_connection *ic, char *handle, char *msg, u_int32_t flags, time_t sent_at ); G_MODULE_EXPORT void imcb_buddy_typing( struct im_connection *ic, char *handle, u_int32_t flags ); +G_MODULE_EXPORT void imcb_clean_handle( struct im_connection *ic, char *handle ); /* Groupchats */ G_MODULE_EXPORT void imcb_chat_invited( struct im_connection *ic, char *handle, char *who, char *msg, GList *data ); -- cgit v1.2.3 From 1baaef858136cd3a4799b3ccf1d9961534e0017c Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 30 Jul 2007 20:12:06 +0100 Subject: Added jabber_error_parse() and using it for both stream- and stanza (only presence so far) errors. --- protocols/jabber/io.c | 31 ++++++++----------------------- protocols/jabber/jabber.h | 7 +++++++ protocols/jabber/jabber_util.c | 35 +++++++++++++++++++++++++++++++++++ protocols/jabber/presence.c | 12 +++++++++++- 4 files changed, 61 insertions(+), 24 deletions(-) (limited to 'protocols') diff --git a/protocols/jabber/io.c b/protocols/jabber/io.c index edde5a8d..cf71ff87 100644 --- a/protocols/jabber/io.c +++ b/protocols/jabber/io.c @@ -435,50 +435,35 @@ static xt_status jabber_pkt_proceed_tls( struct xt_node *node, gpointer data ) static xt_status jabber_pkt_stream_error( struct xt_node *node, gpointer data ) { struct im_connection *ic = data; - struct xt_node *c; - char *s, *type = NULL, *text = NULL; int allow_reconnect = TRUE; + struct jabber_error *err; - for( c = node->children; c; c = c->next ) - { - if( !( s = xt_find_attr( c, "xmlns" ) ) || - strcmp( s, XMLNS_STREAM_ERROR ) != 0 ) - continue; - - if( strcmp( c->name, "text" ) != 0 ) - { - type = c->name; - } - /* Only use the text if it doesn't have an xml:lang attribute, - if it's empty or if it's set to something English. */ - else if( !( s = xt_find_attr( c, "xml:lang" ) ) || - !*s || strncmp( s, "en", 2 ) == 0 ) - { - text = c->text; - } - } + err = jabber_error_parse( node, XMLNS_STREAM_ERROR ); /* Tssk... */ - if( type == NULL ) + if( err->code == NULL ) { imcb_error( ic, "Unknown stream error reported by server" ); imc_logout( ic, allow_reconnect ); + jabber_error_free( err ); return XT_ABORT; } /* We know that this is a fatal error. If it's a "conflict" error, we should turn off auto-reconnect to make sure we won't get some nasty infinite loop! */ - if( strcmp( type, "conflict" ) == 0 ) + if( strcmp( err->code, "conflict" ) == 0 ) { imcb_error( ic, "Account and resource used from a different location" ); allow_reconnect = FALSE; } else { - imcb_error( ic, "Stream error: %s%s%s", type, text ? ": " : "", text ? text : "" ); + imcb_error( ic, "Stream error: %s%s%s", err->code, err->text ? ": " : "", + err->text ? err->text : "" ); } + jabber_error_free( err ); imc_logout( ic, allow_reconnect ); return XT_ABORT; diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h index 90c1e9f6..7af7f98e 100644 --- a/protocols/jabber/jabber.h +++ b/protocols/jabber/jabber.h @@ -193,6 +193,11 @@ typedef enum GET_BUDDY_FIRST = 4, /* No selection, simply get the first resource for this JID. */ } get_buddy_flags_t; +struct jabber_error +{ + char *code, *text, *type; +}; + struct jabber_buddy *jabber_buddy_add( struct im_connection *ic, char *full_jid ); struct jabber_buddy *jabber_buddy_by_jid( struct im_connection *ic, char *jid, get_buddy_flags_t flags ); struct jabber_buddy *jabber_buddy_by_ext_jid( struct im_connection *ic, char *jid, get_buddy_flags_t flags ); @@ -200,6 +205,8 @@ int jabber_buddy_remove( struct im_connection *ic, char *full_jid ); int jabber_buddy_remove_bare( struct im_connection *ic, char *bare_jid ); struct groupchat *jabber_chat_by_name( struct im_connection *ic, const char *name ); time_t jabber_get_timestamp( struct xt_node *xt ); +struct jabber_error *jabber_error_parse( struct xt_node *node, char *xmlns ); +void jabber_error_free( struct jabber_error *err ); extern const struct jabber_away_state jabber_away_state_list[]; diff --git a/protocols/jabber/jabber_util.c b/protocols/jabber/jabber_util.c index 5b91c5ed..56491c4f 100644 --- a/protocols/jabber/jabber_util.c +++ b/protocols/jabber/jabber_util.c @@ -647,3 +647,38 @@ time_t jabber_get_timestamp( struct xt_node *xt ) return res; } + +struct jabber_error *jabber_error_parse( struct xt_node *node, char *xmlns ) +{ + struct jabber_error *err = g_new0( struct jabber_error, 1 ); + struct xt_node *c; + char *s; + + err->type = xt_find_attr( node, "type" ); + + for( c = node->children; c; c = c->next ) + { + if( !( s = xt_find_attr( c, "xmlns" ) ) || + strcmp( s, xmlns ) != 0 ) + continue; + + if( strcmp( c->name, "text" ) != 0 ) + { + err->code = c->name; + } + /* Only use the text if it doesn't have an xml:lang attribute, + if it's empty or if it's set to something English. */ + else if( !( s = xt_find_attr( c, "xml:lang" ) ) || + !*s || strncmp( s, "en", 2 ) == 0 ) + { + err->text = c->text; + } + } + + return err; +} + +void jabber_error_free( struct jabber_error *err ) +{ + g_free( err ); +} diff --git a/protocols/jabber/presence.c b/protocols/jabber/presence.c index e53978ea..cbfcedae 100644 --- a/protocols/jabber/presence.c +++ b/protocols/jabber/presence.c @@ -157,7 +157,17 @@ xt_status jabber_pkt_presence( struct xt_node *node, gpointer data ) } else if( strcmp( type, "error" ) == 0 ) { - /* What to do with it? */ + struct jabber_error *err; + + if( ( c = xt_find_node( node->children, "error" ) ) ) + { + err = jabber_error_parse( c, XMLNS_STANZA_ERROR ); + imcb_error( ic, "Stanza (%s) error: %s%s%s", node->name, + err->code, err->text ? ": " : "", + err->text ? err->text : "" ); + jabber_error_free( err ); + } + /* What else to do with it? */ } else { -- cgit v1.2.3 From 82135c7178b6379f35741991f6c06bb308143194 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 8 Aug 2007 10:20:57 +0100 Subject: Not trying to handle typing notifications from unknown buddies anymore (NULL pointer dereference). --- protocols/jabber/message.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'protocols') diff --git a/protocols/jabber/message.c b/protocols/jabber/message.c index 52ee3a53..fab62a91 100644 --- a/protocols/jabber/message.c +++ b/protocols/jabber/message.c @@ -89,7 +89,11 @@ xt_status jabber_pkt_message( struct xt_node *node, gpointer data ) g_string_free( fullmsg, TRUE ); /* Handling of incoming typing notifications. */ - if( xt_find_node( node->children, "composing" ) ) + if( bud == NULL ) + { + /* Can't handle these for unknown buddies. */ + } + else if( xt_find_node( node->children, "composing" ) ) { bud->flags |= JBFLAG_DOES_XEP85; imcb_buddy_typing( ic, from, OPT_TYPING ); -- cgit v1.2.3 From a6df0b5d21370549328c7929a008abb68f2ed4db Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 14 Nov 2007 23:29:43 +0000 Subject: Added "xmlconsole" setting so it can be enabled at login time already. --- protocols/jabber/jabber.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'protocols') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 9176cd68..ab26efc9 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -54,6 +54,9 @@ static void jabber_init( account_t *acc ) s = set_add( &acc->set, "tls", "try", set_eval_tls, acc ); s->flags |= ACC_SET_OFFLINE_ONLY; + + s = set_add( &acc->set, "xmlconsole", "false", set_eval_bool, acc ); + s->flags |= ACC_SET_OFFLINE_ONLY; } static void jabber_login( account_t *acc ) @@ -188,6 +191,14 @@ static void jabber_login( account_t *acc ) imcb_error( ic, "Could not connect to server" ); imc_logout( ic, TRUE ); } + + if( set_getbool( &acc->set, "xmlconsole" ) ) + { + jd->flags |= JFLAG_XMLCONSOLE; + /* Shouldn't really do this at this stage already, maybe. But + I think this shouldn't break anything. */ + imcb_add_buddy( ic, JABBER_XMLCONSOLE_HANDLE, NULL ); + } } static void jabber_logout( struct im_connection *ic ) -- cgit v1.2.3 From 50e1776cb0c76b3328d458dd8a1bfb379b6b0e43 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 19 Nov 2007 22:23:58 +0000 Subject: Merging /TOPIC code from Miklos Vajna. Untested, because I still have to implement the Jabber hooks. --- protocols/nogaim.c | 24 ++++++++++++++++++++++++ protocols/nogaim.h | 10 ++++++++++ 2 files changed, 34 insertions(+) (limited to 'protocols') diff --git a/protocols/nogaim.c b/protocols/nogaim.c index d1aceb1a..2ad8a049 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -759,6 +759,29 @@ void imcb_chat_msg( struct groupchat *c, char *who, char *msg, u_int32_t flags, g_free( wrapped ); } +void imcb_chat_topic( struct groupchat *c, char *who, char *topic ) +{ + struct im_connection *ic = c->ic; + user_t *u = NULL; + + if( who == NULL) + u = user_find( ic, ic->irc->mynick ); + else if( g_strcasecmp( who, ic->acc->user ) == 0 ) + u = user_find( ic, ic->irc->nick ); + else + u = user_findhandle( ic, who ); + + if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) || + ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) ) + strip_html( topic ); + + g_free( c->topic ); + c->topic = g_strdup( topic ); + + if( c->joined && u ) + irc_write( ic->irc, ":%s!%s@%s TOPIC %s :%s", u->nick, u->user, u->host, c->channel, topic ); +} + struct groupchat *imcb_chat_new( struct im_connection *ic, char *handle ) { struct groupchat *c; @@ -776,6 +799,7 @@ struct groupchat *imcb_chat_new( struct im_connection *ic, char *handle ) c->ic = ic; c->title = g_strdup( handle ); c->channel = g_strdup_printf( "&chat_%03d", ic->irc->c_id++ ); + c->topic = g_strdup_printf( "%s :BitlBee groupchat: \"%s\". Please keep in mind that root-commands won't work here. Have fun!", c->channel, c->title ); if( set_getbool( &ic->irc->set, "debug" ) ) imcb_log( ic, "Creating new conversation: (id=0x%x,handle=%s)", (int) c, handle ); diff --git a/protocols/nogaim.h b/protocols/nogaim.h index 5bf6d922..7c643cd3 100644 --- a/protocols/nogaim.h +++ b/protocols/nogaim.h @@ -109,6 +109,9 @@ struct groupchat { /* The title variable contains the ID you gave when you created the * chat using imcb_chat_new(). */ char *title; + /* Use imcb_chat_topic() to change this variable otherwise the user + * won't notice the topic change. */ + char *topic; char joined; /* This is for you, you can add your own structure here to extend this * structure for your protocol's needs. */ @@ -211,6 +214,11 @@ struct prpl { * not implement this. */ struct groupchat * (* chat_join) (struct im_connection *, char *room, char *nick, char *password); + /* Change the topic, if supported. Note that BitlBee expects the IM + server to confirm the topic change with a regular topic change + event. If it doesn't do that, you have to fake it to make it + visible to the user. */ + void (* chat_topic) (struct groupchat *, char *message); /* You can tell what away states your protocol supports, so that * BitlBee will try to map the IRC away reasons to them, or use @@ -292,6 +300,8 @@ G_MODULE_EXPORT void imcb_chat_add_buddy( struct groupchat *b, char *handle ); G_MODULE_EXPORT void imcb_chat_remove_buddy( struct groupchat *b, char *handle, char *reason ); /* To tell BitlBee 'who' said 'msg' in 'c'. 'flags' and 'sent_at' can be 0. */ G_MODULE_EXPORT void imcb_chat_msg( struct groupchat *c, char *who, char *msg, u_int32_t flags, time_t sent_at ); +/* To tell BitlBee 'who' changed the topic of 'c' to 'topic'. */ +G_MODULE_EXPORT void imcb_chat_topic( struct groupchat *c, char *who, char *topic ); G_MODULE_EXPORT void imcb_chat_free( struct groupchat *c ); /* Actions, or whatever. */ -- cgit v1.2.3 From ef5c1855b406e462fb8b90b517f1672a47bcc4b5 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 19 Nov 2007 23:14:39 +0000 Subject: Added Jabber groupchat topic support. --- protocols/jabber/conference.c | 28 ++++++++++++++++++++++++++++ protocols/jabber/jabber.c | 7 +++++++ protocols/jabber/jabber.h | 1 + protocols/jabber/sasl.c | 2 +- protocols/nogaim.c | 6 +++--- protocols/nogaim.h | 4 ++-- 6 files changed, 42 insertions(+), 6 deletions(-) (limited to 'protocols') diff --git a/protocols/jabber/conference.c b/protocols/jabber/conference.c index 3fc9ee70..008bbe63 100644 --- a/protocols/jabber/conference.c +++ b/protocols/jabber/conference.c @@ -96,6 +96,25 @@ int jabber_chat_msg( struct groupchat *c, char *message, int flags ) return 1; } +int jabber_chat_topic( struct groupchat *c, char *topic ) +{ + struct im_connection *ic = c->ic; + struct jabber_chat *jc = c->data; + struct xt_node *node; + + node = xt_new_node( "subject", topic, NULL ); + node = jabber_make_packet( "message", "groupchat", jc->name, node ); + + if( !jabber_write_packet( ic, node ) ) + { + xt_free_node( node ); + return 0; + } + xt_free_node( node ); + + return 1; +} + int jabber_chat_leave( struct groupchat *c, const char *reason ) { struct im_connection *ic = c->ic; @@ -213,6 +232,7 @@ void jabber_chat_pkt_presence( struct im_connection *ic, struct jabber_buddy *bu void jabber_chat_pkt_message( struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node ) { + struct xt_node *subject = xt_find_node( node->children, "subject" ); struct xt_node *body = xt_find_node( node->children, "body" ); struct groupchat *chat; char *s; @@ -236,6 +256,14 @@ void jabber_chat_pkt_message( struct im_connection *ic, struct jabber_buddy *bud return; } + if( subject ) + { + s = strchr( bud->ext_jid, '/' ); + if( s ) *s = 0; + imcb_chat_topic( chat, bud->ext_jid, subject->text_len > 0 ? + subject->text : NULL, jabber_get_timestamp( node ) ); + if( s ) *s = '/'; + } if( body && body->text_len > 0 ) { s = strchr( bud->ext_jid, '/' ); diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index ab26efc9..e7be63fd 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -384,6 +384,12 @@ static void jabber_chat_msg_( struct groupchat *c, char *message, int flags ) jabber_chat_msg( c, message, flags ); } +static void jabber_chat_topic_( struct groupchat *c, char *topic ) +{ + if( c && topic ) + jabber_chat_topic( c, topic ); +} + static void jabber_chat_leave_( struct groupchat *c ) { if( c ) @@ -460,6 +466,7 @@ void jabber_initmodule() ret->add_buddy = jabber_add_buddy; ret->remove_buddy = jabber_remove_buddy; ret->chat_msg = jabber_chat_msg_; + ret->chat_topic = jabber_chat_topic_; // ret->chat_invite = jabber_chat_invite; ret->chat_leave = jabber_chat_leave_; ret->chat_join = jabber_chat_join_; diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h index 7af7f98e..e26c3899 100644 --- a/protocols/jabber/jabber.h +++ b/protocols/jabber/jabber.h @@ -228,6 +228,7 @@ gboolean sasl_supported( struct im_connection *ic ); struct groupchat *jabber_chat_join( struct im_connection *ic, char *room, char *nick, char *password ); void jabber_chat_free( struct groupchat *c ); int jabber_chat_msg( struct groupchat *ic, char *message, int flags ); +int jabber_chat_topic( struct groupchat *c, char *topic ); int jabber_chat_leave( struct groupchat *c, const char *reason ); void jabber_chat_pkt_presence( struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node ); void jabber_chat_pkt_message( struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node ); diff --git a/protocols/jabber/sasl.c b/protocols/jabber/sasl.c index 6eee37b3..87059051 100644 --- a/protocols/jabber/sasl.c +++ b/protocols/jabber/sasl.c @@ -331,5 +331,5 @@ gboolean sasl_supported( struct im_connection *ic ) { struct jabber_data *jd = ic->proto_data; - return ( (void*) ( jd->xt && jd->xt->root && xt_find_attr( jd->xt->root, "version" ) ) ) != NULL; + return ( jd->xt && jd->xt->root && xt_find_attr( jd->xt->root, "version" ) ) != 0; } diff --git a/protocols/nogaim.c b/protocols/nogaim.c index 2ad8a049..e0f04c0b 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -759,15 +759,15 @@ void imcb_chat_msg( struct groupchat *c, char *who, char *msg, u_int32_t flags, g_free( wrapped ); } -void imcb_chat_topic( struct groupchat *c, char *who, char *topic ) +void imcb_chat_topic( struct groupchat *c, char *who, char *topic, time_t set_at ) { struct im_connection *ic = c->ic; user_t *u = NULL; if( who == NULL) - u = user_find( ic, ic->irc->mynick ); + u = user_find( ic->irc, ic->irc->mynick ); else if( g_strcasecmp( who, ic->acc->user ) == 0 ) - u = user_find( ic, ic->irc->nick ); + u = user_find( ic->irc, ic->irc->nick ); else u = user_findhandle( ic, who ); diff --git a/protocols/nogaim.h b/protocols/nogaim.h index 7c643cd3..adee5e33 100644 --- a/protocols/nogaim.h +++ b/protocols/nogaim.h @@ -218,7 +218,7 @@ struct prpl { server to confirm the topic change with a regular topic change event. If it doesn't do that, you have to fake it to make it visible to the user. */ - void (* chat_topic) (struct groupchat *, char *message); + void (* chat_topic) (struct groupchat *, char *topic); /* You can tell what away states your protocol supports, so that * BitlBee will try to map the IRC away reasons to them, or use @@ -301,7 +301,7 @@ G_MODULE_EXPORT void imcb_chat_remove_buddy( struct groupchat *b, char *handle, /* To tell BitlBee 'who' said 'msg' in 'c'. 'flags' and 'sent_at' can be 0. */ G_MODULE_EXPORT void imcb_chat_msg( struct groupchat *c, char *who, char *msg, u_int32_t flags, time_t sent_at ); /* To tell BitlBee 'who' changed the topic of 'c' to 'topic'. */ -G_MODULE_EXPORT void imcb_chat_topic( struct groupchat *c, char *who, char *topic ); +G_MODULE_EXPORT void imcb_chat_topic( struct groupchat *c, char *who, char *topic, time_t set_at ); G_MODULE_EXPORT void imcb_chat_free( struct groupchat *c ); /* Actions, or whatever. */ -- cgit v1.2.3