aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilmer van der Gaast <wilmer@gaast.net>2006-10-10 14:05:42 +0200
committerWilmer van der Gaast <wilmer@gaast.net>2006-10-10 14:05:42 +0200
commita21a8ac4fbd5a234bc8d31d9d487c74a81383c8a (patch)
treed8445a5409dfe11de56433f59cfa063952734d86
parent6a1128d1333cf79f1ef9fb1f55b1b8fec67caf2a (diff)
Added resource selection (based on priority or time of last message) to
budd_by_jid(), added a full_jid property to easily address that resource without having to rebuild the full JID every time and implemented typing notification shite.
-rw-r--r--protocols/jabber/jabber.c72
-rw-r--r--protocols/jabber/jabber.h20
-rw-r--r--protocols/jabber/jabber_util.c27
-rw-r--r--protocols/jabber/message.c35
-rw-r--r--protocols/jabber/presence.c27
5 files changed, 149 insertions, 32 deletions
diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c
index 266022ba..91f88350 100644
--- a/protocols/jabber/jabber.c
+++ b/protocols/jabber/jabber.c
@@ -44,6 +44,8 @@ static void jabber_acc_init( account_t *acc )
s = set_add( &acc->set, "resource", "BitlBee", NULL, acc );
s->flags |= ACC_SET_OFFLINE_ONLY;
+ s = set_add( &acc->set, "resource_select", "priority", NULL, acc );
+
s = set_add( &acc->set, "server", NULL, set_eval_account, acc );
s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY;
@@ -136,19 +138,33 @@ static void jabber_close( struct gaim_connection *gc )
static int jabber_send_im( struct gaim_connection *gc, char *who, char *message, int len, int away )
{
+ struct jabber_data *jd = gc->proto_data;
+ struct jabber_buddy *bud;
struct xt_node *node;
int st;
- /*
- event = xt_new_node( "active", NULL, NULL );
- xt_add_attr( event, "xlmns", "http://jabber.org/protocol/chatstates" );
-
- event = xt_new_node( "x", NULL, xt_new_node( "composing", NULL, NULL ) );
- xt_add_attr( event, "xmlns", "jabber:x:event" );
- */
+ bud = jabber_buddy_by_jid( gc, who );
node = xt_new_node( "body", message, NULL );
- node = jabber_make_packet( "message", "chat", who, node );
+ node = jabber_make_packet( "message", "chat", bud->full_jid, node );
+
+ if( ( jd->flags & JFLAG_WANT_TYPING ) &&
+ ( ( bud->flags & JBFLAG_DOES_JEP85 ) ||
+ !( bud->flags & JBFLAG_PROBED_JEP85 ) ) )
+ {
+ struct xt_node *act;
+
+ /* If the user likes typing notification and if we don't know
+ (and didn't probe before) if this resource supports JEP85,
+ include a probe in this packet now. */
+ act = xt_new_node( "active", NULL, NULL );
+ xt_add_attr( act, "xmlns", "http://jabber.org/protocol/chatstates" );
+ xt_add_child( node, act );
+
+ /* Just make sure we do this only once. */
+ bud->flags |= JBFLAG_PROBED_JEP85;
+ }
+
st = jabber_write_packet( gc, node );
xt_free_node( node );
@@ -228,6 +244,44 @@ static void jabber_keepalive( struct gaim_connection *gc )
jabber_cache_clean( gc );
}
+static int jabber_send_typing( struct gaim_connection *gc, char *who, int typing )
+{
+ struct jabber_data *jd = gc->proto_data;
+ struct jabber_buddy *bud;
+
+ /* Enable typing notification related code from now. */
+ jd->flags |= JFLAG_WANT_TYPING;
+
+ bud = jabber_buddy_by_jid( gc, who );
+ if( bud->flags & JBFLAG_DOES_JEP85 )
+ {
+ /* We're only allowed to send this stuff if we know the other
+ side supports it. */
+
+ struct xt_node *node;
+ char *type;
+ int st;
+
+ if( typing == 0 )
+ type = "active";
+ else if( typing == 2 )
+ type = "paused";
+ else /* if( typing == 1 ) */
+ type = "composing";
+
+ node = xt_new_node( type, NULL, NULL );
+ xt_add_attr( node, "xmlns", "http://jabber.org/protocol/chatstates" );
+ node = jabber_make_packet( "message", "chat", bud->full_jid, node );
+
+ st = jabber_write_packet( gc, node );
+ xt_free_node( node );
+
+ return st;
+ }
+
+ return 1;
+}
+
void jabber_init()
{
struct prpl *ret = g_new0( struct prpl, 1 );
@@ -249,7 +303,7 @@ void jabber_init()
// ret->chat_leave = jabber_chat_leave;
// ret->chat_open = jabber_chat_open;
ret->keepalive = jabber_keepalive;
-// ret->send_typing = jabber_send_typing;
+ ret->send_typing = jabber_send_typing;
ret->handle_cmp = g_strcasecmp;
register_protocol( ret );
diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h
index 450c8be7..3535ecc5 100644
--- a/protocols/jabber/jabber.h
+++ b/protocols/jabber/jabber.h
@@ -31,13 +31,26 @@
typedef enum
{
- JFLAG_STREAM_STARTED = 1, /* Set when we detected the beginning of the stream and want to do auth. */
+ JFLAG_STREAM_STARTED = 1, /* Set when we detected the beginning of the stream
+ and want to do auth. */
JFLAG_AUTHENTICATED = 2, /* Set when we're successfully authenticatd. */
- JFLAG_STREAM_RESTART = 4, /* Set when we want to restart the stream (after SASL or TLS). */
- JFLAG_WAIT_SESSION = 8, /* Set if we sent a <session> tag and need a reply before we continue. */
+ JFLAG_STREAM_RESTART = 4, /* Set when we want to restart the stream (after
+ SASL or TLS). */
+ JFLAG_WAIT_SESSION = 8, /* Set if we sent a <session> tag and need a reply
+ before we continue. */
JFLAG_WAIT_BIND = 16, /* ... for <bind> tag. */
+ JFLAG_WANT_TYPING = 32, /* Set if we ever sent a typing notification, this
+ activates all JEP-85 related code. */
} jabber_flags_t;
+typedef enum
+{
+ JBFLAG_PROBED_JEP85 = 1, /* Set this when we sent our probe packet to make
+ sure it gets sent only once. */
+ JBFLAG_DOES_JEP85 = 2, /* Set this when the resource seems to support
+ JEP85 (typing notification shite). */
+} jabber_buddy_flag_t;
+
struct jabber_data
{
struct gaim_connection *gc;
@@ -80,6 +93,7 @@ struct jabber_cache_entry
struct jabber_buddy
{
char *handle;
+ char *full_jid;
char *resource;
int priority;
diff --git a/protocols/jabber/jabber_util.c b/protocols/jabber/jabber_util.c
index f4cd40d4..357743d3 100644
--- a/protocols/jabber/jabber_util.c
+++ b/protocols/jabber/jabber_util.c
@@ -246,7 +246,8 @@ struct jabber_buddy *jabber_buddy_add( struct gaim_connection *gc, char *full_ji
}
*s = '/';
- new->resource = g_strdup( s + 1 );
+ new->full_jid = g_strdup( full_jid );
+ new->resource = strchr( new->full_jid, '/' ) + 1;
return new;
}
@@ -267,8 +268,24 @@ struct jabber_buddy *jabber_buddy_by_jid( struct gaim_connection *gc, char *jid
}
else
{
- /* TODO: Add selection. */
- return g_hash_table_lookup( jd->buddies, jid );
+ struct jabber_buddy *best_prio, *best_time;
+ char *set;
+
+ best_prio = best_time = bud = g_hash_table_lookup( jd->buddies, jid );
+ for( ; bud; bud = bud->next )
+ {
+ if( bud->priority > best_prio->priority )
+ best_prio = bud;
+ if( bud->last_act > best_time->last_act )
+ best_time = bud;
+ }
+
+ if( ( set = set_getstr( &gc->acc->set, "resource_select" ) ) == NULL )
+ return NULL;
+ else if( strcmp( set, "activity" ) == 0 )
+ return best_time;
+ else /* if( strcmp( set, "priority" ) == 0 ) */
+ return best_prio;
}
*s = '/';
@@ -294,7 +311,7 @@ int jabber_buddy_remove( struct gaim_connection *gc, char *full_jid )
{
g_hash_table_remove( jd->buddies, bud->handle );
g_free( bud->handle );
- g_free( bud->resource );
+ g_free( bud->full_jid );
g_free( bud->away_message );
g_free( bud );
}
@@ -313,7 +330,7 @@ int jabber_buddy_remove( struct gaim_connection *gc, char *full_jid )
item, because we're removing the first. */
g_hash_table_replace( jd->buddies, bi->handle, bi->next );
- g_free( bi->resource );
+ g_free( bi->full_jid );
g_free( bi->away_message );
g_free( bi );
}
diff --git a/protocols/jabber/message.c b/protocols/jabber/message.c
index b41522fd..fea728e3 100644
--- a/protocols/jabber/message.c
+++ b/protocols/jabber/message.c
@@ -28,27 +28,42 @@ xt_status jabber_pkt_message( struct xt_node *node, gpointer data )
struct gaim_connection *gc = data;
char *from = xt_find_attr( node, "from" );
char *type = xt_find_attr( node, "type" );
- struct xt_node *msg = xt_find_node( node->children, "body" );
+ struct xt_node *body = xt_find_node( node->children, "body" );
- if( !type || !msg )
+ if( !type )
return XT_HANDLED; /* Grmbl... FIXME */
if( strcmp( type, "chat" ) == 0 )
{
- char *s;
+ struct jabber_buddy *bud = NULL;
- s = strchr( from, '/' );
- if( s )
- *s = 0;
+ if( strchr( from, '/' ) == NULL )
+ {
+ /* It just shouldn't happen. */
+ hide_login_progress( gc, "Received message packet from bare JID" );
+ signoff( gc );
+ return XT_ABORT;
+ }
- serv_got_im( gc, from, msg->text, 0, 0, 0 );
+ bud = jabber_buddy_by_jid( gc, from );
+ bud->last_act = time( NULL );
- if( s )
- *s = '/';
+ if( body ) /* Could be just a typing notification. */
+ serv_got_im( gc, bud->handle, body->text, 0, 0, 0 );
+
+ if( xt_find_node( node->children, "composing" ) )
+ {
+ bud->flags |= JBFLAG_DOES_JEP85;
+ serv_got_typing( gc, bud->handle, 0, 1 );
+ }
+ else if( xt_find_node( node->children, "active" ) )
+ {
+ bud->flags |= JBFLAG_DOES_JEP85;
+ }
}
else
{
- printf( "Received MSG from %s: %s\n", from, msg ? msg->text : "<null>" );
+ printf( "Received MSG from %s:\n", from );
xt_print( node );
}
diff --git a/protocols/jabber/presence.c b/protocols/jabber/presence.c
index 86bdcb1d..3a682e52 100644
--- a/protocols/jabber/presence.c
+++ b/protocols/jabber/presence.c
@@ -29,13 +29,19 @@ xt_status jabber_pkt_presence( struct xt_node *node, gpointer data )
char *from = xt_find_attr( node, "from" );
char *type = xt_find_attr( node, "type" ); /* NULL should mean the person is online. */
struct xt_node *c;
+ struct jabber_buddy *bud;
if( !from )
return XT_HANDLED;
if( type == NULL )
{
- struct jabber_buddy *bud;
+ if( strchr( from, '/' ) == NULL )
+ {
+ char *s = xt_to_string( node );
+ serv_got_crap( gc, "WARNING: Ignoring presence tag with bare JID: %s\n", s );
+ g_free( s );
+ }
if( !( bud = jabber_buddy_by_jid( gc, from ) ) )
{
@@ -51,23 +57,34 @@ xt_status jabber_pkt_presence( struct xt_node *node, gpointer data )
if( ( c = xt_find_node( node->children, "show" ) ) && c->text_len > 0 )
bud->away_state = (void*) jabber_away_state_by_code( c->text );
else
+ {
bud->away_state = NULL;
+ /* Let's only set last_act if there's *no* away state,
+ since it could be some auto-away thingy. */
+ bud->last_act = time( NULL );
+ }
if( ( c = xt_find_node( node->children, "priority" ) ) && c->text_len > 0 )
bud->priority = atoi( c->text );
else
bud->priority = 0;
- serv_got_update( gc, bud->handle, 1, 0, 0, 0, 0, 0 );
+ serv_got_update( gc, bud->handle, 1, 0, 0, 0,
+ bud->away_state ? UC_UNAVAILABLE : 0, 0 );
}
else if( strcmp( type, "unavailable" ) == 0 )
{
char *s;
- jabber_buddy_remove( gc, from );
+ if( ( s = strchr( from, '/' ) ) == NULL )
+ {
+ char *s = xt_to_string( node );
+ serv_got_crap( gc, "WARNING: Ignoring presence tag with bare JID: %s\n", s );
+ g_free( s );
+ }
- if( ( s = strchr( from, '/' ) ) )
- *s = 0;
+ jabber_buddy_remove( gc, from );
+ *s = 0;
/* Only count this as offline if there's no other resource
available anymore. */