示例#1
0
文件: jabber.c 项目: 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;
}
示例#2
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);
	}
}
示例#3
0
文件: jabber.c 项目: AlD/bitlbee
static struct groupchat *jabber_chat_join_( struct im_connection *ic, const char *room, const char *nick, const char *password, set_t **sets )
{
	if( strchr( room, '@' ) == NULL )
		imcb_error( ic, "Invalid room name: %s", room );
	else if( jabber_chat_by_jid( ic, room ) )
		imcb_error( ic, "Already present in chat `%s'", room );
	else
		return jabber_chat_join( ic, room, nick, set_getstr( sets, "password" ) );
	
	return NULL;
}
示例#4
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;
}
示例#5
0
static struct groupchat *jabber_chat_join_(struct im_connection *ic, const char *room, const char *nick,
        const char *password, set_t **sets)
{
    struct jabber_data *jd = ic->proto_data;
    char *final_nick;

    /* Ignore the passed nick parameter if we have our own default */
    if (!(final_nick = set_getstr(sets, "nick")) &&
            !(final_nick = set_getstr(&ic->acc->set, "display_name"))) {
        /* Well, whatever, actually use the provided default, then */
        final_nick = (char *) nick;
    }

    if (strchr(room, '@') == NULL) {
        imcb_error(ic, "%s is not a valid Jabber room name. Maybe you mean %s@conference.%s?",
                   room, room, jd->server);
    } else if (jabber_chat_by_jid(ic, room)) {
        imcb_error(ic, "Already present in chat `%s'", room);
    } else {
        return jabber_chat_join(ic, room, final_nick, set_getstr(sets, "password"));
    }

    return NULL;
}
示例#6
0
文件: jabber.c 项目: luka-n/bitlbee
static struct groupchat *jabber_chat_join_(struct im_connection *ic, const char *room, const char *nick,
                                           const char *password, set_t **sets)
{
	struct jabber_data *jd = ic->proto_data;
	char *final_nick;

	/* Ignore the passed nick parameter if we have our own default */
	if (!(final_nick = set_getstr(sets, "nick")) &&
	    !(final_nick = set_getstr(&ic->acc->set, "display_name"))) {
		/* Well, whatever, actually use the provided default, then */
		final_nick = (char *) nick;
	}

	if (jd->flags & JFLAG_HIPCHAT && jd->muc_host && !g_str_has_suffix(room, jd->muc_host)) {
		char *guessed_name = hipchat_guess_channel_name(ic, room);
		if (guessed_name) {
			set_setstr(sets, "room", guessed_name);
			g_free(guessed_name);

			/* call this same function again with the fixed name */
			return jabber_chat_join_(ic, set_getstr(sets, "room"), nick, password, sets);
		}
	}

	if (strchr(room, '@') == NULL) {
		imcb_error(ic, "%s is not a valid Jabber room name. Maybe you mean %s@conference.%s?",
		           room, room, jd->server);
	} else if (jabber_chat_by_jid(ic, room)) {
		imcb_error(ic, "Already present in chat `%s'", room);
	} else {
		/* jabber_chat_join without the underscore is the conference.c one */
		return jabber_chat_join(ic, room, final_nick, set_getstr(sets, "password"));
	}

	return NULL;
}
示例#7
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;
}
示例#8
0
/* 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)
{
	struct groupchat *chat;
	struct xt_node *c;
	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) {
		/* 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... 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)) {
				struct xt_node *item;

				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);
					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 {
				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] = '_';
					}
				}

				/* Some program-specific restrictions. */
				imcb_clean_handle(ic, bud->ext_jid);
			}
			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);
		}

		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) {
			char *reason = NULL;
			char *status = NULL;
			char *status_text = NULL;
			
			if ((c = xt_find_node_by_attr(node->children, "x", "xmlns", XMLNS_MUC_USER))) {
				struct xt_node *c2 = c->children;

				while ((c2 = xt_find_node(c2, "status"))) {
					char *code = xt_find_attr(c2, "code");
					if (g_strcmp0(code, "301") == 0) {
						status = "Banned";
						break;
					} else if (g_strcmp0(code, "303") == 0) {
						/* This could be handled in a cleverer way,
						 * but let's just show a literal part/join for now */
						status = "Changing nicks";
						break;
					} else if (g_strcmp0(code, "307") == 0) {
						status = "Kicked";
						break;
					}
					c2 = c2->next;
				}

				/* Sometimes the status message is in presence/x/item/reason */
				if ((c2 = xt_find_path(c, "item/reason")) && c2->text && c2->text_len) {
					status_text = c2->text;
				}
			}

			/* Sometimes the status message is right inside <presence> */
			if ((c = xt_find_node(node->children, "status")) && c->text && c->text_len) {
				status_text = c->text;
			}

			if (status_text && status) {
				reason = g_strdup_printf("%s: %s", status, status_text);
			} else {
				reason = g_strdup(status_text ? : status);
			}

			s = strchr(bud->ext_jid, '/');
			if (s) {
				*s = 0;
			}
			imcb_chat_remove_buddy(chat, bud->ext_jid, reason);
			if (bud != jc->me && bud->flags & JBFLAG_IS_ANONYMOUS) {
				imcb_remove_buddy(ic, bud->ext_jid, reason);
			}
			if (s) {
				*s = '/';
			}

			g_free(reason);
		}

		if (bud == jc->me) {
			jabber_chat_free(chat);
		}
	}