Example #1
0
File: iq.c Project: shiplu/bitlbee
xt_status jabber_iq_parse_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
{
	struct xt_node *c;
	struct jabber_buddy *bud;
	char *feature, *xmlns, *from;

	if( !( from = xt_find_attr( node, "from" ) ) ||
	    !( c = xt_find_node( node->children, "query" ) ) ||
	    !( xmlns = xt_find_attr( c, "xmlns" ) ) ||
	    !( strcmp( xmlns, XMLNS_DISCO_INFO ) == 0 ) )
	{
		imcb_log( ic, "WARNING: Received incomplete IQ-result packet for discover" );
		return XT_HANDLED;
	}
	if( ( bud = jabber_buddy_by_jid( ic, from, 0 ) ) == NULL )
	{
		/* Who cares about the unknown... */
		imcb_log( ic, "Couldn't find buddy: %s", from );
		return XT_HANDLED;
	}
	
	c = c->children;
	while( ( c = xt_find_node( c, "feature" ) ) )
	{
		feature = xt_find_attr( c, "var" );
		if( feature )
			bud->features = g_slist_append( bud->features, g_strdup( feature ) );
		c = c->next;
	}

	return XT_HANDLED;
}
Example #2
0
File: iq.c Project: shiplu/bitlbee
static xt_status jabber_iq_version_response( struct im_connection *ic,
	struct xt_node *node, struct xt_node *orig )
{
	struct xt_node *query;
	GString *rets;
	char *s;
	char *ret[2] = {};
	bee_user_t *bu;
	struct jabber_buddy *bud = NULL;
	
	if( ( s = xt_find_attr( node, "from" ) ) &&
	    ( bud = jabber_buddy_by_jid( ic, s, 0 ) ) &&
	    ( query = xt_find_node( node->children, "query" ) ) &&
	    ( bu = bee_user_by_handle( ic->bee, ic, bud->bare_jid ) ) )
	{
		rets = g_string_new( "Resource " );
		g_string_append( rets, bud->resource );
	}
	else
		return XT_HANDLED;
	
	for( query = query->children; query; query = query->next )
		if( query->text_len > 0 )
			g_string_append_printf( rets, " %s: %s,", query->name, query->text );
	
	g_string_truncate( rets, rets->len - 1 );
	ret[0] = rets->str;
	imcb_buddy_action_response( bu, "VERSION", ret, NULL );
	g_string_free( rets, TRUE );
	
