diff options
Diffstat (limited to 'protocols/jabber/conference.c')
| -rw-r--r-- | protocols/jabber/conference.c | 482 | 
1 files changed, 240 insertions, 242 deletions
diff --git a/protocols/jabber/conference.c b/protocols/jabber/conference.c index c8930f83..7435358a 100644 --- a/protocols/jabber/conference.c +++ b/protocols/jabber/conference.c @@ -24,51 +24,50 @@  #include "jabber.h"  #include "sha1.h" -static xt_status jabber_chat_join_failed( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ); +static xt_status jabber_chat_join_failed(struct im_connection *ic, struct xt_node *node, struct xt_node *orig); -struct groupchat *jabber_chat_join( struct im_connection *ic, const char *room, const char *nick, const char *password ) +struct groupchat *jabber_chat_join(struct im_connection *ic, const char *room, const char *nick, const 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 ); -	if( password ) -		xt_add_child( node, xt_new_node( "password", password, NULL ) ); -	node = jabber_make_packet( "presence", NULL, roomjid, node ); -	jabber_cache_add( ic, node, jabber_chat_join_failed ); -	 -	if( !jabber_write_packet( ic, node ) ) -	{ -		g_free( roomjid ); + +	roomjid = g_strdup_printf("%s/%s", room, nick); +	node = xt_new_node("x", NULL, NULL); +	xt_add_attr(node, "xmlns", XMLNS_MUC); +	if (password) { +		xt_add_child(node, xt_new_node("password", password, NULL)); +	} +	node = jabber_make_packet("presence", NULL, roomjid, node); +	jabber_cache_add(ic, node, jabber_chat_join_failed); + +	if (!jabber_write_packet(ic, node)) { +		g_free(roomjid);  		return NULL;  	} -	 -	jc = g_new0( struct jabber_chat, 1 ); -	jc->name = jabber_normalize( room ); -	 -	if( ( jc->me = jabber_buddy_add( ic, roomjid ) ) == NULL ) -	{ -		g_free( roomjid ); -		g_free( jc->name ); -		g_free( jc ); + +	jc = g_new0(struct jabber_chat, 1); +	jc->name = jabber_normalize(room); + +	if ((jc->me = jabber_buddy_add(ic, roomjid)) == NULL) { +		g_free(roomjid); +		g_free(jc->name); +		g_free(jc);  		return NULL;  	} -	 +  	/* roomjid isn't normalized yet, and we need an original version  	   of the nick to send a proper presence update. */  	jc->my_full_jid = roomjid; -	 -	c = imcb_chat_new( ic, room ); + +	c = imcb_chat_new(ic, room);  	c->data = jc; -	 +  	return c;  } -struct groupchat *jabber_chat_with( struct im_connection *ic, char *who ) +struct groupchat *jabber_chat_with(struct im_connection *ic, char *who)  {  	struct jabber_data *jd = ic->proto_data;  	struct jabber_chat *jc; @@ -76,357 +75,356 @@ struct groupchat *jabber_chat_with( struct im_connection *ic, char *who )  	sha1_state_t sum;  	double now = gettime();  	char *uuid, *rjid, *cserv; -	 -	sha1_init( &sum ); -	sha1_append( &sum, (uint8_t*) ic->acc->user, strlen( ic->acc->user ) ); -	sha1_append( &sum, (uint8_t*) &now, sizeof( now ) ); -	sha1_append( &sum, (uint8_t*) who, strlen( who ) ); -	uuid = sha1_random_uuid( &sum ); -	 -	if( jd->flags & JFLAG_GTALK ) -		cserv = g_strdup( "groupchat.google.com" ); -	else + +	sha1_init(&sum); +	sha1_append(&sum, (uint8_t *) ic->acc->user, strlen(ic->acc->user)); +	sha1_append(&sum, (uint8_t *) &now, sizeof(now)); +	sha1_append(&sum, (uint8_t *) who, strlen(who)); +	uuid = sha1_random_uuid(&sum); + +	if (jd->flags & JFLAG_GTALK) { +		cserv = g_strdup("groupchat.google.com"); +	} else {  		/* Guess... */ -		cserv = g_strdup_printf( "conference.%s", jd->server ); -	 -	rjid = g_strdup_printf( "private-chat-%s@%s", uuid, cserv ); -	g_free( uuid ); -	g_free( cserv ); -	 -	c = jabber_chat_join( ic, rjid, jd->username, NULL ); -	g_free( rjid ); -	if( c == NULL ) +		cserv = g_strdup_printf("conference.%s", jd->server); +	} + +	rjid = g_strdup_printf("private-chat-%s@%s", uuid, cserv); +	g_free(uuid); +	g_free(cserv); + +	c = jabber_chat_join(ic, rjid, jd->username, NULL); +	g_free(rjid); +	if (c == NULL) {  		return NULL; -	 +	} +  	jc = c->data; -	jc->invite = g_strdup( who ); -	 +	jc->invite = g_strdup(who); +  	return c;  } -static xt_status jabber_chat_join_failed( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ) +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 ); + +	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 ) ); -	 +	if (bud) { +		jabber_chat_free(jabber_chat_by_jid(ic, bud->bare_jid)); +	} +  	return XT_HANDLED;  } -struct groupchat *jabber_chat_by_jid( struct im_connection *ic, const char *name ) +struct groupchat *jabber_chat_by_jid(struct im_connection *ic, const char *name)  { -	char *normalized = jabber_normalize( name ); +	char *normalized = jabber_normalize(name);  	GSList *l;  	struct groupchat *ret;  	struct jabber_chat *jc; -	 -	for( l = ic->groupchats; l; l = l->next ) -	{ + +	for (l = ic->groupchats; l; l = l->next) {  		ret = l->data;  		jc = ret->data; -		if( strcmp( normalized, jc->name ) == 0 ) +		if (strcmp(normalized, jc->name) == 0) {  			break; +		}  	} -	g_free( normalized ); -	 +	g_free(normalized); +  	return l ? ret : NULL;  } -void jabber_chat_free( struct groupchat *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->invite ); -	g_free( jc ); -	 -	imcb_chat_free( c ); + +	jabber_buddy_remove_bare(c->ic, jc->name); + +	g_free(jc->my_full_jid); +	g_free(jc->name); +	g_free(jc->invite); +	g_free(jc); + +	imcb_chat_free(c);  } -int jabber_chat_msg( struct groupchat *c, char *message, int flags ) +int jabber_chat_msg(struct groupchat *c, char *message, int flags)  {  	struct im_connection *ic = c->ic;  	struct jabber_chat *jc = c->data;  	struct xt_node *node; -	 +  	jc->flags |= JCFLAG_MESSAGE_SENT; -	 -	node = xt_new_node( "body", message, NULL ); -	node = jabber_make_packet( "message", "groupchat", jc->name, node ); -	 -	if( !jabber_write_packet( ic, node ) ) -	{ -		xt_free_node( node ); + +	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 ); -	 +	xt_free_node(node); +  	return 1;  } -int jabber_chat_topic( struct groupchat *c, char *topic ) +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 ); + +	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 ); -	 +	xt_free_node(node); +  	return 1;  } -int jabber_chat_leave( struct groupchat *c, const char *reason ) +int jabber_chat_leave(struct groupchat *c, const char *reason)  {  	struct im_connection *ic = c->ic;  	struct jabber_chat *jc = c->data;  	struct xt_node *node; -	 -	node = xt_new_node( "x", NULL, NULL ); -	xt_add_attr( node, "xmlns", XMLNS_MUC ); -	node = jabber_make_packet( "presence", "unavailable", jc->my_full_jid, node ); -	 -	if( !jabber_write_packet( ic, node ) ) -	{ -		xt_free_node( node ); + +	node = xt_new_node("x", NULL, NULL); +	xt_add_attr(node, "xmlns", XMLNS_MUC); +	node = jabber_make_packet("presence", "unavailable", jc->my_full_jid, node); + +	if (!jabber_write_packet(ic, node)) { +		xt_free_node(node);  		return 0;  	} -	xt_free_node( node ); -	 +	xt_free_node(node); +  	return 1;  } -void jabber_chat_invite( struct groupchat *c, char *who, char *message ) +void jabber_chat_invite(struct groupchat *c, char *who, char *message)  {  	struct xt_node *node;  	struct im_connection *ic = c->ic;  	struct jabber_chat *jc = c->data; -	node = xt_new_node( "reason", message, NULL );  +	node = xt_new_node("reason", message, NULL); + +	node = xt_new_node("invite", NULL, node); +	xt_add_attr(node, "to", who); -	node = xt_new_node( "invite", NULL, node ); -	xt_add_attr( node, "to", who );  +	node = xt_new_node("x", NULL, node); +	xt_add_attr(node, "xmlns", XMLNS_MUC_USER); -	node = xt_new_node( "x", NULL, node );  -	xt_add_attr( node, "xmlns", XMLNS_MUC_USER );  -	 -	node = jabber_make_packet( "message", NULL, jc->name, node );  +	node = jabber_make_packet("message", NULL, jc->name, node); -	jabber_write_packet( ic, node );  +	jabber_write_packet(ic, node); -	xt_free_node( node ); +	xt_free_node(node);  }  /* Not really the same syntax as the normal pkt_ functions, but this isn't     called by the xmltree parser directly and this way I can add some extra     parameters so we won't have to repeat too many things done by the caller     already. */ -void jabber_chat_pkt_presence( struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node ) +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" ); +	char *type = xt_find_attr(node, "type");  	struct jabber_data *jd = ic->proto_data;  	struct jabber_chat *jc;  	char *s; -	 -	if( ( chat = jabber_chat_by_jid( ic, bud->bare_jid ) ) == NULL ) -	{ + +	if ((chat = jabber_chat_by_jid(ic, bud->bare_jid)) == NULL) {  		/* How could this happen?? We could do kill( self, 11 )  		   now or just wait for the OS to do it. :-) */  		return;  	} -	 +  	jc = chat->data; -	 -	if( type == NULL && !( bud->flags & JBFLAG_IS_CHATROOM ) ) -	{ + +	if (type == NULL && !(bud->flags & JBFLAG_IS_CHATROOM)) {  		bud->flags |= JBFLAG_IS_CHATROOM;  		/* If this one wasn't set yet, this buddy just joined the chat.  		   Slightly hackish way of finding out eh? ;-) */ -		 +  		/* This is pretty messy... Here it sets ext_jid to the real  		   JID of the participant. Works for non-anonymized channels.  		   Might break if someone joins a chat twice, though. */ -		for( c = node->children; ( c = xt_find_node( c, "x" ) ); c = c->next ) -			if( ( s = xt_find_attr( c, "xmlns" ) ) && -			    ( strcmp( s, XMLNS_MUC_USER ) == 0 ) ) -			{ +		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)) {  				struct xt_node *item; -				 -				item = xt_find_node( c->children, "item" ); -				if( ( s = xt_find_attr( item, "jid" ) ) ) -				{ + +				item = xt_find_node(c->children, "item"); +				if ((s = xt_find_attr(item, "jid"))) {  					/* Yay, found what we need. :-) */ -					bud->ext_jid = jabber_normalize( s ); +					bud->ext_jid = jabber_normalize(s);  					break;  				}  			} -		 +		} +  		/* Make up some other handle, if necessary. */ -		if( bud->ext_jid == NULL ) -		{ -			if( bud == jc->me ) -			{ -				bud->ext_jid = g_strdup( jd->me ); -			} -			else -			{ +		if (bud->ext_jid == NULL) { +			if (bud == jc->me) { +				bud->ext_jid = g_strdup(jd->me); +			} 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 ); -				 +				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] == '@' ) +				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 ); +				imcb_clean_handle(ic, bud->ext_jid);  			}  			bud->flags |= JBFLAG_IS_ANONYMOUS;  		} -		 -		if( bud != jc->me && bud->flags & JBFLAG_IS_ANONYMOUS ) -		{ + +		if (bud != jc->me && bud->flags & JBFLAG_IS_ANONYMOUS) {  			/* If JIDs are anonymized, add them to the local  			   list for the duration of this chat. */ -			imcb_add_buddy( ic, bud->ext_jid, NULL ); -			imcb_buddy_nick_hint( ic, bud->ext_jid, bud->resource ); +			imcb_add_buddy(ic, bud->ext_jid, NULL); +			imcb_buddy_nick_hint(ic, bud->ext_jid, bud->resource);  		} -		 -		if( bud == jc->me && jc->invite != NULL ) -		{ -			char *msg = g_strdup_printf( "Please join me in room %s", jc->name ); -			jabber_chat_invite( chat, jc->invite, msg ); -			g_free( jc->invite ); -			g_free( msg ); + +		if (bud == jc->me && jc->invite != NULL) { +			char *msg = g_strdup_printf("Please join me in room %s", jc->name); +			jabber_chat_invite(chat, jc->invite, msg); +			g_free(jc->invite); +			g_free(msg);  			jc->invite = NULL;  		} -		 -		s = strchr( bud->ext_jid, '/' ); -		if( s ) *s = 0; /* Should NEVER be NULL, but who knows... */ -		imcb_chat_add_buddy( chat, bud->ext_jid ); -		if( s ) *s = '/'; -	} -	else if( type ) /* type can only be NULL or "unavailable" in this function */ -	{ -		if( ( bud->flags & JBFLAG_IS_CHATROOM ) && bud->ext_jid ) -		{ -			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 = '/'; + +		s = strchr(bud->ext_jid, '/'); +		if (s) { +			*s = 0; /* Should NEVER be NULL, but who knows... */ +		} +		imcb_chat_add_buddy(chat, bud->ext_jid); +		if (s) { +			*s = '/'; +		} +	} else if (type) { /* type can only be NULL or "unavailable" in this function */ +		if ((bud->flags & JBFLAG_IS_CHATROOM) && bud->ext_jid) { +			s = strchr(bud->ext_jid, '/'); +			if (s) { +				*s = 0; +			} +			imcb_chat_remove_buddy(chat, bud->ext_jid, NULL); +			if (bud != jc->me && bud->flags & JBFLAG_IS_ANONYMOUS) { +				imcb_remove_buddy(ic, bud->ext_jid, NULL); +			} +			if (s) { +				*s = '/'; +			} +		} + +		if (bud == jc->me) { +			jabber_chat_free(chat);  		} -		 -		if( bud == jc->me ) -			jabber_chat_free( chat );  	}  } -void jabber_chat_pkt_message( struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node ) +void jabber_chat_pkt_message(struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node)  { -	struct xt_node *subject = xt_find_node( node->children, "subject" ); -	struct xt_node *body = xt_find_node( node->children, "body" ); -	struct groupchat *chat = bud ? jabber_chat_by_jid( ic, bud->bare_jid ) : NULL; +	struct xt_node *subject = xt_find_node(node->children, "subject"); +	struct xt_node *body = xt_find_node(node->children, "body"); +	struct groupchat *chat = bud ? jabber_chat_by_jid(ic, bud->bare_jid) : NULL;  	struct jabber_chat *jc = chat ? chat->data : NULL;  	char *s; -	 -	if( subject && chat ) -	{ -		s = bud ? strchr( bud->ext_jid, '/' ) : NULL; -		if( s ) *s = 0; -		imcb_chat_topic( chat, bud ? bud->ext_jid : NULL, subject->text_len > 0 ? -		                 subject->text : NULL, jabber_get_timestamp( node ) ); -		if( s ) *s = '/'; + +	if (subject && chat) { +		s = bud ? strchr(bud->ext_jid, '/') : NULL; +		if (s) { +			*s = 0; +		} +		imcb_chat_topic(chat, bud ? bud->ext_jid : NULL, subject->text_len > 0 ? +		                subject->text : NULL, jabber_get_timestamp(node)); +		if (s) { +			*s = '/'; +		}  	} -	 -	if( bud == NULL || ( jc && ~jc->flags & JCFLAG_MESSAGE_SENT && bud == jc->me ) ) -	{ + +	if (bud == NULL || (jc && ~jc->flags & JCFLAG_MESSAGE_SENT && bud == jc->me)) {  		char *nick; -		 -		if( body == NULL || body->text_len == 0 ) + +		if (body == NULL || body->text_len == 0) {  			/* Meh. Empty messages aren't very interesting, no matter  			   how much some servers love to send them. */  			return; -		 -		s = xt_find_attr( node, "from" ); /* pkt_message() already NULL-checked this one. */ -		nick = strchr( s, '/' ); -		if( nick ) -		{ +		} + +		s = xt_find_attr(node, "from");   /* pkt_message() already NULL-checked this one. */ +		nick = strchr(s, '/'); +		if (nick) {  			/* If this message included a resource/nick we don't know,  			   we might still know the groupchat itself. */  			*nick = 0; -			chat = jabber_chat_by_jid( ic, s ); +			chat = jabber_chat_by_jid(ic, s);  			*nick = '/'; -			 -			nick ++; -		} -		else -		{ + +			nick++; +		} else {  			/* message.c uses the EXACT_JID option, so bud should  			   always be NULL here for bare JIDs. */ -			chat = jabber_chat_by_jid( ic, s ); +			chat = jabber_chat_by_jid(ic, s);  		} -		 -		if( nick == NULL ) -		{ + +		if (nick == NULL) {  			/* This is fine, the groupchat itself isn't in jd->buddies. */ -			if( chat ) -				imcb_chat_log( chat, "From conference server: %s", body->text ); -			else -				imcb_log( ic, "System message from unknown groupchat %s: %s", s, body->text ); -		} -		else -		{ +			if (chat) { +				imcb_chat_log(chat, "From conference server: %s", body->text); +			} else { +				imcb_log(ic, "System message from unknown groupchat %s: %s", s, body->text); +			} +		} else {  			/* This can happen too, at least when receiving a backlog when  			   just joining a channel. */ -			if( chat ) -				imcb_chat_log( chat, "Message from unknown participant %s: %s", nick, body->text ); -			else -				imcb_log( ic, "Groupchat message from unknown JID %s: %s", s, body->text ); +			if (chat) { +				imcb_chat_log(chat, "Message from unknown participant %s: %s", nick, body->text); +			} else { +				imcb_log(ic, "Groupchat message from unknown JID %s: %s", s, body->text); +			}  		} -		 +  		return; -	} -	else if( chat == NULL ) -	{ +	} else if (chat == NULL) {  		/* How could this happen?? We could do kill( self, 11 )  		   now or just wait for the OS to do it. :-) */  		return;  	} -	if( body && body->text_len > 0 ) -	{ -		s = strchr( bud->ext_jid, '/' ); -		if( s ) *s = 0; -		imcb_chat_msg( chat, bud->ext_jid, body->text, 0, jabber_get_timestamp( node ) ); -		if( s ) *s = '/'; +	if (body && body->text_len > 0) { +		s = strchr(bud->ext_jid, '/'); +		if (s) { +			*s = 0; +		} +		imcb_chat_msg(chat, bud->ext_jid, body->text, 0, jabber_get_timestamp(node)); +		if (s) { +			*s = '/'; +		}  	}  }  | 
