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

📄 simple.c

📁 Linux下的多协议即时通讯程序源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	if(purple_circ_buffer_get_max_read(sip->txbuf) > 0)		purple_circ_buffer_append(sip->txbuf, "\r\n", 2);	purple_circ_buffer_append(sip->txbuf, buf, strlen(buf));}static void sendout_pkt(PurpleConnection *gc, const char *buf) {	struct simple_account_data *sip = gc->proto_data;	time_t currtime = time(NULL);	int writelen = strlen(buf);	purple_debug(PURPLE_DEBUG_MISC, "simple", "\n\nsending - %s\n######\n%s\n######\n\n", ctime(&currtime), buf);	if(sip->udp) {		if(sendto(sip->fd, buf, writelen, 0, (struct sockaddr*)&sip->serveraddr, sizeof(struct sockaddr_in)) < writelen) {			purple_debug_info("simple", "could not send packet\n");		}	} else {		int ret;		if(sip->fd < 0) {			sendlater(gc, buf);			return;		}		if(sip->tx_handler) {			ret = -1;			errno = EAGAIN;		} else			ret = write(sip->fd, buf, writelen);		if (ret < 0 && errno == EAGAIN)			ret = 0;		else if(ret <= 0) { /* XXX: When does this happen legitimately? */			sendlater(gc, buf);			return;		}		if (ret < writelen) {			if(!sip->tx_handler)				sip->tx_handler = purple_input_add(sip->fd,					PURPLE_INPUT_WRITE, simple_canwrite_cb,					gc);			/* XXX: is it OK to do this? You might get part of a request sent			   with part of another. */			if(sip->txbuf->bufused > 0)				purple_circ_buffer_append(sip->txbuf, "\r\n", 2);			purple_circ_buffer_append(sip->txbuf, buf + ret,				writelen - ret);		}	}}static int simple_send_raw(PurpleConnection *gc, const char *buf, int len){	sendout_pkt(gc, buf);	return len;}static void sendout_sipmsg(struct simple_account_data *sip, struct sipmsg *msg) {	GSList *tmp = msg->headers;	gchar *name;	gchar *value;	GString *outstr = g_string_new("");	g_string_append_printf(outstr, "%s %s SIP/2.0\r\n", msg->method, msg->target);	while(tmp) {		name = ((struct siphdrelement*) (tmp->data))->name;		value = ((struct siphdrelement*) (tmp->data))->value;		g_string_append_printf(outstr, "%s: %s\r\n", name, value);		tmp = g_slist_next(tmp);	}	g_string_append_printf(outstr, "\r\n%s", msg->body ? msg->body : "");	sendout_pkt(sip->gc, outstr->str);	g_string_free(outstr, TRUE);}static void send_sip_response(PurpleConnection *gc, struct sipmsg *msg, int code,		const char *text, const char *body) {	GSList *tmp = msg->headers;	gchar *name;	gchar *value;	GString *outstr = g_string_new("");	/* When sending the acknowlegements and errors, the content length from the original	   message is still here, but there is no body; we need to make sure we're sending the	   correct content length */	sipmsg_remove_header(msg, "Content-Length");	if(body) {		gchar len[12];		sprintf(len, "%" G_GSIZE_FORMAT , strlen(body));		sipmsg_add_header(msg, "Content-Length", len);	}	else		sipmsg_add_header(msg, "Content-Length", "0");	g_string_append_printf(outstr, "SIP/2.0 %d %s\r\n", code, text);	while(tmp) {		name = ((struct siphdrelement*) (tmp->data))->name;		value = ((struct siphdrelement*) (tmp->data))->value;		g_string_append_printf(outstr, "%s: %s\r\n", name, value);		tmp = g_slist_next(tmp);	}	g_string_append_printf(outstr, "\r\n%s", body ? body : "");	sendout_pkt(gc, outstr->str);	g_string_free(outstr, TRUE);}static void transactions_remove(struct simple_account_data *sip, struct transaction *trans) {	if(trans->msg) sipmsg_free(trans->msg);	sip->transactions = g_slist_remove(sip->transactions, trans);	g_free(trans);}static void transactions_add_buf(struct simple_account_data *sip, const gchar *buf, void *callback) {	struct transaction *trans = g_new0(struct transaction, 1);	trans->time = time(NULL);	trans->msg = sipmsg_parse_msg(buf);	trans->cseq = sipmsg_find_header(trans->msg, "CSeq");	trans->callback = callback;	sip->transactions = g_slist_append(sip->transactions, trans);}static struct transaction *transactions_find(struct simple_account_data *sip, struct sipmsg *msg) {	struct transaction *trans;	GSList *transactions = sip->transactions;	gchar *cseq = sipmsg_find_header(msg, "CSeq");	if (cseq) {		while(transactions) {			trans = transactions->data;			if(!strcmp(trans->cseq, cseq)) {				return trans;			}			transactions = transactions->next;		}	} else {		purple_debug(PURPLE_DEBUG_MISC, "simple", "Received message contains no CSeq header.\n");	}	return NULL;}static void send_sip_request(PurpleConnection *gc, const gchar *method,		const gchar *url, const gchar *to, const gchar *addheaders,		const gchar *body, struct sip_dialog *dialog, TransCallback tc) {	struct simple_account_data *sip = gc->proto_data;	char *callid = dialog ? g_strdup(dialog->callid) : gencallid();	char *auth = NULL;	const char *addh = "";	gchar *branch = genbranch();	gchar *tag = NULL;	char *buf;	if(!strcmp(method, "REGISTER")) {		if(sip->regcallid) {			g_free(callid);			callid = g_strdup(sip->regcallid);		}		else sip->regcallid = g_strdup(callid);	}	if(addheaders) addh = addheaders;	if(sip->registrar.type && !strcmp(method, "REGISTER")) {		buf = auth_header(sip, &sip->registrar, method, url);		auth = g_strdup_printf("Authorization: %s\r\n", buf);		g_free(buf);		purple_debug(PURPLE_DEBUG_MISC, "simple", "header %s", auth);	} else if(sip->proxy.type && strcmp(method, "REGISTER")) {		buf = auth_header(sip, &sip->proxy, method, url);		auth = g_strdup_printf("Proxy-Authorization: %s\r\n", buf);		g_free(buf);		purple_debug(PURPLE_DEBUG_MISC, "simple", "header %s", auth);	}	if (!dialog)		tag = gentag();	buf = g_strdup_printf("%s %s SIP/2.0\r\n"			"Via: SIP/2.0/%s %s:%d;branch=%s\r\n"			/* Don't know what epid is, but LCS wants it */			"From: <sip:%s@%s>;tag=%s;epid=1234567890\r\n"			"To: <%s>%s%s\r\n"			"Max-Forwards: 10\r\n"			"CSeq: %d %s\r\n"			"User-Agent: Purple/" VERSION "\r\n"			"Call-ID: %s\r\n"			"%s%s"			"Content-Length: %" G_GSIZE_FORMAT "\r\n\r\n%s",			method,			url,			sip->udp ? "UDP" : "TCP",			purple_network_get_my_ip(-1),			sip->listenport,			branch,			sip->username,			sip->servername,			dialog ? dialog->ourtag : tag,			to,			dialog ? ";tag=" : "",			dialog ? dialog->theirtag : "",			++sip->cseq,			method,			callid,			auth ? auth : "",			addh,			strlen(body),			body);	g_free(tag);	g_free(auth);	g_free(branch);	g_free(callid);	/* add to ongoing transactions */	transactions_add_buf(sip, buf, tc);	sendout_pkt(gc, buf);	g_free(buf);}static char *get_contact(struct simple_account_data  *sip) {	return g_strdup_printf("<sip:%s@%s:%d;transport=%s>;methods=\"MESSAGE, SUBSCRIBE, NOTIFY\"", sip->username, purple_network_get_my_ip(-1), sip->listenport, sip->udp ? "udp" : "tcp");}static void do_register_exp(struct simple_account_data *sip, int expire) {	char *uri = g_strdup_printf("sip:%s", sip->servername);	char *to = g_strdup_printf("sip:%s@%s", sip->username, sip->servername);	char *contact = get_contact(sip);	char *hdr = g_strdup_printf("Contact: %s\r\nExpires: %d\r\n", contact, expire);	g_free(contact);	sip->registerstatus = 1;	if(expire) {		sip->reregister = time(NULL) + expire - 50;	} else {		sip->reregister = time(NULL) + 600;	}	send_sip_request(sip->gc, "REGISTER", uri, to, hdr, "", NULL,		process_register_response);	g_free(hdr);	g_free(uri);	g_free(to);}static void do_register(struct simple_account_data *sip) {	do_register_exp(sip, sip->registerexpire);}static gchar *parse_from(const gchar *hdr) {	gchar *from;	const gchar *tmp, *tmp2 = hdr;	if(!hdr) return NULL;	purple_debug_info("simple", "parsing address out of %s\n", hdr);	tmp = strchr(hdr, '<');	/* i hate the different SIP UA behaviours... */	if(tmp) { /* sip address in <...> */		tmp2 = tmp + 1;		tmp = strchr(tmp2, '>');		if(tmp) {			from = g_strndup(tmp2, tmp - tmp2);		} else {			purple_debug_info("simple", "found < without > in From\n");			return NULL;		}	} else {		tmp = strchr(tmp2, ';');		if(tmp) {			from = g_strndup(tmp2, tmp - tmp2);		} else {			from = g_strdup(tmp2);		}	}	purple_debug_info("simple", "got %s\n", from);	return from;}static gboolean process_subscribe_response(struct simple_account_data *sip, struct sipmsg *msg, struct transaction *tc) {	gchar *to;	if(msg->response == 200 || msg->response == 202) {		return TRUE;	}	to = parse_from(sipmsg_find_header(tc->msg, "To")); /* cant be NULL since it is our own msg */	/* we can not subscribe -> user is offline (TODO unknown status?) */	purple_prpl_got_user_status(sip->account, to, "offline", NULL);	g_free(to);	return TRUE;}static void simple_subscribe(struct simple_account_data *sip, struct simple_buddy *buddy) {	gchar *contact = "Expires: 1200\r\nAccept: application/pidf+xml, application/xpidf+xml\r\nEvent: presence\r\n";	gchar *to;	gchar *tmp;	if(strstr(buddy->name, "sip:"))		to = g_strdup(buddy->name);	else		to = g_strdup_printf("sip:%s", buddy->name);	tmp = get_contact(sip);	contact = g_strdup_printf("%sContact: %s\r\n", contact, tmp);	g_free(tmp);	/* subscribe to buddy presence	 * we dont need to know the status so we do not need a callback */	send_sip_request(sip->gc, "SUBSCRIBE", to, to, contact, "", NULL,		process_subscribe_response);	g_free(to);	g_free(contact);	/* resubscribe before subscription expires */	/* add some jitter */	buddy->resubscribe = time(NULL)+1140+(rand()%50);}static gboolean simple_add_lcs_contacts(struct simple_account_data *sip, struct sipmsg *msg, struct transaction *tc) {	gchar *tmp;	xmlnode *item, *group, *isc;	const char *name_group;	PurpleBuddy *b;	PurpleGroup *g = NULL;	struct simple_buddy *bs;	int len = msg->bodylen;	tmp = sipmsg_find_header(msg, "Event");	if(tmp && !strncmp(tmp, "vnd-microsoft-roaming-contacts", 30)){		purple_debug_info("simple", "simple_add_lcs_contacts->%s-%d\n", msg->body, len);		/*Convert the contact from XML to Purple Buddies*/		isc = xmlnode_from_str(msg->body, len);		/* ToDo. Find for all groups */		if ((group = xmlnode_get_child(isc, "group"))) {			name_group = xmlnode_get_attrib(group, "name");			purple_debug_info("simple", "name_group->%s\n", name_group);			g = purple_find_group(name_group);			if(!g)				g = purple_group_new(name_group);		}		if (!g) {			g = purple_find_group("Buddies");			if(!g)				g = purple_group_new("Buddies");		}		for(item = xmlnode_get_child(isc, "contact"); item; item = xmlnode_get_next_twin(item))		{			const char *uri, *name, *groups;			char *buddy_name;			uri = xmlnode_get_attrib(item, "uri");			name = xmlnode_get_attrib(item, "name");			groups = xmlnode_get_attrib(item, "groups");			purple_debug_info("simple", "URI->%s\n", uri);			buddy_name = g_strdup_printf("sip:%s", uri);			b = purple_find_buddy(sip->account, buddy_name);			if(!b){				b = purple_buddy_new(sip->account, buddy_name, uri);			}			g_free(buddy_name);			purple_blist_add_buddy(b, NULL, g, NULL);			purple_blist_alias_buddy(b, uri);			bs = g_new0(struct simple_buddy, 1);			bs->name = g_strdup(b->name);			g_hash_table_insert(sip->buddies, bs->name, bs);		}		xmlnode_free(isc);	}	return 0;}static void simple_subscribe_buddylist(struct simple_account_data *sip) {	gchar *contact = "Event: vnd-microsoft-roaming-contacts\r\nAccept: application/vnd-microsoft-roaming-contacts+xml\r\nSupported: com.microsoft.autoextend\r\nSupported: ms-benotify\r\nProxy-Require: ms-benotify\r\nSupported: ms-piggyback-first-notify\r\n";	gchar *to;	gchar *tmp;	to = g_strdup_printf("sip:%s@%s", sip->username, sip->servername);	tmp = get_contact(sip);	contact = g_strdup_printf("%sContact: %s\r\n", contact, tmp);	g_free(tmp);	send_sip_request(sip->gc, "SUBSCRIBE", to, to, contact, "", NULL, simple_add_lcs_contacts);	g_free(to);	g_free(contact);}static void simple_buddy_resub(char *name, struct simple_buddy *buddy, struct simple_account_data *sip) {	time_t curtime = time(NULL);	purple_debug_info("simple", "buddy resub\n");	if(buddy->resubscribe < curtime) {		purple_debug(PURPLE_DEBUG_MISC, "simple", "simple_buddy_resub %s\n", name);		simple_subscribe(sip, buddy);	}}static gboolean resend_timeout(struct simple_account_data *sip) {	GSList *tmp = sip->transactions;	time_t currtime = time(NULL);	while(tmp) {		struct transaction *trans = tmp->data;		tmp = tmp->next;		purple_debug_info("simple", "have open transaction age: %d\n", currtime- trans->time);		if((currtime - trans->time > 5) && trans->retries >= 1) {			/* TODO 408 */		} else {			if((currtime - trans->time > 2) && trans->retries == 0) {				trans->retries++;				sendout_sipmsg(sip, trans->msg);			}		}	}	return TRUE;}static gboolean subscribe_timeout(struct simple_account_data *sip) {	GSList *tmp;	time_t curtime = time(NULL);	/* register again if first registration expires */	if(sip->reregister < curtime) {		do_register(sip);	}	/* check for every subscription if we need to resubscribe */	g_hash_table_foreach(sip->buddies, (GHFunc)simple_buddy_resub, (gpointer)sip);	/* remove a timed out suscriber */	tmp = sip->watcher;	while(tmp) {		struct simple_watcher *watcher = tmp->data;		if(watcher->expire < curtime) {			watcher_remove(sip, watcher->name);			tmp = sip->watcher;		}		if(tmp) tmp = tmp->next;	}	return TRUE;}static void simple_send_message(struct simple_account_data *sip, const char *to, const char *msg, const char *type) {	gchar *hdr;	gchar *fullto;	if(strncmp("sip:", to, 4)) {		fullto = g_strdup_printf("sip:%s", to);	} else {		fullto = g_strdup(to);	}	if(type) {		hdr = g_strdup_printf("Content-Type: %s\r\n", type);

⌨️ 快捷键说明

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