	return XT_HANDLED;
}
Example #3
0
File: iq.c Project: shiplu/bitlbee
xt_status jabber_iq_query_features( struct im_connection *ic, char *bare_jid )
{
	struct xt_node *node, *query;
	struct jabber_buddy *bud;
	
	if( ( bud = jabber_buddy_by_jid( ic, bare_jid , 0 ) ) == NULL )
	{
		/* Who cares about the unknown... */
		imcb_log( ic, "Couldn't find buddy: %s", bare_jid);
		return XT_HANDLED;
	}
	
	if( bud->features ) /* been here already */
		return XT_HANDLED;
	
	node = xt_new_node( "query", NULL, NULL );
	xt_add_attr( node, "xmlns", XMLNS_DISCO_INFO );
	
	if( !( query = jabber_make_packet( "iq", "get", bare_jid, node ) ) )
	{
		imcb_log( ic, "WARNING: Couldn't generate feature query" );
		xt_free_node( node );
		return XT_HANDLED;
	}

	jabber_cache_add( ic, query, jabber_iq_parse_features );

	return jabber_write_packet( ic, query ) ? XT_HANDLED : XT_ABORT;
}
Example #4
0
File: jabber.c Project: AlD/bitlbee
static int jabber_buddy_msg( struct im_connection *ic, char *who, char *message, int flags )
{
	struct jabber_data *jd = ic->proto_data;
	struct jabber_buddy *bud;
	struct xt_node *node;
	char *s;
	int st;
	
	if( g_strcasecmp( who, JABBER_XMLCONSOLE_HANDLE ) == 0 )
		return jabber_write( ic, message, strlen( message ) );
	
	if( g_strcasecmp( who, JABBER_OAUTH_HANDLE ) == 0 &&
	    !( jd->flags & OPT_LOGGED_IN ) && jd->fd == -1 )
	{
		if( sasl_oauth2_get_refresh_token( ic, message ) )
		{
			return 1;
		}
		else
		{
			imcb_error( ic, "OAuth failure" );
			imc_logout( ic, TRUE );
			return 0;
		}
	}
	
	if( ( s = strchr( who, '=' ) ) && jabber_chat_by_jid( ic, s + 1 ) )
		bud = jabber_buddy_by_ext_jid( ic, who, 0 );
	else
		bud = jabber_buddy_by_jid( ic, who, GET_BUDDY_BARE_OK );
	
	node = xt_new_node( "body", message, NULL );
	node = jabber_make_packet( "message", "chat", bud ? bud->full_jid : who, node );
	
	if( bud && ( jd->flags & JFLAG_WANT_TYPING ) &&
	    ( ( bud->flags & JBFLAG_DOES_XEP85 ) ||
	     !( bud->flags & JBFLAG_PROBED_XEP85 ) ) )
	{
		struct xt_node *act;
		
		/* If the user likes typing notification and if we don't know
		   (and didn't probe before) if this resource supports XEP85,
		   include a probe in this packet now. Also, if we know this
		   buddy does support XEP85, we have to send this <active/>
		   tag to tell that the user stopped typing (well, that's what
		   we guess when s/he pressed Enter...). */
		act = xt_new_node( "active", NULL, NULL );
		xt_add_attr( act, "xmlns", XMLNS_CHATSTATES );
		xt_add_child( node, act );
		
		/* Just make sure we do this only once. */
		bud->flags |= JBFLAG_PROBED_XEP85;
	}
	
	st = jabber_write_packet( ic, node );
	xt_free_node( node );
	
	return st;
}
Example #5
0
static int jabber_send_typing(struct im_connection *ic, char *who, int typing)
{
	struct jabber_data *jd = ic->proto_data;
	struct jabber_buddy *bud, *bare;

	/* Enable typing notification related code from now. */
	jd->flags |= JFLAG_WANT_TYPING;

	if ((bud = jabber_buddy_by_jid(ic, who, 0)) == NULL ||
	    (bare = jabber_buddy_by_jid(ic, who, GET_BUDDY_BARE)) == NULL) {
		/* Sending typing notifications to unknown buddies is
		   unsupported for now. Shouldn't be a problem, I think. */
		return 0;
	}


	if (bud->flags & JBFLAG_DOES_XEP85 || bare->flags & JBFLAG_DOES_XEP85) {
		/* We're only allowed to send this stuff if we know the other
		   side supports it. If the bare JID has the flag, all other
		   resources get it, too (That is the case in gtalk) */

		struct xt_node *node;
		char *type;
		int st;

		if (typing & OPT_TYPING) {
			type = "composing";
		} else if (typing & OPT_THINKING) {
			type = "paused";
		} else {
			type = "active";
		}

		node = xt_new_node(type, NULL, NULL);
		xt_add_attr(node, "xmlns", XMLNS_CHATSTATES);
		node = jabber_make_packet("message", "chat", bud->full_jid, node);

		st = jabber_write_packet(ic, node);
		xt_free_node(node);

		return st;
	}

	return 1;
}
Example #6
0
void jabber_si_transfer_request(struct im_connection *ic, file_transfer_t *ft, char *who)
{
	struct jabber_transfer *tf;
	struct jabber_data *jd = ic->proto_data;
	struct jabber_buddy *bud;
	char *server = jd->server, *s;

	if ((s = strchr(who, '=')) && jabber_chat_by_jid(ic, s + 1)) {
		bud = jabber_buddy_by_ext_jid(ic, who, 0);
	} else {
		bud = jabber_buddy_by_jid(ic, who, 0);
	}

	if (bud == NULL) {
		imcb_file_canceled(ic, ft, "Couldn't find buddy (BUG?)");
		return;
	}

	imcb_log(ic, "Trying to send %s(%zd bytes) to %s", ft->file_name, ft->file_size, who);

	tf = g_new0(struct jabber_transfer, 1);

	tf->ic = ic;
	tf->ft = ft;
	tf->fd = -1;
	tf->ft->data = tf;
	tf->ft->free = jabber_si_free_transfer;
	tf->bud = bud;
	ft->write = jabber_bs_send_write;

	jd->filetransfers = g_slist_prepend(jd->filetransfers, tf);

	/* query buddy's features and server's streaming proxies if necessary */

	if (!tf->bud->features) {
		jabber_iq_query_features(ic, bud->full_jid);
	}

	/* If <auto> is not set don't check for proxies */
	if ((jd->have_streamhosts != 1) && (jd->streamhosts == NULL) &&
	    (strstr(set_getstr(&ic->acc->set, "proxy"), "<auto>") != NULL)) {
		jd->have_streamhosts = 0;
		jabber_iq_query_server(ic, server, XMLNS_DISCO_ITEMS);
	} else if (jd->streamhosts != NULL) {
		jd->have_streamhosts = 1;
	}

	/* if we had to do a query, wait for the result.
	 * Otherwise fire away. */
	if (!tf->bud->features || jd->have_streamhosts != 1) {
		tf->disco_timeout = b_timeout_add(500, jabber_si_waitfor_disco, tf);
	} else {
		jabber_si_transfer_start(tf);
	}
}
Example #7
0
File: jabber.c Project: AlD/bitlbee
void *jabber_buddy_action( struct bee_user *bu, const char *action, char * const args[], void *data )
{
	if( g_strcasecmp( action, "VERSION" ) == 0 )
	{
		struct jabber_buddy *bud;
		
		if( ( bud = jabber_buddy_by_ext_jid( bu->ic, bu->handle, 0 ) ) == NULL )
			bud = jabber_buddy_by_jid( bu->ic, bu->handle, GET_BUDDY_FIRST );
		for( ; bud; bud = bud->next )
			jabber_iq_version_send( bu->ic, bud, data );
	}
	
	return NULL;
}
Example #8
0
File: jabber.c Project: AlD/bitlbee
static void jabber_get_info( struct im_connection *ic, char *who )
{
	struct jabber_buddy *bud;
	
	bud = jabber_buddy_by_jid( ic, who, GET_BUDDY_FIRST );
	
	while( bud )
	{
		imcb_log( ic, "Buddy %s (%d) information:", bud->full_jid, bud->priority );
		if( bud->away_state )
			imcb_log( ic, "Away state: %s", bud->away_state->full_name );
		imcb_log( ic, "Status message: %s", bud->away_message ? bud->away_message : "(none)" );
		
		bud = bud->next;
	}
	
	jabber_get_vcard( ic, bud ? bud->full_jid : who );
}
Example #9
0
static xt_status jabber_chat_join_failed(struct im_connection *ic, struct xt_node *node, struct xt_node *orig)
{
	struct jabber_error *err;
	struct jabber_buddy *bud;
	char *room;

	room = xt_find_attr(orig, "to");
	bud = jabber_buddy_by_jid(ic, room, 0);
	err = jabber_error_parse(xt_find_node(node->children, "error"), XMLNS_STANZA_ERROR);
	if (err) {
		imcb_error(ic, "Error joining groupchat %s: %s%s%s", room, err->code,
		           err->text ? ": " : "", err->text ? err->text : "");
		jabber_error_free(err);
	}
	if (bud) {
		jabber_chat_free(jabber_chat_by_jid(ic, bud->bare_jid));
	}

	return XT_HANDLED;
}
Example #10
0
static xt_status jabber_pkt_message_normal(struct xt_node *node, gpointer data, gboolean carbons_sent)
{
	struct im_connection *ic = data;
	struct jabber_data *jd = ic->proto_data;
	char *from = xt_find_attr(node, carbons_sent ? "to" : "from");
	char *type = xt_find_attr(node, "type");
	char *id = xt_find_attr(node, "id");
	struct xt_node *body = xt_find_node(node->children, "body"), *c;
	struct xt_node *request = xt_find_node(node->children, "request");
	struct jabber_buddy *bud = NULL;
	char *s, *room = NULL, *reason = NULL;

	if (!from) {
		return XT_HANDLED; /* Consider this packet corrupted. */
	}

	/* try to detect hipchat's own version of self-messages */
	if (jd->flags & JFLAG_HIPCHAT) {
		struct xt_node *c;

		if ((c = xt_find_node_by_attr(node->children, "delay", "xmlns", XMLNS_DELAY)) &&
		    (s = xt_find_attr(c, "from_jid")) &&
		    jabber_compare_jid(s, jd->me)) {
			carbons_sent = TRUE;
		}
	}

	if (request && id && g_strcmp0(type, "groupchat") != 0 && !carbons_sent) {
		/* Send a message receipt (XEP-0184), looking like this:
		 * <message from='...' id='...' to='...'>
		 *  <received xmlns='urn:xmpp:receipts' id='richard2-4.1.247'/>
		 * </message>
		 *
		 * MUC messages are excluded, since receipts aren't supposed to be sent over MUCs
		 * (XEP-0184 section 5.3) and replying to those may result in 'forbidden' errors.
		 */
		struct xt_node *received, *receipt;

		received = xt_new_node("received", NULL, NULL);
		xt_add_attr(received, "xmlns", XMLNS_RECEIPTS);
		xt_add_attr(received, "id", id);
		receipt = jabber_make_packet("message", NULL, from, received);

		jabber_write_packet(ic, receipt);
		xt_free_node(receipt);
	}

	bud = jabber_buddy_by_jid(ic, from, GET_BUDDY_EXACT);

	if (type && strcmp(type, "error") == 0) {
		/* Handle type=error packet. */
	} else if (type && from && strcmp(type, "groupchat") == 0) {
		jabber_chat_pkt_message(ic, bud, node);
	} else { /* "chat", "normal", "headline", no-type or whatever. Should all be pretty similar. */
		GString *fullmsg = g_string_new("");

		for (c = node->children; (c = xt_find_node(c, "x")); c = c->next) {
			char *ns = xt_find_attr(c, "xmlns");
			struct xt_node *inv;

			if (ns && strcmp(ns, XMLNS_MUC_USER) == 0 &&
			    (inv = xt_find_node(c->children, "invite"))) {
				/* This is an invitation. Set some vars which
				   will be passed to imcb_chat_invite() below. */
				room = from;
				if ((from = xt_find_attr(inv, "from")) == NULL) {
					from = room;
				}
				if ((inv = xt_find_node(inv->children, "reason")) && inv->text_len > 0) {
					reason = inv->text;
				}
			}
		}

		if ((s = strchr(from, '/'))) {
			if (bud) {
				bud->last_msg = time(NULL);
				from = bud->ext_jid ? bud->ext_jid : bud->bare_jid;
			} else {
				*s = 0; /* We need to generate a bare JID now. */
			}
		}

		if (type && strcmp(type, "headline") == 0) {
			if ((c = xt_find_node(node->children, "subject")) && c->text_len > 0) {
				g_string_append_printf(fullmsg, "Headline: %s\n", c->text);
			}

			/* <x xmlns="jabber:x:oob"><url>http://....</url></x> can contain a URL, it seems. */
			for (c = node->children; c; c = c->next) {
				struct xt_node *url;

				if ((url = xt_find_node(c->children, "url")) && url->text_len > 0) {
					g_string_append_printf(fullmsg, "URL: %s\n", url->text);
				}
			}
		} else if ((c = xt_find_node(node->children, "subject")) && c->text_len > 0 &&
		           (!bud || !(bud->flags & JBFLAG_HIDE_SUBJECT))) {
			g_string_append_printf(fullmsg, "<< \002BitlBee\002 - Message with subject: %s >>\n", c->text);
			if (bud) {
				bud->flags |= JBFLAG_HIDE_SUBJECT;
			}
		} else if (bud && !c) {
			/* Yeah, possibly we're hiding changes to this field now. But nobody uses
			   this for anything useful anyway, except GMail when people reply to an
			   e-mail via chat, repeating the same subject all the time. I don't want
			   to have to remember full subject strings for everyone. */
			bud->flags &= ~JBFLAG_HIDE_SUBJECT;
		}

		if (body && body->text_len > 0) { /* Could be just a typing notification. */
			fullmsg = g_string_append(fullmsg, body->text);
		}

		if (fullmsg->len > 0) {
			imcb_buddy_msg(ic, from, fullmsg->str,
			               carbons_sent ? OPT_SELFMESSAGE : 0, jabber_get_timestamp(node));
		}
		if (room) {
			imcb_chat_invite(ic, room, from, reason);
		}

		g_string_free(fullmsg, TRUE);

		/* Handling of incoming typing notifications. */
		if (bud == NULL || carbons_sent) {
			/* Can't handle these for unknown buddies.
			   And ignore them if it's just carbons */
		} else if (xt_find_node(node->children, "composing")) {
			bud->flags |= JBFLAG_DOES_XEP85;
			imcb_buddy_typing(ic, from, OPT_TYPING);
		}
		else if (xt_find_node(node->children, "active")) {
			bud->flags |= JBFLAG_DOES_XEP85;

			/* No need to send a "stopped typing" signal when there's a message. */
			if (body == NULL) {
				imcb_buddy_typing(ic, from, 0);
			}
		} else if (xt_find_node(node->children, "paused")) {
			bud->flags |= JBFLAG_DOES_XEP85;
			imcb_buddy_typing(ic, from, OPT_THINKING);
		}

		if (s) {
			*s = '/'; /* And convert it back to a full JID. */
		}
	}

	return XT_HANDLED;
}
Example #11
0
/*
 * First function that gets called when a file transfer request comes in.
 * A lot to parse.
 *
 * We choose a stream type from the options given by the initiator.
 * Then we wait for imcb to call the accept or cancel callbacks.
 */
