⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jabber.c

📁 Linux下的多协议即时通讯程序源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * purple - Jabber Protocol Plugin * * Copyright (C) 2003, Nathan Walp <faceprint@faceprint.com> * * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * */#include "internal.h"#include "account.h"#include "accountopt.h"#include "blist.h"#include "cmds.h"#include "connection.h"#include "conversation.h"#include "debug.h"#include "dnssrv.h"#include "message.h"#include "notify.h"#include "pluginpref.h"#include "proxy.h"#include "prpl.h"#include "request.h"#include "server.h"#include "util.h"#include "version.h"#include "xmlnode.h"#include "auth.h"#include "buddy.h"#include "chat.h"#include "disco.h"#include "google.h"#include "iq.h"#include "jutil.h"#include "message.h"#include "parser.h"#include "presence.h"#include "jabber.h"#include "roster.h"#include "si.h"#include "xdata.h"#define JABBER_CONNECT_STEPS (js->gsc ? 8 : 5)static PurplePlugin *my_protocol = NULL;static void jabber_stream_init(JabberStream *js){	char *open_stream;	open_stream = g_strdup_printf("<stream:stream to='%s' "				          "xmlns='jabber:client' "						  "xmlns:stream='http://etherx.jabber.org/streams' "						  "version='1.0'>",						  js->user->domain);	/* setup the parser fresh for each stream */	jabber_parser_setup(js);	jabber_send_raw(js, open_stream, -1);	js->reinit = FALSE;	g_free(open_stream);}static voidjabber_session_initialized_cb(JabberStream *js, xmlnode *packet, gpointer data){	const char *type = xmlnode_get_attrib(packet, "type");	if(type && !strcmp(type, "result")) {		jabber_stream_set_state(js, JABBER_STREAM_CONNECTED);	} else {		purple_connection_error(js->gc, _("Error initializing session"));	}}static void jabber_session_init(JabberStream *js){	JabberIq *iq = jabber_iq_new(js, JABBER_IQ_SET);	xmlnode *session;	jabber_iq_set_callback(iq, jabber_session_initialized_cb, NULL);	session = xmlnode_new_child(iq->node, "session");	xmlnode_set_namespace(session, "urn:ietf:params:xml:ns:xmpp-session");	jabber_iq_send(iq);}static void jabber_bind_result_cb(JabberStream *js, xmlnode *packet,		gpointer data){	const char *type = xmlnode_get_attrib(packet, "type");	xmlnode *bind;	if(type && !strcmp(type, "result") &&			(bind = xmlnode_get_child_with_namespace(packet, "bind", "urn:ietf:params:xml:ns:xmpp-bind"))) {		xmlnode *jid;		char *full_jid;		if((jid = xmlnode_get_child(bind, "jid")) && (full_jid = xmlnode_get_data(jid))) {			JabberBuddy *my_jb = NULL;			jabber_id_free(js->user);			if(!(js->user = jabber_id_new(full_jid))) {				purple_connection_error(js->gc, _("Invalid response from server."));			}			if((my_jb = jabber_buddy_find(js, full_jid, TRUE)))				my_jb->subscription |= JABBER_SUB_BOTH;			g_free(full_jid);		}	} else {		char *msg = jabber_parse_error(js, packet);		purple_connection_error(js->gc, msg);		g_free(msg);	}	jabber_session_init(js);}static void jabber_stream_features_parse(JabberStream *js, xmlnode *packet){	if(xmlnode_get_child(packet, "starttls")) {		if(jabber_process_starttls(js, packet))			return;	}	if(js->registration) {		jabber_register_start(js);	} else if(xmlnode_get_child(packet, "mechanisms")) {		jabber_auth_start(js, packet);	} else if(xmlnode_get_child(packet, "bind")) {		xmlnode *bind, *resource;		JabberIq *iq = jabber_iq_new(js, JABBER_IQ_SET);		bind = xmlnode_new_child(iq->node, "bind");		xmlnode_set_namespace(bind, "urn:ietf:params:xml:ns:xmpp-bind");		resource = xmlnode_new_child(bind, "resource");		xmlnode_insert_data(resource, js->user->resource, -1);		jabber_iq_set_callback(iq, jabber_bind_result_cb, NULL);		jabber_iq_send(iq);	} else /* if(xmlnode_get_child_with_namespace(packet, "auth")) */ {		/* If we get an empty stream:features packet, or we explicitly get		 * an auth feature with namespace http://jabber.org/features/iq-auth		 * we should revert back to iq:auth authentication, even though we're		 * connecting to an XMPP server.  */		js->auth_type = JABBER_AUTH_IQ_AUTH;		jabber_stream_set_state(js, JABBER_STREAM_AUTHENTICATING);	}}static void jabber_stream_handle_error(JabberStream *js, xmlnode *packet){	char *msg = jabber_parse_error(js, packet);	purple_connection_error(js->gc, msg);	g_free(msg);}static void tls_init(JabberStream *js);void jabber_process_packet(JabberStream *js, xmlnode *packet){	const char *xmlns;	purple_signal_emit(my_protocol, "jabber-receiving-xmlnode", js->gc, &packet);	/* if the signal leaves us with a null packet, we're done */	if(NULL == packet)		return;	xmlns = xmlnode_get_namespace(packet);	if(!strcmp(packet->name, "iq")) {		jabber_iq_parse(js, packet);	} else if(!strcmp(packet->name, "presence")) {		jabber_presence_parse(js, packet);	} else if(!strcmp(packet->name, "message")) {		jabber_message_parse(js, packet);	} else if(!strcmp(packet->name, "stream:features")) {		jabber_stream_features_parse(js, packet);	} else if (!strcmp(packet->name, "features") &&		   !strcmp(xmlns, "http://etherx.jabber.org/streams")) {		jabber_stream_features_parse(js, packet);	} else if(!strcmp(packet->name, "stream:error") ||			 (!strcmp(packet->name, "error") &&				!strcmp(xmlns, "http://etherx.jabber.org/streams")))	{		jabber_stream_handle_error(js, packet);	} else if(!strcmp(packet->name, "challenge")) {		if(js->state == JABBER_STREAM_AUTHENTICATING)			jabber_auth_handle_challenge(js, packet);	} else if(!strcmp(packet->name, "success")) {		if(js->state == JABBER_STREAM_AUTHENTICATING)			jabber_auth_handle_success(js, packet);	} else if(!strcmp(packet->name, "failure")) {		if(js->state == JABBER_STREAM_AUTHENTICATING)			jabber_auth_handle_failure(js, packet);	} else if(!strcmp(packet->name, "proceed")) {		if(js->state == JABBER_STREAM_AUTHENTICATING && !js->gsc)			tls_init(js);	} else {		purple_debug(PURPLE_DEBUG_WARNING, "jabber", "Unknown packet: %s\n",				packet->name);	}}static int jabber_do_send(JabberStream *js, const char *data, int len){	int ret;	if (js->gsc)		ret = purple_ssl_write(js->gsc, data, len);	else		ret = write(js->fd, data, len);	return ret;}static void jabber_send_cb(gpointer data, gint source, PurpleInputCondition cond){	JabberStream *js = data;	int ret, writelen;	writelen = purple_circ_buffer_get_max_read(js->write_buffer);	if (writelen == 0) {		purple_input_remove(js->writeh);		js->writeh = 0;		return;	}	ret = jabber_do_send(js, js->write_buffer->outptr, writelen);	if (ret < 0 && errno == EAGAIN)		return;	else if (ret <= 0) {		purple_connection_error(js->gc, _("Write error"));		return;	}	purple_circ_buffer_mark_read(js->write_buffer, ret);}void jabber_send_raw(JabberStream *js, const char *data, int len){	int ret;	/* because printing a tab to debug every minute gets old */	if(strcmp(data, "\t"))		purple_debug(PURPLE_DEBUG_MISC, "jabber", "Sending%s: %s\n",				js->gsc ? " (ssl)" : "", data);	/* If we've got a security layer, we need to encode the data,	 * splitting it on the maximum buffer length negotiated */		purple_signal_emit(my_protocol, "jabber-sending-text", js->gc, &data);	if (data == NULL)		return;	#ifdef HAVE_CYRUS_SASL	if (js->sasl_maxbuf>0) {		int pos;		if (!js->gsc && js->fd<0)			return;		pos = 0;		if (len == -1)			len = strlen(data);		while (pos < len) {			int towrite;			const char *out;			unsigned olen;			if ((len - pos) < js->sasl_maxbuf)				towrite = len - pos;			else				towrite = js->sasl_maxbuf;			sasl_encode(js->sasl, &data[pos], towrite, &out, &olen);			pos += towrite;			if (js->writeh == 0)				ret = jabber_do_send(js, out, olen);			else {				ret = -1;				errno = EAGAIN;			}			if (ret < 0 && errno != EAGAIN)				purple_connection_error(js->gc, _("Write error"));			else if (ret < olen) {				if (ret < 0)					ret = 0;				if (js->writeh == 0)					js->writeh = purple_input_add(						js->gsc ? js->gsc->fd : js->fd,						PURPLE_INPUT_WRITE,						jabber_send_cb, js);				purple_circ_buffer_append(js->write_buffer,					out + ret, olen - ret);			}		}		return;	}#endif	if (len == -1)		len = strlen(data);	if (js->writeh == 0)		ret = jabber_do_send(js, data, len);	else {		ret = -1;		errno = EAGAIN;	}	if (ret < 0 && errno != EAGAIN)		purple_connection_error(js->gc, _("Write error"));	else if (ret < len) {		if (ret < 0)			ret = 0;		if (js->writeh == 0)			js->writeh = purple_input_add(				js->gsc ? js->gsc->fd : js->fd,				PURPLE_INPUT_WRITE, jabber_send_cb, js);		purple_circ_buffer_append(js->write_buffer,			data + ret, len - ret);	}	return;}int jabber_prpl_send_raw(PurpleConnection *gc, const char *buf, int len){	JabberStream *js = (JabberStream*)gc->proto_data;	jabber_send_raw(js, buf, len);	return len;}void jabber_send(JabberStream *js, xmlnode *packet){	char *txt;	int len;	purple_signal_emit(my_protocol, "jabber-sending-xmlnode", js->gc, &packet);	/* if we get NULL back, we're done processing */	if(NULL == packet)		return;	txt = xmlnode_to_str(packet, &len);	jabber_send_raw(js, txt, len);	g_free(txt);}void jabber_keepalive(PurpleConnection *gc){	jabber_send_raw(gc->proto_data, "\t", -1);}static voidjabber_recv_cb_ssl(gpointer data, PurpleSslConnection *gsc,		PurpleInputCondition cond){	PurpleConnection *gc = data;	JabberStream *js = gc->proto_data;	int len;	static char buf[4096];	/* TODO: It should be possible to make this check unnecessary */	if(!PURPLE_CONNECTION_IS_VALID(gc)) {		purple_ssl_close(gsc);		return;	}	while((len = purple_ssl_read(gsc, buf, sizeof(buf) - 1)) > 0) {		buf[len] = '\0';		purple_debug(PURPLE_DEBUG_INFO, "jabber", "Recv (ssl)(%d): %s\n", len, buf);		jabber_parser_process(js, buf, len);		if(js->reinit)			jabber_stream_init(js);	}	if(errno == EAGAIN)		return;	else		purple_connection_error(gc, _("Read Error"));}static voidjabber_recv_cb(gpointer data, gint source, PurpleInputCondition condition){	PurpleConnection *gc = data;	JabberStream *js = gc->proto_data;	int len;	static char buf[4096];	if(!PURPLE_CONNECTION_IS_VALID(gc))		return;	if((len = read(js->fd, buf, sizeof(buf) - 1)) > 0) {#ifdef HAVE_CYRUS_SASL		if (js->sasl_maxbuf>0) {			const char *out;			unsigned int olen;			sasl_decode(js->sasl, buf, len, &out, &olen);			if (olen>0) {				purple_debug(PURPLE_DEBUG_INFO, "jabber", "RecvSASL (%u): %s\n", olen, out);				jabber_parser_process(js,out,olen);				if(js->reinit)					jabber_stream_init(js);			}			return;		}#endif		buf[len] = '\0';		purple_debug(PURPLE_DEBUG_INFO, "jabber", "Recv (%d): %s\n", len, buf);		jabber_parser_process(js, buf, len);		if(js->reinit)			jabber_stream_init(js);	} else if(errno == EAGAIN) {		return;	} else {		purple_connection_error(gc, _("Read Error"));	}}static voidjabber_login_callback_ssl(gpointer data, PurpleSslConnection *gsc,		PurpleInputCondition cond){	PurpleConnection *gc = data;	JabberStream *js;	/* TODO: It should be possible to make this check unnecessary */	if(!PURPLE_CONNECTION_IS_VALID(gc)) {		purple_ssl_close(gsc);		return;	}		js = gc->proto_data;	if(js->state == JABBER_STREAM_CONNECTING)		jabber_send_raw(js, "<?xml version='1.0' ?>", -1);	jabber_stream_set_state(js, JABBER_STREAM_INITIALIZING);	purple_ssl_input_add(gsc, jabber_recv_cb_ssl, gc);}static voidjabber_login_callback(gpointer data, gint source, const gchar *error){	PurpleConnection *gc = data;	JabberStream *js = gc->proto_data;	if (source < 0) {		gchar *tmp;		tmp = g_strdup_printf(_("Could not establish a connection with the server:\n%s"),				error);		purple_connection_error(gc, tmp);		g_free(tmp);		return;	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -