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

📄 si.c

📁 Linux下的多协议即时通讯程序源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
static voidjabber_si_xfer_bytestreams_send_connected_cb(gpointer data, gint source,		PurpleInputCondition cond){	PurpleXfer *xfer = data;	int acceptfd;	purple_debug_info("jabber", "in jabber_si_xfer_bytestreams_send_connected_cb\n");	acceptfd = accept(source, NULL, 0);	if(acceptfd == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))		return;	else if(acceptfd == -1) {		purple_debug_warning("jabber", "accept: %s\n", strerror(errno));		return;	}	purple_input_remove(xfer->watcher);	close(source);	xfer->watcher = purple_input_add(acceptfd, PURPLE_INPUT_READ,			jabber_si_xfer_bytestreams_send_read_cb, xfer);}static voidjabber_si_xfer_bytestreams_listen_cb(int sock, gpointer data){	PurpleXfer *xfer = data;	JabberSIXfer *jsx;	JabberIq *iq;	xmlnode *query, *streamhost;	char *jid, *port;	jsx = xfer->data;	jsx->listen_data = NULL;	if (purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_CANCEL_LOCAL) {		purple_xfer_unref(xfer);		return;	}	purple_xfer_unref(xfer);	if (sock < 0) {		purple_xfer_cancel_local(xfer);		return;	}	iq = jabber_iq_new_query(jsx->js, JABBER_IQ_SET,			"http://jabber.org/protocol/bytestreams");	xmlnode_set_attrib(iq->node, "to", xfer->who);	query = xmlnode_get_child(iq->node, "query");	xmlnode_set_attrib(query, "sid", jsx->stream_id);	streamhost = xmlnode_new_child(query, "streamhost");	jid = g_strdup_printf("%s@%s/%s", jsx->js->user->node,			jsx->js->user->domain, jsx->js->user->resource);	xmlnode_set_attrib(streamhost, "jid", jid);	g_free(jid);	/* XXX: shouldn't we use the public IP or something? here */	xmlnode_set_attrib(streamhost, "host",			purple_network_get_my_ip(jsx->js->fd));	xfer->local_port = purple_network_get_port_from_fd(sock);	port = g_strdup_printf("%hu", xfer->local_port);	xmlnode_set_attrib(streamhost, "port", port);	g_free(port);	xfer->watcher = purple_input_add(sock, PURPLE_INPUT_READ,			jabber_si_xfer_bytestreams_send_connected_cb, xfer);	/* XXX: insert proxies here */	/* XXX: callback to find out which streamhost they used, or see if they	 * screwed it up */	jabber_iq_send(iq);}static voidjabber_si_xfer_bytestreams_send_init(PurpleXfer *xfer){	JabberSIXfer *jsx;	purple_xfer_ref(xfer);	jsx = xfer->data;	jsx->listen_data = purple_network_listen_range(0, 0, SOCK_STREAM,				jabber_si_xfer_bytestreams_listen_cb, xfer);	if (jsx->listen_data == NULL) {		purple_xfer_unref(xfer);		/* XXX: couldn't open a port, we're fscked */		purple_xfer_cancel_local(xfer);		return;	}}static void jabber_si_xfer_send_method_cb(JabberStream *js, xmlnode *packet,		gpointer data){	PurpleXfer *xfer = data;	xmlnode *si, *feature, *x, *field, *value;	if(!(si = xmlnode_get_child_with_namespace(packet, "si", "http://jabber.org/protocol/si"))) {		purple_xfer_cancel_remote(xfer);		return;	}	if(!(feature = xmlnode_get_child_with_namespace(si, "feature", "http://jabber.org/protocol/feature-neg"))) {		purple_xfer_cancel_remote(xfer);		return;	}	if(!(x = xmlnode_get_child_with_namespace(feature, "x", "jabber:x:data"))) {		purple_xfer_cancel_remote(xfer);		return;	}	for(field = xmlnode_get_child(x, "field"); field; field = xmlnode_get_next_twin(field)) {		const char *var = xmlnode_get_attrib(field, "var");		if(var && !strcmp(var, "stream-method")) {			if((value = xmlnode_get_child(field, "value"))) {				char *val = xmlnode_get_data(value);				if(val && !strcmp(val, "http://jabber.org/protocol/bytestreams")) {					jabber_si_xfer_bytestreams_send_init(xfer);					g_free(val);					return;				}				g_free(val);			}		}	}	purple_xfer_cancel_remote(xfer);}static void jabber_si_xfer_send_request(PurpleXfer *xfer){	JabberSIXfer *jsx = xfer->data;	JabberIq *iq;	xmlnode *si, *file, *feature, *x, *field, *option, *value;	char buf[32];	xfer->filename = g_path_get_basename(xfer->local_filename);	iq = jabber_iq_new(jsx->js, JABBER_IQ_SET);	xmlnode_set_attrib(iq->node, "to", xfer->who);	si = xmlnode_new_child(iq->node, "si");	xmlnode_set_namespace(si, "http://jabber.org/protocol/si");	jsx->stream_id = jabber_get_next_id(jsx->js);	xmlnode_set_attrib(si, "id", jsx->stream_id);	xmlnode_set_attrib(si, "profile",			"http://jabber.org/protocol/si/profile/file-transfer");	file = xmlnode_new_child(si, "file");	xmlnode_set_namespace(file,			"http://jabber.org/protocol/si/profile/file-transfer");	xmlnode_set_attrib(file, "name", xfer->filename);	g_snprintf(buf, sizeof(buf), "%" G_GSIZE_FORMAT, xfer->size);	xmlnode_set_attrib(file, "size", buf);	/* maybe later we'll do hash and date attribs */	feature = xmlnode_new_child(si, "feature");	xmlnode_set_namespace(feature,			"http://jabber.org/protocol/feature-neg");	x = xmlnode_new_child(feature, "x");	xmlnode_set_namespace(x, "jabber:x:data");	xmlnode_set_attrib(x, "type", "form");	field = xmlnode_new_child(x, "field");	xmlnode_set_attrib(field, "var", "stream-method");	xmlnode_set_attrib(field, "type", "list-single");	option = xmlnode_new_child(field, "option");	value = xmlnode_new_child(option, "value");	xmlnode_insert_data(value, "http://jabber.org/protocol/bytestreams",			-1);	/*	option = xmlnode_new_child(field, "option");	value = xmlnode_new_child(option, "value");	xmlnode_insert_data(value, "http://jabber.org/protocol/ibb", -1);	*/	jabber_iq_set_callback(iq, jabber_si_xfer_send_method_cb, xfer);	jabber_iq_send(iq);}static void jabber_si_xfer_free(PurpleXfer *xfer){	JabberSIXfer *jsx = xfer->data;	JabberStream *js = jsx->js;	js->file_transfers = g_list_remove(js->file_transfers, xfer);	if (jsx->connect_data != NULL)		purple_proxy_connect_cancel(jsx->connect_data);	if (jsx->listen_data != NULL)		purple_network_listen_cancel(jsx->listen_data);	g_free(jsx->stream_id);	g_free(jsx->iq_id);	/* XXX: free other stuff */	g_free(jsx->rxqueue);	g_free(jsx);	xfer->data = NULL;}static void jabber_si_xfer_cancel_send(PurpleXfer *xfer){	jabber_si_xfer_free(xfer);	purple_debug(PURPLE_DEBUG_INFO, "jabber", "in jabber_si_xfer_cancel_send\n");}static void jabber_si_xfer_request_denied(PurpleXfer *xfer){	jabber_si_xfer_free(xfer);	purple_debug(PURPLE_DEBUG_INFO, "jabber", "in jabber_si_xfer_request_denied\n");}static void jabber_si_xfer_cancel_recv(PurpleXfer *xfer){	jabber_si_xfer_free(xfer);	purple_debug(PURPLE_DEBUG_INFO, "jabber", "in jabber_si_xfer_cancel_recv\n");}static void jabber_si_xfer_end(PurpleXfer *xfer){	jabber_si_xfer_free(xfer);}static void jabber_si_xfer_send_disco_cb(JabberStream *js, const char *who,		JabberCapabilities capabilities, gpointer data){	PurpleXfer *xfer = data;	if(capabilities & JABBER_CAP_SI_FILE_XFER) {		jabber_si_xfer_send_request(xfer);	} else {		char *msg = g_strdup_printf(_("Unable to send file to %s, user does not support file transfers"), who);		purple_notify_error(js->gc, _("File Send Failed"),				_("File Send Failed"), msg);		g_free(msg);	}}static void resource_select_cancel_cb(PurpleXfer *xfer, PurpleRequestFields *fields){	purple_xfer_cancel_local(xfer);}static void do_transfer_send(PurpleXfer *xfer, const char *resource){	JabberSIXfer *jsx = xfer->data;	char **who_v = g_strsplit(xfer->who, "/", 2);	char *who;	who = g_strdup_printf("%s/%s", who_v[0], resource);	g_strfreev(who_v);	g_free(xfer->who);	xfer->who = who;	jabber_disco_info_do(jsx->js, who,			jabber_si_xfer_send_disco_cb, xfer);}static void resource_select_ok_cb(PurpleXfer *xfer, PurpleRequestFields *fields){	PurpleRequestField *field = purple_request_fields_get_field(fields, "resource");	int selected_id = purple_request_field_choice_get_value(field);	GList *labels = purple_request_field_choice_get_labels(field);	const char *selected_label = g_list_nth_data(labels, selected_id);	do_transfer_send(xfer, selected_label);}static void jabber_si_xfer_init(PurpleXfer *xfer){	JabberSIXfer *jsx = xfer->data;	JabberIq *iq;	if(purple_xfer_get_type(xfer) == PURPLE_XFER_SEND) {		JabberBuddy *jb;		JabberBuddyResource *jbr = NULL;		char *resource;		if(NULL != (resource = jabber_get_resource(xfer->who))) {			/* they've specified a resource, no need to ask or			 * default or anything, just do it */			do_transfer_send(xfer, resource);			g_free(resource);		}		jb = jabber_buddy_find(jsx->js, xfer->who, TRUE);		if(!jb || !jb->resources) {			/* no resources online, we're trying to send to someone			 * whose presence we're not subscribed to, or			 * someone who is offline.  Let's inform the user */			char *msg;			if(!jb) {				msg = g_strdup_printf(_("Unable to send file to %s, invalid JID"), xfer->who);			} else if(jb->subscription & JABBER_SUB_TO) {				msg = g_strdup_printf(_("Unable to send file to %s, user is not online"), xfer->who);			} else {				msg = g_strdup_printf(_("Unable to send file to %s, not subscribed to user presence"), xfer->who);			}			purple_notify_error(jsx->js->gc, _("File Send Failed"), _("File Send Failed"), msg);			g_free(msg);		} else if(g_list_length(jb->resources) == 1) {			/* only 1 resource online (probably our most common case)			 * so no need to ask who to send to */			jbr = jb->resources->data;			do_transfer_send(xfer, jbr->name);		} else {			/* we've got multiple resources, we need to pick one to send to */			GList *l;			char *msg = g_strdup_printf(_("Please select which resource of %s you would like to send a file to"), xfer->who);			PurpleRequestFields *fields = purple_request_fields_new();			PurpleRequestField *field = purple_request_field_choice_new("resource", _("Resource"), 0);			PurpleRequestFieldGroup *group = purple_request_field_group_new(NULL);			for(l = jb->resources; l; l = l->next)			{				jbr = l->data;				purple_request_field_choice_add(field, jbr->name);			}			purple_request_field_group_add_field(group, field);			purple_request_fields_add_group(fields, group);			purple_request_fields(jsx->js->gc, _("Select a Resource"), msg, NULL, fields,					_("Send File"), G_CALLBACK(resource_select_ok_cb), _("Cancel"), G_CALLBACK(resource_select_cancel_cb),					jsx->js->gc->account, xfer->who, NULL, xfer);			g_free(msg);		}	} else {		xmlnode *si, *feature, *x, *field, *value;		iq = jabber_iq_new(jsx->js, JABBER_IQ_RESULT);		xmlnode_set_attrib(iq->node, "to", xfer->who);		if(jsx->iq_id)			jabber_iq_set_id(iq, jsx->iq_id);		jsx->accepted = TRUE;		si = xmlnode_new_child(iq->node, "si");		xmlnode_set_namespace(si, "http://jabber.org/protocol/si");		feature = xmlnode_new_child(si, "feature");		xmlnode_set_namespace(feature, "http://jabber.org/protocol/feature-neg");		x = xmlnode_new_child(feature, "x");		xmlnode_set_namespace(x, "jabber:x:data");		xmlnode_set_attrib(x, "type", "submit");		field = xmlnode_new_child(x, "field");		xmlnode_set_attrib(field, "var", "stream-method");		value = xmlnode_new_child(field, "value");		if(jsx->stream_method & STREAM_METHOD_BYTESTREAMS)			xmlnode_insert_data(value, "http://jabber.org/protocol/bytestreams", -1);		/*		else if(jsx->stream_method & STREAM_METHOD_IBB)		xmlnode_insert_data(value, "http://jabber.org/protocol/ibb", -1);		*/		jabber_iq_send(iq);	}}PurpleXfer *jabber_si_new_xfer(PurpleConnection *gc, const char *who){	JabberStream *js;	PurpleXfer *xfer;	JabberSIXfer *jsx;	js = gc->proto_data;	xfer = purple_xfer_new(gc->account, PURPLE_XFER_SEND, who);	if (xfer)	{		xfer->data = jsx = g_new0(JabberSIXfer, 1);		jsx->js = js;		purple_xfer_set_init_fnc(xfer, jabber_si_xfer_init);		purple_xfer_set_cancel_send_fnc(xfer, jabber_si_xfer_cancel_send);		purple_xfer_set_end_fnc(xfer, jabber_si_xfer_end);		js->file_transfers = g_list_append(js->file_transfers, xfer);	}	return xfer;}void jabber_si_xfer_send(PurpleConnection *gc, const char *who, const char *file){	JabberStream *js;	PurpleXfer *xfer;	js = gc->proto_data;	if(!purple_find_buddy(gc->account, who) || !jabber_buddy_find(js, who, FALSE))		return;	xfer = jabber_si_new_xfer(gc, who);	if (file)		purple_xfer_request_accepted(xfer, file);	else		purple_xfer_request(xfer);}void jabber_si_parse(JabberStream *js, xmlnode *packet){	JabberSIXfer *jsx;	PurpleXfer *xfer;	xmlnode *si, *file, *feature, *x, *field, *option, *value;	const char *stream_id, *filename, *filesize_c, *profile, *from;	size_t filesize = 0;	if(!(si = xmlnode_get_child(packet, "si")))		return;	if(!(profile = xmlnode_get_attrib(si, "profile")) ||			strcmp(profile, "http://jabber.org/protocol/si/profile/file-transfer"))		return;	if(!(stream_id = xmlnode_get_attrib(si, "id")))		return;	if(!(file = xmlnode_get_child(si, "file")))		return;	if(!(filename = xmlnode_get_attrib(file, "name")))		return;	if((filesize_c = xmlnode_get_attrib(file, "size")))		filesize = atoi(filesize_c);	if(!(feature = xmlnode_get_child(si, "feature")))		return;	if(!(x = xmlnode_get_child_with_namespace(feature, "x", "jabber:x:data")))		return;	if(!(from = xmlnode_get_attrib(packet, "from")))		return;	/* if they've already sent us this file transfer with the same damn id	 * then we're gonna ignore it, until I think of something better to do	 * with it */	if((xfer = jabber_si_xfer_find(js, stream_id, from)))		return;	jsx = g_new0(JabberSIXfer, 1);	for(field = xmlnode_get_child(x, "field"); field; field = xmlnode_get_next_twin(field)) {		const char *var = xmlnode_get_attrib(field, "var");		if(var && !strcmp(var, "stream-method")) {			for(option = xmlnode_get_child(field, "option"); option;					option = xmlnode_get_next_twin(option)) {				if((value = xmlnode_get_child(option, "value"))) {					char *val;					if((val = xmlnode_get_data(value))) {						if(!strcmp(val, "http://jabber.org/protocol/bytestreams")) {							jsx->stream_method |= STREAM_METHOD_BYTESTREAMS;							/*						} else if(!strcmp(val, "http://jabber.org/protocol/ibb")) {							jsx->stream_method |= STREAM_METHOD_IBB;							*/						}						g_free(val);					}				}			}		}	}	if(jsx->stream_method == STREAM_METHOD_UNKNOWN) {		g_free(jsx);		return;	}	jsx->js = js;	jsx->stream_id = g_strdup(stream_id);	jsx->iq_id = g_strdup(xmlnode_get_attrib(packet, "id"));	xfer = purple_xfer_new(js->gc->account, PURPLE_XFER_RECEIVE, from);	if (xfer)	{		xfer->data = jsx;		purple_xfer_set_filename(xfer, filename);		if(filesize > 0)			purple_xfer_set_size(xfer, filesize);		purple_xfer_set_init_fnc(xfer, jabber_si_xfer_init);		purple_xfer_set_request_denied_fnc(xfer, jabber_si_xfer_request_denied);		purple_xfer_set_cancel_recv_fnc(xfer, jabber_si_xfer_cancel_recv);		purple_xfer_set_end_fnc(xfer, jabber_si_xfer_end);		js->file_transfers = g_list_append(js->file_transfers, xfer);		purple_xfer_request(xfer);	}}

⌨️ 快捷键说明

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