int jabber_si_handle_request(struct im_connection *ic, struct xt_node *node, struct xt_node *sinode)
{
	struct xt_node *c, *d, *reply;
	char *sid, *ini_jid, *tgt_jid, *iq_id, *s, *ext_jid, *size_s;
	struct jabber_buddy *bud;
	int requestok = FALSE;
	char *name, *cmp;
	size_t size;
	struct jabber_transfer *tf;
	struct jabber_data *jd = ic->proto_data;
	file_transfer_t *ft;

	/* All this means we expect something like this: ( I think )
	 * <iq from=... to=... id=...>
	 *      <si id=id xmlns=si profile=ft>
	 *              <file xmlns=ft/>
	 *              <feature xmlns=feature>
	 *                      <x xmlns=xdata type=submit>
	 *                              <field var=stream-method>
	 *
	 */
	if (!(ini_jid          = xt_find_attr(node, "from")) ||
	    !(tgt_jid          = xt_find_attr(node, "to")) ||
	    !(iq_id            = xt_find_attr(node, "id")) ||
	    !(sid              = xt_find_attr(sinode, "id")) ||
	    !(cmp              = xt_find_attr(sinode, "profile")) ||
	    !(0               == strcmp(cmp, XMLNS_FILETRANSFER)) ||
	    !(d                = xt_find_node(sinode->children, "file")) ||
	    !(cmp = xt_find_attr(d, "xmlns")) ||
	    !(0               == strcmp(cmp, XMLNS_FILETRANSFER)) ||
	    !(name             = xt_find_attr(d, "name")) ||
	    !(size_s           = xt_find_attr(d, "size")) ||
	    !(1               == sscanf(size_s, "%zd", &size)) ||
	    !(d                = xt_find_node(sinode->children, "feature")) ||
	    !(cmp              = xt_find_attr(d, "xmlns")) ||
	    !(0               == strcmp(cmp, XMLNS_FEATURE)) ||
	    !(d                = xt_find_node(d->children, "x")) ||
	    !(cmp              = xt_find_attr(d, "xmlns")) ||
	    !(0               == strcmp(cmp, XMLNS_XDATA)) ||
	    !(cmp              = xt_find_attr(d, "type")) ||
	    !(0               == strcmp(cmp, "form")) ||
	    !(d                = xt_find_node(d->children, "field")) ||
	    !(cmp              = xt_find_attr(d, "var")) ||
	    !(0               == strcmp(cmp, "stream-method"))) {
		imcb_log(ic, "WARNING: Received incomplete Stream Initiation request");
	} else {
		/* Check if we support one of the options */

		c = d->children;
		while ((c = xt_find_node(c, "option"))) {
			if ((d = xt_find_node(c->children, "value")) &&
			    (d->text != NULL) &&
			    (strcmp(d->text, XMLNS_BYTESTREAMS) == 0)) {
				requestok = TRUE;
				break;
			} else {
				c = c->next;
			}
		}

		if (!requestok) {
			imcb_log(ic, "WARNING: Unsupported file transfer request from %s", ini_jid);
		}
	}

	if (requestok) {
		/* Figure out who the transfer should come from... */

		ext_jid = ini_jid;
		if ((s = strchr(ini_jid, '/'))) {
			if ((bud = jabber_buddy_by_jid(ic, ini_jid, GET_BUDDY_EXACT))) {
				bud->last_msg = time(NULL);
				ext_jid = bud->ext_jid ? : bud->bare_jid;
			} else {
				*s = 0; /* We need to generate a bare JID now. */
			}
		}
Example #12
0
xt_status jabber_pkt_message( struct xt_node *node, gpointer data )
{
	struct im_connection *ic = data;
	char *from = xt_find_attr( node, "from" );
	char *type = xt_find_attr( node, "type" );
	char *id = xt_find_attr( node, "id" );
	struct xt_node *body = xt_find_node( node->children, "body" ), *c;
	struct xt_node *request = xt_find_node( node->children, "request" );
	struct jabber_buddy *bud = NULL;
	char *s, *room = NULL, *reason = NULL;
	
	if( !from )
		return XT_HANDLED; /* Consider this packet corrupted. */

	if( request && id )
	{
		/* Send a message receipt (XEP-0184), looking like this:
		 * <message
		 *  from='[email protected]/throne'
		 *  id='bi29sg183b4v'
		 *  to='[email protected]/westminster'>
		 *  <received xmlns='urn:xmpp:receipts' id='richard2-4.1.247'/>
		 * </message> */
		struct xt_node *received, *receipt;
		
		received = xt_new_node( "received", NULL, NULL );
		xt_add_attr( received, "xmlns", XMLNS_RECEIPTS );
		xt_add_attr( received, "id", id );
		receipt = jabber_make_packet( "message", NULL, from, received );

		jabber_write_packet( ic, receipt );
		xt_free_node( receipt );
	}
	
	bud = jabber_buddy_by_jid( ic, from, GET_BUDDY_EXACT );
	
	if( type && strcmp( type, "error" ) == 0 )
	{
		/* Handle type=error packet. */
	}
	else if( type && from && strcmp( type, "groupchat" ) == 0 )
	{
		jabber_chat_pkt_message( ic, bud, node );
	}
	else /* "chat", "normal", "headline", no-type or whatever. Should all be pretty similar. */
	{
		GString *fullmsg = g_string_new( "" );

		for( c = node->children; ( c = xt_find_node( c, "x" ) ); c = c->next )
		{
			char *ns = xt_find_attr( c, "xmlns" );
			struct xt_node *inv;
			
			if( ns && strcmp( ns, XMLNS_MUC_USER ) == 0 &&
			    ( inv = xt_find_node( c->children, "invite" ) ) )
			{
				/* This is an invitation. Set some vars which
				   will be passed to imcb_chat_invite() below. */
				room = from;
				if( ( from = xt_find_attr( inv, "from" ) ) == NULL )
					from = room;
				if( ( inv = xt_find_node( inv->children, "reason" ) ) && inv->text_len > 0 )
					reason = inv->text;
			}
		}
		
		if( ( s = strchr( from, '/' ) ) )
		{
			if( bud )
			{
				bud->last_msg = time( NULL );
				from = bud->ext_jid ? bud->ext_jid : bud->bare_jid;
			}
			else
				*s = 0; /* We need to generate a bare JID now. */
		}
		
		if( type && strcmp( type, "headline" ) == 0 )
		{
			if( ( c = xt_find_node( node->children, "subject" ) ) && c->text_len > 0 )
				g_string_append_printf( fullmsg, "Headline: %s\n", c->text );
			
			/* <x xmlns="jabber:x:oob"><url>http://....</url></x> can contain a URL, it seems. */
			for( c = node->children; c; c = c->next )
			{
				struct xt_node *url;
				
				if( ( url = xt_find_node( c->children, "url" ) ) && url->text_len > 0 )
					g_string_append_printf( fullmsg, "URL: %s\n", url->text );
			}
		}
		else if( ( c = xt_find_node( node->children, "subject" ) ) && c->text_len > 0 &&
		         ( !bud || !( bud->flags & JBFLAG_HIDE_SUBJECT ) ) )
		{
			g_string_append_printf( fullmsg, "<< \002BitlBee\002 - Message with subject: %s >>\n", c->text );
			if( bud )
				bud->flags |= JBFLAG_HIDE_SUBJECT;
		}
		else if( bud && !c )
		{
			/* Yeah, possibly we're hiding changes to this field now. But nobody uses
			   this for anything useful anyway, except GMail when people reply to an
			   e-mail via chat, repeating the same subject all the time. I don't want
			   to have to remember full subject strings for everyone. */
			bud->flags &= ~JBFLAG_HIDE_SUBJECT;
		}
		
		if( body && body->text_len > 0 ) /* Could be just a typing notification. */
			fullmsg = g_string_append( fullmsg, body->text );
		
		if( fullmsg->len > 0 )
			imcb_buddy_msg( ic, from, fullmsg->str,
			                0, jabber_get_timestamp( node ) );
		if( room )
			imcb_chat_invite( ic, room, from, reason );
		
		g_string_free( fullmsg, TRUE );
		
		/* Handling of incoming typing notifications. */
		if( bud == NULL )
		{
			/* Can't handle these for unknown buddies. */
		}
		else if( xt_find_node( node->children, "composing" ) )
		{
			bud->flags |= JBFLAG_DOES_XEP85;
			imcb_buddy_typing( ic, from, OPT_TYPING );
		}
		/* No need to send a "stopped typing" signal when there's a message. */
		else if( xt_find_node( node->children, "active" ) && ( body == NULL ) )
		{
			bud->flags |= JBFLAG_DOES_XEP85;
			imcb_buddy_typing( ic, from, 0 );
		}
		else if( xt_find_node( node->children, "paused" ) )
		{
			bud->flags |= JBFLAG_DOES_XEP85;
			imcb_buddy_typing( ic, from, OPT_THINKING );
		}
		
		if( s )
			*s = '/'; /* And convert it back to a full JID. */
	}
	
	return XT_HANDLED;
}
Example #13
0
xt_status jabber_pkt_presence( struct xt_node *node, gpointer data )
{
	struct im_connection *ic = data;
	char *from = xt_find_attr( node, "from" );
	char *type = xt_find_attr( node, "type" );	/* NULL should mean the person is online. */
	struct xt_node *c, *cap;
	struct jabber_buddy *bud, *send_presence = NULL;
	int is_chat = 0;
	char *s;
	
	if( !from )
		return XT_HANDLED;
	
	if( ( s = strchr( from, '/' ) ) )
	{
		*s = 0;
		if( jabber_chat_by_jid( ic, from ) )
			is_chat = 1;
		*s = '/';
	}
	
	if( type == NULL )
	{
		if( !( bud = jabber_buddy_by_jid( ic, from, GET_BUDDY_EXACT | GET_BUDDY_CREAT ) ) )
		{
			if( set_getbool( &ic->irc->set, "debug" ) )
				imcb_log( ic, "Warning: Could not handle presence information from JID: %s", from );
			return XT_HANDLED;
		}
		
		g_free( bud->away_message );
		if( ( c = xt_find_node( node->children, "status" ) ) && c->text_len > 0 )
			bud->away_message = g_strdup( c->text );
		else
			bud->away_message = NULL;
		
		if( ( c = xt_find_node( node->children, "show" ) ) && c->text_len > 0 )
		{
			bud->away_state = (void*) jabber_away_state_by_code( c->text );
		}
		else
		{
			bud->away_state = NULL;
			/* Let's only set last_act if there's *no* away state,
			   since it could be some auto-away thingy. */
			bud->last_act = time( NULL );
		}
		
		if( ( c = xt_find_node( node->children, "priority" ) ) && c->text_len > 0 )
			bud->priority = atoi( c->text );
		else
			bud->priority = 0;
		
		if( bud && ( cap = xt_find_node( node->children, "c" ) ) &&
		    ( s = xt_find_attr( cap, "xmlns" ) ) && strcmp( s, XMLNS_CAPS ) == 0 )
		{
			/* This <presence> stanza includes an XEP-0115
			   capabilities part. Not too interesting, but we can
			   see if it has an ext= attribute. */
			s = xt_find_attr( cap, "ext" );
			if( s && ( strstr( s, "cstates" ) || strstr( s, "chatstate" ) ) )
				bud->flags |= JBFLAG_DOES_XEP85;
			
			/* This field can contain more information like xhtml
			   support, but we don't support that ourselves.
			   Officially the ext= tag was deprecated, but enough
			   clients do send it.
			   
			   (I'm aware that this is not the right way to use
			   this field.) See for an explanation of ext=:
			   http://www.xmpp.org/extensions/attic/xep-0115-1.3.html*/
		}
		
		if( is_chat )
			jabber_chat_pkt_presence( ic, bud, node );
		else
			send_presence = jabber_buddy_by_jid( ic, bud->bare_jid, 0 );
	}
	else if( strcmp( type, "unavailable" ) == 0 )
	{
		if( ( bud = jabber_buddy_by_jid( ic, from, 0 ) ) == NULL )
		{
			if( set_getbool( &ic->irc->set, "debug" ) )
				imcb_log( ic, "Warning: Received presence information from unknown JID: %s", from );
			return XT_HANDLED;
		}
		
		/* Handle this before we delete the JID. */
		if( is_chat )
		{
			jabber_chat_pkt_presence( ic, bud, node );
		}
		
		if( strchr( from, '/' ) == NULL )
			/* Sometimes servers send a type="unavailable" from a
			   bare JID, which should mean that suddenly all
			   resources for this JID disappeared. */
			jabber_buddy_remove_bare( ic, from );
		else
			jabber_buddy_remove( ic, from );
		
		if( is_chat )
		{
			/* Nothing else to do for now? */
		}
		else if( ( s = strchr( from, '/' ) ) )
		{
			*s = 0;
		
			/* If another resource is still available, send its presence
			   information. */
			if( ( send_presence = jabber_buddy_by_jid( ic, from, 0 ) ) == NULL )
			{
				/* Otherwise, count him/her as offline now. */
				imcb_buddy_status( ic, from, 0, NULL, NULL );
			}
			
			*s = '/';
		}
		else
		{
			imcb_buddy_status( ic, from, 0, NULL, NULL );
		}
	}
	else if( strcmp( type, "subscribe" ) == 0 )
	{
		jabber_buddy_ask( ic, from );
	}
	else if( strcmp( type, "subscribed" ) == 0 )
	{
		/* Not sure about this one, actually... */
		imcb_log( ic, "%s just accepted your authorization request", from );
	}
	else if( strcmp( type, "unsubscribe" ) == 0 || strcmp( type, "unsubscribed" ) == 0 )
	{
		/* Do nothing here. Plenty of control freaks or over-curious
		   souls get excited when they can see who still has them in
		   their buddy list and who finally removed them. Somehow I
		   got the impression that those are the people who get
		   removed from many buddy lists for "some" reason...
		   
		   If you're one of those people, this is your chance to write
		   your first line of code in C... */
	}
	else if( strcmp( type, "error" ) == 0 )
	{
		return jabber_cache_handle_packet( ic, node );
		
		/*
		struct jabber_error *err;
		if( ( c = xt_find_node( node->children, "error" ) ) )
		{
			err = jabber_error_parse( c, XMLNS_STANZA_ERROR );
			imcb_error( ic, "Stanza (%s) error: %s%s%s", node->name,
			            err->code, err->text ? ": " : "",
			            err->text ? err->text : "" );
			jabber_error_free( err );
		} */
	}

	if( send_presence )
	{
		int is_away = 0;

		if( send_presence->away_state && !( *send_presence->away_state->code == 0 ||
		    strcmp( send_presence->away_state->code, "chat" ) == 0 ) )
			is_away = OPT_AWAY;

		imcb_buddy_status( ic, send_presence->bare_jid, OPT_LOGGED_IN | is_away,
		                   ( is_away && send_presence->away_state ) ?
		                   send_presence->away_state->full_name : NULL,
		                   send_presence->away_message );
	}
	
	return XT_HANDLED;
}
Example #14
0
static void check_buddy_add(int l)
{
	struct jabber_buddy *budw1, *budw2, *budw3, *budn, *bud;
	
	budw1 = jabber_buddy_add( ic, "[email protected]/BitlBee" );
	budw1->last_msg = time( NULL ) - 100;
	budw2 = jabber_buddy_add( ic, "[email protected]/Telepathy" );
	budw2->priority = 2;
	budw2->last_msg = time( NULL );
	budw3 = jabber_buddy_add( ic, "[email protected]/bitlbee" );
	budw3->last_msg = time( NULL ) - 200;
	budw3->priority = 4;
	/* TODO(wilmer): Shouldn't this just return budw3? */
	fail_if( jabber_buddy_add( ic, "[email protected]/Telepathy" ) != NULL );
	
	budn = jabber_buddy_add( ic, "*****@*****.**" );
	/* Shouldn't be allowed if there's already a bare JID. */
	fail_if( jabber_buddy_add( ic, "[email protected]/Illegal" ) );
	
	/* Case sensitivity: Case only matters after the / */
	fail_if( jabber_buddy_by_jid( ic, "[email protected]/BitlBee", 0 ) ==
	         jabber_buddy_by_jid( ic, "[email protected]/bitlbee", 0 ) );
	fail_if( jabber_buddy_by_jid( ic, "[email protected]/telepathy", 0 ) );
	
	fail_unless( jabber_buddy_by_jid( ic, "[email protected]/BitlBee", 0 ) == budw1 );
	fail_unless( jabber_buddy_by_jid( ic, "[email protected]/BitlBee", GET_BUDDY_EXACT ) == budw1 );
	fail_unless( jabber_buddy_by_jid( ic, "[email protected]/BitlBee", GET_BUDDY_CREAT ) == budw1 );

	fail_if( jabber_buddy_by_jid( ic, "*****@*****.**", GET_BUDDY_EXACT ) );
	fail_unless( jabber_buddy_by_jid( ic, "*****@*****.**", 0 ) == budw3 );

	/* Check O_FIRST and see if it's indeed the first item from the list. */
	fail_unless( ( bud = jabber_buddy_by_jid( ic, "*****@*****.**", GET_BUDDY_FIRST ) ) == budw1 );
	fail_unless( bud->next == budw2 && bud->next->next == budw3 && bud->next->next->next == NULL );
	
	/* Change the resource_select setting, now we should get a different resource. */
	set_setstr( &ic->acc->set, "resource_select", "activity" );
	fail_unless( jabber_buddy_by_jid( ic, "*****@*****.**", 0 ) == budw2 );
	
	/* Some testing of bare JID handling (which is horrible). */
	fail_if( jabber_buddy_by_jid( ic, "[email protected]/Illegal", 0 ) );
	fail_if( jabber_buddy_by_jid( ic, "[email protected]/Illegal", GET_BUDDY_CREAT ) );
	fail_unless( jabber_buddy_by_jid( ic, "*****@*****.**", 0 ) == budn );
	fail_unless( jabber_buddy_by_jid( ic, "*****@*****.**", GET_BUDDY_EXACT ) == budn );
	fail_unless( jabber_buddy_by_jid( ic, "*****@*****.**", GET_BUDDY_CREAT ) == budn );
	
	/* More case sensitivity testing, and see if remove works properly. */
	fail_if( jabber_buddy_remove( ic, "[email protected]/telepathy" ) );
	fail_if( jabber_buddy_by_jid( ic, "[email protected]/telepathy", GET_BUDDY_CREAT ) == budw2 );
	fail_unless( jabber_buddy_remove( ic, "[email protected]/Telepathy" ) );
	fail_unless( jabber_buddy_remove( ic, "[email protected]/telepathy" ) );
	
	/* Test activity_timeout and GET_BUDDY_BARE_OK. */
	fail_unless( jabber_buddy_by_jid( ic, "*****@*****.**", GET_BUDDY_BARE_OK ) == budw1 );
	budw1->last_msg -= 50;
	fail_unless( ( bud = jabber_buddy_by_jid( ic, "*****@*****.**", GET_BUDDY_BARE_OK ) ) != NULL );
	fail_unless( strcmp( bud->full_jid, "*****@*****.**" ) == 0 );
	
	fail_if( jabber_buddy_remove( ic, "*****@*****.**" ) );
	fail_unless( jabber_buddy_by_jid( ic, "*****@*****.**", 0 ) == budw1 );
	
	fail_if( jabber_buddy_remove( ic, "*****@*****.**" ) );
	fail_unless( jabber_buddy_remove( ic, "[email protected]/bitlbee" ) );
	fail_unless( jabber_buddy_remove( ic, "[email protected]/BitlBee" ) );
	fail_if( jabber_buddy_by_jid( ic, "*****@*****.**", GET_BUDDY_BARE_OK ) );
	
	/* Check if remove_bare() indeed gets rid of all. */
	/* disable this one for now.
	fail_unless( jabber_buddy_remove_bare( ic, "*****@*****.**" ) );
	fail_if( jabber_buddy_by_jid( ic, "*****@*****.**", 0 ) );
	*/

	fail_if( jabber_buddy_remove( ic, "[email protected]/Illegal" ) );
	fail_unless( jabber_buddy_remove( ic, "*****@*****.**" ) );
	fail_if( jabber_buddy_by_jid( ic, "*****@*****.**", 0 ) );
	
	/* Fixing a bug in this branch that caused information to get lost when
	   removing the first full JID from a list. */
	jabber_buddy_add( ic, "[email protected]/A" );
	jabber_buddy_add( ic, "[email protected]/B" );
	jabber_buddy_add( ic, "[email protected]/C" );
	fail_unless( jabber_buddy_remove( ic, "[email protected]/A" ) );
	fail_unless( jabber_buddy_remove( ic, "[email protected]/B" ) );
	fail_unless( jabber_buddy_remove( ic, "[email protected]/C" ) );
}