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

📄 simple.c

📁 Linux下的多协议即时通讯程序源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/** * @file simple.c * * purple * * Copyright (C) 2005 Thomas Butter <butter@uni-mannheim.de> * * *** * Thanks to Google's Summer of Code Program and the helpful mentors * *** * * 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 "accountopt.h"#include "blist.h"#include "conversation.h"#include "dnsquery.h"#include "debug.h"#include "notify.h"#include "privacy.h"#include "prpl.h"#include "plugin.h"#include "util.h"#include "version.h"#include "network.h"#include "xmlnode.h"#include "simple.h"#include "sipmsg.h"#include "dnssrv.h"#include "ntlm.h"static char *gentag() {	return g_strdup_printf("%04d%04d", rand() & 0xFFFF, rand() & 0xFFFF);}static char *genbranch() {	return g_strdup_printf("z9hG4bK%04X%04X%04X%04X%04X",		rand() & 0xFFFF, rand() & 0xFFFF, rand() & 0xFFFF,		rand() & 0xFFFF, rand() & 0xFFFF);}static char *gencallid() {	return g_strdup_printf("%04Xg%04Xa%04Xi%04Xm%04Xt%04Xb%04Xx%04Xx",		rand() & 0xFFFF, rand() & 0xFFFF, rand() & 0xFFFF,		rand() & 0xFFFF, rand() & 0xFFFF, rand() & 0xFFFF,		rand() & 0xFFFF, rand() & 0xFFFF);}static const char *simple_list_icon(PurpleAccount *a, PurpleBuddy *b) {	return "simple";}static void simple_keep_alive(PurpleConnection *gc) {	struct simple_account_data *sip = gc->proto_data;	if(sip->udp) { /* in case of UDP send a packet only with a 0 byte to			 remain in the NAT table */		gchar buf[2] = {0, 0};		purple_debug_info("simple", "sending keep alive\n");		sendto(sip->fd, buf, 1, 0, (struct sockaddr*)&sip->serveraddr, sizeof(struct sockaddr_in));	}	return;}static gboolean process_register_response(struct simple_account_data *sip, struct sipmsg *msg, struct transaction *tc);static void send_notify(struct simple_account_data *sip, struct simple_watcher *);static void send_publish(struct simple_account_data *sip);static void do_notifies(struct simple_account_data *sip) {	GSList *tmp = sip->watcher;	purple_debug_info("simple", "do_notifies()\n");	if((sip->republish != -1) || sip->republish < time(NULL)) {		if(purple_account_get_bool(sip->account, "dopublish", TRUE)) {			send_publish(sip);		}	}	while(tmp) {		purple_debug_info("simple", "notifying %s\n", ((struct simple_watcher*)tmp->data)->name);		send_notify(sip, tmp->data);		tmp = tmp->next;	}}static void simple_set_status(PurpleAccount *account, PurpleStatus *status) {	PurpleStatusPrimitive primitive = purple_status_type_get_primitive(purple_status_get_type(status));	struct simple_account_data *sip = NULL;	if (!purple_status_is_active(status))		return;	if (account->gc)		sip = account->gc->proto_data;	if (sip)	{		g_free(sip->status);		if (primitive == PURPLE_STATUS_AVAILABLE)			sip->status = g_strdup("available");		else			sip->status = g_strdup("busy");		do_notifies(sip);	}}static struct sip_connection *connection_find(struct simple_account_data *sip, int fd) {	struct sip_connection *ret = NULL;	GSList *entry = sip->openconns;	while(entry) {		ret = entry->data;		if(ret->fd == fd) return ret;		entry = entry->next;	}	return NULL;}static struct simple_watcher *watcher_find(struct simple_account_data *sip,		const gchar *name) {	struct simple_watcher *watcher;	GSList *entry = sip->watcher;	while(entry) {		watcher = entry->data;		if(!strcmp(name, watcher->name)) return watcher;		entry = entry->next;	}	return NULL;}static struct simple_watcher *watcher_create(struct simple_account_data *sip,		const gchar *name, const gchar *callid, const gchar *ourtag,		const gchar *theirtag, gboolean needsxpidf) {	struct simple_watcher *watcher = g_new0(struct simple_watcher, 1);	watcher->name = g_strdup(name);	watcher->dialog.callid = g_strdup(callid);	watcher->dialog.ourtag = g_strdup(ourtag);	watcher->dialog.theirtag = g_strdup(theirtag);	watcher->needsxpidf = needsxpidf;	sip->watcher = g_slist_append(sip->watcher, watcher);	return watcher;}static void watcher_remove(struct simple_account_data *sip, const gchar *name) {	struct simple_watcher *watcher = watcher_find(sip, name);	sip->watcher = g_slist_remove(sip->watcher, watcher);	g_free(watcher->name);	g_free(watcher->dialog.callid);	g_free(watcher->dialog.ourtag);	g_free(watcher->dialog.theirtag);	g_free(watcher);}static struct sip_connection *connection_create(struct simple_account_data *sip, int fd) {	struct sip_connection *ret = g_new0(struct sip_connection, 1);	ret->fd = fd;	sip->openconns = g_slist_append(sip->openconns, ret);	return ret;}static void connection_remove(struct simple_account_data *sip, int fd) {	struct sip_connection *conn = connection_find(sip, fd);	sip->openconns = g_slist_remove(sip->openconns, conn);	if(conn->inputhandler) purple_input_remove(conn->inputhandler);	g_free(conn->inbuf);	g_free(conn);}static void connection_free_all(struct simple_account_data *sip) {	struct sip_connection *ret = NULL;	GSList *entry = sip->openconns;	while(entry) {		ret = entry->data;		connection_remove(sip, ret->fd);		entry = sip->openconns;	}}static void simple_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group){	struct simple_account_data *sip = (struct simple_account_data *)gc->proto_data;	struct simple_buddy *b;	if(strncmp("sip:", buddy->name, 4)) {		gchar *buf = g_strdup_printf("sip:%s", buddy->name);		purple_blist_rename_buddy(buddy, buf);		g_free(buf);	}	if(!g_hash_table_lookup(sip->buddies, buddy->name)) {		b = g_new0(struct simple_buddy, 1);		purple_debug_info("simple", "simple_add_buddy %s\n", buddy->name);		b->name = g_strdup(buddy->name);		g_hash_table_insert(sip->buddies, b->name, b);	} else {		purple_debug_info("simple", "buddy %s already in internal list\n", buddy->name);	}}static void simple_get_buddies(PurpleConnection *gc) {	PurpleBlistNode *gnode, *cnode, *bnode;	purple_debug_info("simple", "simple_get_buddies\n");	for(gnode = purple_get_blist()->root; gnode; gnode = gnode->next) {		if(!PURPLE_BLIST_NODE_IS_GROUP(gnode)) continue;		for(cnode = gnode->child; cnode; cnode = cnode->next) {			if(!PURPLE_BLIST_NODE_IS_CONTACT(cnode)) continue;			for(bnode = cnode->child; bnode; bnode = bnode->next) {				if(!PURPLE_BLIST_NODE_IS_BUDDY(bnode)) continue;				if(((PurpleBuddy*)bnode)->account == gc->account)					simple_add_buddy(gc, (PurpleBuddy*)bnode, (PurpleGroup *)gnode);			}		}	}}static void simple_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group){	struct simple_account_data *sip = (struct simple_account_data *)gc->proto_data;	struct simple_buddy *b = g_hash_table_lookup(sip->buddies, buddy->name);	g_hash_table_remove(sip->buddies, buddy->name);	g_free(b->name);	g_free(b);}static GList *simple_status_types(PurpleAccount *acc) {	PurpleStatusType *type;	GList *types = NULL;	type = purple_status_type_new_with_attrs(		PURPLE_STATUS_AVAILABLE, NULL, NULL, TRUE, TRUE, FALSE,		"message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),		NULL);	types = g_list_append(types, type);	type = purple_status_type_new_full(		PURPLE_STATUS_OFFLINE, NULL, NULL, TRUE, TRUE, FALSE);	types = g_list_append(types, type);	return types;}static gchar *auth_header(struct simple_account_data *sip,		struct sip_auth *auth, const gchar *method, const gchar *target) {	gchar noncecount[9];	gchar *response;	gchar *ret;	gchar *tmp;	const char *authdomain;	const char *authuser;	authdomain = purple_account_get_string(sip->account, "authdomain", "");	authuser = purple_account_get_string(sip->account, "authuser", sip->username);	if(!authuser || strlen(authuser) < 1) {		authuser = sip->username;	}	if(auth->type == 1) { /* Digest */		sprintf(noncecount, "%08d", auth->nc++);		response = purple_cipher_http_digest_calculate_response(							"md5", method, target, NULL, NULL,							auth->nonce, noncecount, NULL, auth->digest_session_key);		purple_debug(PURPLE_DEBUG_MISC, "simple", "response %s\n", response);		ret = g_strdup_printf("Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", nc=\"%s\", response=\"%s\"", authuser, auth->realm, auth->nonce, target, noncecount, response);		g_free(response);		return ret;	} else if(auth->type == 2) { /* NTLM */		if(auth->nc == 3 && auth->nonce) {			/* TODO: Don't hardcode "purple" as the hostname */			ret = purple_ntlm_gen_type3(authuser, sip->password, "purple", authdomain, (const guint8 *)auth->nonce, &auth->flags);			tmp = g_strdup_printf("NTLM qop=\"auth\", opaque=\"%s\", realm=\"%s\", targetname=\"%s\", gssapi-data=\"%s\"", auth->opaque, auth->realm, auth->target, ret);			g_free(ret);			return tmp;		}		tmp = g_strdup_printf("NTLM qop=\"auth\", realm=\"%s\", targetname=\"%s\", gssapi-data=\"\"", auth->realm, auth->target);		return tmp;	}	sprintf(noncecount, "%08d", auth->nc++);	response = purple_cipher_http_digest_calculate_response(						"md5", method, target, NULL, NULL,						auth->nonce, noncecount, NULL, auth->digest_session_key);	purple_debug(PURPLE_DEBUG_MISC, "simple", "response %s\n", response);	ret = g_strdup_printf("Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", nc=\"%s\", response=\"%s\"", authuser, auth->realm, auth->nonce, target, noncecount, response);	g_free(response);	return ret;}static char *parse_attribute(const char *attrname, const char *source) {	const char *tmp, *tmp2;	char *retval = NULL;	int len = strlen(attrname);	if(!strncmp(source, attrname, len)) {		tmp = source + len;		tmp2 = g_strstr_len(tmp, strlen(tmp), "\"");		if(tmp2)			retval = g_strndup(tmp, tmp2 - tmp);		else			retval = g_strdup(tmp);	}	return retval;}static void fill_auth(struct simple_account_data *sip, gchar *hdr, struct sip_auth *auth) {	int i = 0;	const char *authuser;	char *tmp;	gchar **parts;	authuser = purple_account_get_string(sip->account, "authuser", sip->username);	if(!authuser || strlen(authuser) < 1) {		authuser = sip->username;	}	if(!hdr) {		purple_debug_error("simple", "fill_auth: hdr==NULL\n");		return;	}	if(!g_strncasecmp(hdr, "NTLM", 4)) {		purple_debug_info("simple", "found NTLM\n");		auth->type = 2;		parts = g_strsplit(hdr+5, "\", ", 0);		i = 0;		while(parts[i]) {			purple_debug_info("simple", "parts[i] %s\n", parts[i]);			if((tmp = parse_attribute("gssapi-data=\"", parts[i]))) {				auth->nonce = g_memdup(purple_ntlm_parse_type2(tmp, &auth->flags), 8);				g_free(tmp);			}			if((tmp = parse_attribute("targetname=\"",					parts[i]))) {				auth->target = tmp;			}			else if((tmp = parse_attribute("realm=\"",					parts[i]))) {				auth->realm = tmp;			}			else if((tmp = parse_attribute("opaque=\"", parts[i]))) {				auth->opaque = tmp;			}			i++;		}		g_strfreev(parts);		auth->nc = 1;		if(!strstr(hdr, "gssapi-data")) {			auth->nc = 1;		} else {			auth->nc = 3;                }		return;	}	auth->type = 1;	parts = g_strsplit(hdr, " ", 0);	while(parts[i]) {		if((tmp = parse_attribute("nonce=\"", parts[i]))) {			auth->nonce = tmp;		}		else if((tmp = parse_attribute("realm=\"", parts[i]))) {			auth->realm = tmp;		}		i++;	}	g_strfreev(parts);	purple_debug(PURPLE_DEBUG_MISC, "simple", "nonce: %s realm: %s\n", auth->nonce ? auth->nonce : "(null)", auth->realm ? auth->realm : "(null)");	if(auth->realm) {		auth->digest_session_key = purple_cipher_http_digest_calculate_session_key(				"md5", authuser, auth->realm, sip->password, auth->nonce, NULL);		auth->nc = 1;	}}static void simple_canwrite_cb(gpointer data, gint source, PurpleInputCondition cond) {	PurpleConnection *gc = data;	struct simple_account_data *sip = gc->proto_data;	gsize max_write;	gssize written;	max_write = purple_circ_buffer_get_max_read(sip->txbuf);	if(max_write == 0) {		purple_input_remove(sip->tx_handler);		sip->tx_handler = 0;		return;	}	written = write(sip->fd, sip->txbuf->outptr, max_write);	if(written < 0 && errno == EAGAIN)		written = 0;	else if(written <= 0) {		/*TODO: do we really want to disconnect on a failure to write?*/		purple_connection_error(gc, _("Could not write"));		return;	}	purple_circ_buffer_mark_read(sip->txbuf, written);}static void simple_input_cb(gpointer data, gint source, PurpleInputCondition cond);static void send_later_cb(gpointer data, gint source, const gchar *error) {	PurpleConnection *gc = data;	struct simple_account_data *sip;	struct sip_connection *conn;	if (!PURPLE_CONNECTION_IS_VALID(gc))	{		if (source >= 0)			close(source);		return;	}	if(source < 0) {		purple_connection_error(gc, _("Could not connect"));		return;	}	sip = gc->proto_data;	sip->fd = source;	sip->connecting = FALSE;	simple_canwrite_cb(gc, sip->fd, PURPLE_INPUT_WRITE);	/* If there is more to write now, we need to register a handler */	if(sip->txbuf->bufused > 0)		sip->tx_handler = purple_input_add(sip->fd, PURPLE_INPUT_WRITE,			simple_canwrite_cb, gc);	conn = connection_create(sip, source);	conn->inputhandler = purple_input_add(sip->fd, PURPLE_INPUT_READ, simple_input_cb, gc);}static void sendlater(PurpleConnection *gc, const char *buf) {	struct simple_account_data *sip = gc->proto_data;	if(!sip->connecting) {		purple_debug_info("simple", "connecting to %s port %d\n", sip->realhostname ? sip->realhostname : "{NULL}", sip->realport);		if (purple_proxy_connect(gc, sip->account, sip->realhostname, sip->realport, send_later_cb, gc) == NULL) {			purple_connection_error(gc, _("Couldn't create socket"));		}		sip->connecting = TRUE;	}

⌨️ 快捷键说明

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