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

📄 simple.c

📁 Linux下的多协议即时通讯程序源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	} else {		hdr = g_strdup("Content-Type: text/plain\r\n");	}	send_sip_request(sip->gc, "MESSAGE", fullto, fullto, hdr, msg, NULL, NULL);	g_free(hdr);	g_free(fullto);}static int simple_im_send(PurpleConnection *gc, const char *who, const char *what, PurpleMessageFlags flags) {	struct simple_account_data *sip = gc->proto_data;	char *to = g_strdup(who);	char *text = purple_unescape_html(what);	simple_send_message(sip, to, text, NULL);	g_free(to);	g_free(text);	return 1;}static void process_incoming_message(struct simple_account_data *sip, struct sipmsg *msg) {	gchar *from;	gchar *contenttype;	gboolean found = FALSE;	from = parse_from(sipmsg_find_header(msg, "From"));	if(!from) return;	purple_debug(PURPLE_DEBUG_MISC, "simple", "got message from %s: %s\n", from, msg->body);	contenttype = sipmsg_find_header(msg, "Content-Type");	if(!contenttype || !strncmp(contenttype, "text/plain", 10) || !strncmp(contenttype, "text/html", 9)) {		serv_got_im(sip->gc, from, msg->body, 0, time(NULL));		send_sip_response(sip->gc, msg, 200, "OK", NULL);		found = TRUE;	}	if(!strncmp(contenttype, "application/im-iscomposing+xml", 30)) {		xmlnode *isc = xmlnode_from_str(msg->body, msg->bodylen);		xmlnode *state;		gchar *statedata;		if(!isc) {			purple_debug_info("simple", "process_incoming_message: can not parse iscomposing\n");			return;		}		state = xmlnode_get_child(isc, "state");		if(!state) {				purple_debug_info("simple", "process_incoming_message: no state found\n");				xmlnode_free(isc);			return;		}		statedata = xmlnode_get_data(state);		if(statedata) {			if(strstr(statedata, "active")) serv_got_typing(sip->gc, from, 0, PURPLE_TYPING);			else serv_got_typing_stopped(sip->gc, from);			g_free(statedata);		}		xmlnode_free(isc);		send_sip_response(sip->gc, msg, 200, "OK", NULL);		found = TRUE;	}	if(!found) {		purple_debug_info("simple", "got unknown mime-type");		send_sip_response(sip->gc, msg, 415, "Unsupported media type", NULL);	}	g_free(from);}gboolean process_register_response(struct simple_account_data *sip, struct sipmsg *msg, struct transaction *tc) {	gchar *tmp;	purple_debug(PURPLE_DEBUG_MISC, "simple", "in process register response response: %d\n", msg->response);	switch (msg->response) {		case 200:			if(sip->registerstatus < 3) { /* registered */				if(purple_account_get_bool(sip->account, "dopublish", TRUE)) {					send_publish(sip);				}			}			sip->registerstatus = 3;			purple_connection_set_state(sip->gc, PURPLE_CONNECTED);			/* get buddies from blist */			simple_get_buddies(sip->gc);			subscribe_timeout(sip);			tmp = sipmsg_find_header(msg, "Allow-Events");		        if(tmp && strstr(tmp, "vnd-microsoft-provisioning")){				simple_subscribe_buddylist(sip);			}			break;		case 401:			if(sip->registerstatus != 2) {				purple_debug_info("simple", "REGISTER retries %d\n", sip->registrar.retries);				if(sip->registrar.retries > 3) {					sip->gc->wants_to_die = TRUE;					purple_connection_error(sip->gc, _("Incorrect password."));					return TRUE;				}				tmp = sipmsg_find_header(msg, "WWW-Authenticate");				fill_auth(sip, tmp, &sip->registrar);				sip->registerstatus = 2;				do_register(sip);			}			break;		}	return TRUE;}static void process_incoming_notify(struct simple_account_data *sip, struct sipmsg *msg) {	gchar *from;	gchar *fromhdr;	gchar *tmp2;	xmlnode *pidf;	xmlnode *basicstatus = NULL, *tuple, *status;	gboolean isonline = FALSE;	fromhdr = sipmsg_find_header(msg, "From");	from = parse_from(fromhdr);	if(!from) return;	pidf = xmlnode_from_str(msg->body, msg->bodylen);	if(!pidf) {		purple_debug_info("simple", "process_incoming_notify: no parseable pidf\n");		return;	}	if ((tuple = xmlnode_get_child(pidf, "tuple")))		if ((status = xmlnode_get_child(tuple, "status")))			basicstatus = xmlnode_get_child(status, "basic");	if(!basicstatus) {		purple_debug_info("simple", "process_incoming_notify: no basic found\n");		xmlnode_free(pidf);		return;	}	tmp2 = xmlnode_get_data(basicstatus);	if(!tmp2) {		purple_debug_info("simple", "process_incoming_notify: no basic data found\n");		xmlnode_free(pidf);		return;	}	if(strstr(tmp2, "open")) {		isonline = TRUE;	}	g_free(tmp2);	if(isonline) purple_prpl_got_user_status(sip->account, from, "available", NULL);	else purple_prpl_got_user_status(sip->account, from, "offline", NULL);	xmlnode_free(pidf);	g_free(from);	send_sip_response(sip->gc, msg, 200, "OK", NULL);}static unsigned int simple_typing(PurpleConnection *gc, const char *name, PurpleTypingState state) {	struct simple_account_data *sip = gc->proto_data;	gchar *xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"			"<isComposing xmlns=\"urn:ietf:params:xml:ns:im-iscomposing\"\n"			"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"			"xsi:schemaLocation=\"urn:ietf:params:xml:ns:im-composing iscomposing.xsd\">\n"			"<state>%s</state>\n"			"<contenttype>text/plain</contenttype>\n"			"<refresh>60</refresh>\n"			"</isComposing>";	gchar *recv = g_strdup(name);	if(state == PURPLE_TYPING) {		gchar *msg = g_strdup_printf(xml, "active");		simple_send_message(sip, recv, msg, "application/im-iscomposing+xml");		g_free(msg);	} else /* TODO: Only if (state == PURPLE_TYPED) ? */ {		gchar *msg = g_strdup_printf(xml, "idle");		simple_send_message(sip, recv, msg, "application/im-iscomposing+xml");		g_free(msg);	}	g_free(recv);	/*	 * TODO: Is this right?  It will cause the core to call	 *       serv_send_typing(gc, who, PURPLE_TYPING) once every second	 *       until the user stops typing.  If that's not desired,	 *       then return 0 instead.	 */	return 1;}static gchar *find_tag(const gchar *hdr) {	const gchar *tmp = strstr(hdr, ";tag="), *tmp2;	if(!tmp) return NULL;	tmp += 5;	if((tmp2 = strchr(tmp, ';'))) {		return g_strndup(tmp, tmp2 - tmp);	}	return g_strdup(tmp);}static gchar* gen_xpidf(struct simple_account_data *sip) {	gchar *doc = g_strdup_printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"			"<presence>\n"			"<presentity uri=\"sip:%s@%s;method=SUBSCRIBE\"/>\n"			"<display name=\"sip:%s@%s\"/>\n"			"<atom id=\"1234\">\n"			"<address uri=\"sip:%s@%s\">\n"			"<status status=\"%s\"/>\n"			"</address>\n"			"</atom>\n"			"</presence>\n",			sip->username,			sip->servername,			sip->username,			sip->servername,			sip->username,			sip->servername,			sip->status);	return doc;}static gchar* gen_pidf(struct simple_account_data *sip) {	gchar *doc = g_strdup_printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"			"<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n"			"xmlns:im=\"urn:ietf:params:xml:ns:pidf:im\"\n"			"entity=\"sip:%s@%s\">\n"			"<tuple id=\"bs35r9f\">\n"			"<status>\n"			"<basic>open</basic>\n"			"</status>\n"			"<note>%s</note>\n"			"</tuple>\n"			"</presence>",			sip->username,			sip->servername,			sip->status);	return doc;}static void send_notify(struct simple_account_data *sip, struct simple_watcher *watcher) {	gchar *doc = watcher->needsxpidf ? gen_xpidf(sip) : gen_pidf(sip);	gchar *hdr = watcher->needsxpidf ? "Event: presence\r\nContent-Type: application/xpidf+xml\r\n" : "Event: presence\r\nContent-Type: application/pidf+xml\r\n";	send_sip_request(sip->gc, "NOTIFY", watcher->name, watcher->name, hdr, doc, &watcher->dialog, NULL);	g_free(doc);}static gboolean process_publish_response(struct simple_account_data *sip, struct sipmsg *msg, struct transaction *tc) {	if(msg->response != 200 && msg->response != 408) {		/* never send again */		sip->republish = -1;	}	return TRUE;}static void send_publish(struct simple_account_data *sip) {	gchar *uri = g_strdup_printf("sip:%s@%s", sip->username, sip->servername);	gchar *doc = gen_pidf(sip);	send_sip_request(sip->gc, "PUBLISH", uri, uri,		"Expires: 600\r\nEvent: presence\r\n"		"Content-Type: application/pidf+xml\r\n",		doc, NULL, process_publish_response);	sip->republish = time(NULL) + 500;	g_free(uri);	g_free(doc);}static void process_incoming_subscribe(struct simple_account_data *sip, struct sipmsg *msg) {	const char *from_hdr = sipmsg_find_header(msg, "From");	gchar *from = parse_from(from_hdr);	gchar *theirtag = find_tag(from_hdr);	gchar *ourtag = find_tag(sipmsg_find_header(msg, "To"));	gboolean tagadded = FALSE;	gchar *callid = sipmsg_find_header(msg, "Call-ID");	gchar *expire = sipmsg_find_header(msg, "Expire");	gchar *tmp;	struct simple_watcher *watcher = watcher_find(sip, from);	if(!ourtag) {		tagadded = TRUE;		ourtag = gentag();	}	if(!watcher) { /* new subscription */		gchar *acceptheader = sipmsg_find_header(msg, "Accept");		gboolean needsxpidf = FALSE;		if(!purple_privacy_check(sip->account, from)) {			send_sip_response(sip->gc, msg, 202, "Ok", NULL);			goto privend;		}		if(acceptheader) {			gchar *tmp = acceptheader;			gboolean foundpidf = FALSE;			gboolean foundxpidf = FALSE;			while(tmp && tmp < acceptheader + strlen(acceptheader)) {				gchar *tmp2 = strchr(tmp, ',');				if(tmp2) *tmp2 = '\0';				if(!g_ascii_strcasecmp("application/pidf+xml", tmp))					foundpidf = TRUE;				if(!g_ascii_strcasecmp("application/xpidf+xml", tmp))					foundxpidf = TRUE;				if(tmp2) {					*tmp2 = ',';					tmp = tmp2 + 1;					while(*tmp == ' ') tmp++;				} else					tmp = 0;			}			if(!foundpidf && foundxpidf) needsxpidf = TRUE;			g_free(acceptheader);		}		watcher = watcher_create(sip, from, callid, ourtag, theirtag, needsxpidf);	}	if(tagadded) {		gchar *to = g_strdup_printf("%s;tag=%s", sipmsg_find_header(msg, "To"), ourtag);		sipmsg_remove_header(msg, "To");		sipmsg_add_header(msg, "To", to);		g_free(to);	}	if(expire)		watcher->expire = time(NULL) + strtol(expire, NULL, 10);	else		watcher->expire = time(NULL) + 600;	sipmsg_remove_header(msg, "Contact");	tmp = get_contact(sip);	sipmsg_add_header(msg, "Contact", tmp);	g_free(tmp);	purple_debug_info("simple", "got subscribe: name %s ourtag %s theirtag %s callid %s\n", watcher->name, watcher->dialog.ourtag, watcher->dialog.theirtag, watcher->dialog.callid);	send_sip_response(sip->gc, msg, 200, "Ok", NULL);	send_notify(sip, watcher);privend:	g_free(from);	g_free(theirtag);	g_free(ourtag);	g_free(callid);	g_free(expire);}static void process_input_message(struct simple_account_data *sip, struct sipmsg *msg) {	gboolean found = FALSE;	if(msg->response == 0) { /* request */		if(!strcmp(msg->method, "MESSAGE")) {			process_incoming_message(sip, msg);			found = TRUE;		} else if(!strcmp(msg->method, "NOTIFY")) {			process_incoming_notify(sip, msg);			found = TRUE;		} else if(!strcmp(msg->method, "SUBSCRIBE")) {			process_incoming_subscribe(sip, msg);			found = TRUE;		} else {			send_sip_response(sip->gc, msg, 501, "Not implemented", NULL);		}	} else { /* response */		struct transaction *trans = transactions_find(sip, msg);		if(trans) {			if(msg->response == 407) {				gchar *resend, *auth, *ptmp;				if(sip->proxy.retries > 3) return;				sip->proxy.retries++;				/* do proxy authentication */				ptmp = sipmsg_find_header(msg, "Proxy-Authenticate");				fill_auth(sip, ptmp, &sip->proxy);				auth = auth_header(sip, &sip->proxy, trans->msg->method, trans->msg->target);				sipmsg_remove_header(trans->msg, "Proxy-Authorization");				sipmsg_add_header(trans->msg, "Proxy-Authorization", auth);				g_free(auth);				resend = sipmsg_to_string(trans->msg);				/* resend request */				sendout_pkt(sip->gc, resend);				g_free(resend);			} else {				if(msg->response == 100) {					/* ignore provisional response */					purple_debug_info("simple", "got trying response\n");				} else {					sip->proxy.retries = 0;					if(!strcmp(trans->msg->method, "REGISTER")) {						if(msg->response == 401) sip->registrar.retries++;						else sip->registrar.retries = 0;					} else {						if(msg->response == 401) {							gchar *resend, *auth, *ptmp;							if(sip->registrar.retries > 4) return;							sip->registrar.retries++;							ptmp = sipmsg_find_header(msg, "WWW-Authenticate");							fill_auth(sip, ptmp, &sip->registrar);							auth = auth_header(sip, &sip->registrar, trans->msg->method, trans->msg->target);							sipmsg_remove_header(trans->msg, "Authorization");							sipmsg_add_header(trans->msg, "Authorization", auth);							g_free(auth);							resend = sipmsg_to_string(trans->msg);							/* resend request */							sendout_pkt(sip->gc, resend);							g_free(resend);						}					}					if(trans->callback) {						/* call the callback to process response*/						(trans->callback)(sip, msg, trans);					}					transactions_remove(sip, trans);				}			}			found = TRUE;		} else {			purple_debug(PURPLE_DEBUG_MISC, "simple", "received response to unknown transaction");		}	}	if(!found) {		purple_debug(PURPLE_DEBUG_MISC, "simple", "received a unknown sip message with method %s and response %d\n", msg->method, msg->response);	}}static void process_input(struct simple_account_data *sip, struct sip_connection *conn){	char *cur;	char *dummy;	struct sipmsg *msg;	int restlen;	cur = conn->inbuf;	/* according to the RFC remove CRLF at the beginning */	while(*cur == '\r' || *cur == '\n') {		cur++;	}	if(cur != conn->inbuf) {		memmove(conn->inbuf, cur, conn->inbufused - (cur - conn->inbuf));		conn->inbufused = strlen(conn->inbuf);	}	/* Received a full Header? */	if((cur = strstr(conn->inbuf, "\r\n\r\n")) != NULL) {		time_t currtime = time(NULL);		cur += 2;		cur[0] = '\0';		purple_debug_info("simple", "\n\nreceived - %s\n######\n%s\n#######\n\n", ctime(&currtime), conn->inbuf);		msg = sipmsg_parse_header(conn->inbuf);		cur[0] = '\r';		cur += 2;		restlen = conn->inbufused - (cur - conn->inbuf);		if(restlen >= msg->bodylen) {			dummy = g_malloc(msg->bodylen + 1);			memcpy(dummy, cur, msg->bodylen);			dummy[msg->bodylen] = '\0';			msg->body = dummy;			cur += msg->bodylen;			memmove(conn->inbuf, cur, conn->inbuflen - (cur - conn->inbuf));			conn->inbufused = strlen(conn->inbuf);		} else {			sipmsg_free(msg);			return;		}		purple_debug(PURPLE_DEBUG_MISC, "simple", "in process response response: %d\n", msg->response);		process_input_message(sip, msg);	} else {

⌨️ 快捷键说明

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