예제 #1
0
파일: fetion.c 프로젝트: Gankraft/fetion
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, "L");
	if (body) {
		gchar len[12];
		sprintf(len, "%d", (int)strlen(body));
		sipmsg_add_header(msg, "L", len);
	}

	g_string_append_printf(outstr, "SIP-C/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);
}
예제 #2
0
struct sipmsg *sipmsg_copy(const struct sipmsg *other) {
	struct sipmsg *msg = g_new0(struct sipmsg, 1);
	GSList *list;

	msg->response		= other->response;
	msg->responsestr	= g_strdup(other->responsestr);
	msg->method		= g_strdup(other->method);
	msg->target		= g_strdup(other->target);

	list = other->headers;
	while(list) {
		struct sipnameval *elem = list->data;
		sipmsg_add_header_now(msg, elem->name, elem->value);
		list = list->next;
	}

	list = other->new_headers;
	while(list) {
		struct sipnameval *elem = list->data;
		sipmsg_add_header(msg, elem->name, elem->value);
		list = list->next;
	}

	msg->bodylen	= other->bodylen;
	msg->body	= g_memdup(other->body, other->bodylen);
	msg->signature	= g_strdup(other->signature);
	msg->rand	= g_strdup(other->rand);
	msg->num	= g_strdup(other->num);

	return msg;
}
void process_incoming_options(struct sipe_core_private *sipe_private,
			      struct sipmsg *msg)
{
	gchar *body;

	sipmsg_add_header(msg, "Allow", "INVITE, MESSAGE, INFO, SUBSCRIBE, OPTIONS, BYE, CANCEL, NOTIFY, ACK, REFER, BENOTIFY");
	sipmsg_add_header(msg, "Content-Type", "application/sdp");

	body = g_strdup_printf(
		"v=0\r\n"
		"o=- 0 0 IN IP4 0.0.0.0\r\n"
		"s=session\r\n"
		"c=IN IP4 0.0.0.0\r\n"
		"t=0 0\r\n"
		"m=%s %d sip sip:%s\r\n"
		"a=accept-types:" SDP_ACCEPT_TYPES "\r\n",
		SIPE_CORE_PRIVATE_FLAG_IS(OCS2007) ? "message" : "x-ms-message",
		sip_transport_port(sipe_private),
		sipe_private->username);
	sip_transport_response(sipe_private, msg, 200, "OK", body);
	g_free(body);
}
static void send_invite_response(struct sipe_core_private *sipe_private,
				 struct sipmsg *msg)
{
	gchar *body = g_strdup_printf(
		"v=0\r\n"
		"o=- 0 0 IN IP4 %s\r\n"
		"s=session\r\n"
		"c=IN IP4 %s\r\n"
		"t=0 0\r\n"
		"m=%s %d sip sip:%s\r\n"
		"a=accept-types:" SDP_ACCEPT_TYPES "\r\n",
		sipe_backend_network_ip_address(SIPE_CORE_PUBLIC),
		sipe_backend_network_ip_address(SIPE_CORE_PUBLIC),
		SIPE_CORE_PRIVATE_FLAG_IS(OCS2007) ? "message" : "x-ms-message",
		sip_transport_port(sipe_private),
		sipe_private->username);
	sipmsg_add_header(msg, "Content-Type", "application/sdp");
	sip_transport_response(sipe_private, msg, 200, "OK", body);
	g_free(body);
}
예제 #5
0
파일: sipmsg.c 프로젝트: VoxOx/VoxOx
struct sipmsg *sipmsg_parse_header(const gchar *header) {
	struct sipmsg *msg = g_new0(struct sipmsg,1);
	gchar **lines = g_strsplit(header,"\r\n",0);
	gchar **parts;
	gchar *dummy;
	gchar *dummy2;
	gchar *tmp;
	int i=1;
	if(!lines[0]) return NULL;
	parts = g_strsplit(lines[0], " ", 3);
	if(!parts[0] || !parts[1] || !parts[2]) {
		g_strfreev(parts);
		g_strfreev(lines);
		g_free(msg);
		return NULL;
	}
	if(strstr(parts[0],"SIP")) { /* numeric response */
		msg->method = g_strdup(parts[2]);
		msg->response = strtol(parts[1],NULL,10);
	} else { /* request */
		msg->method = g_strdup(parts[0]);
		msg->target = g_strdup(parts[1]);
		msg->response = 0;
	}
	g_strfreev(parts);
	for(i=1; lines[i] && strlen(lines[i])>2; i++) {
		parts = g_strsplit(lines[i], ":", 2);
		if(!parts[0] || !parts[1]) {
			g_strfreev(parts);
			g_strfreev(lines);
			g_free(msg);
			return NULL;
		}
		dummy = parts[1];
		dummy2 = 0;
		while(*dummy==' ' || *dummy=='\t') dummy++;
		dummy2 = g_strdup(dummy);
		while(lines[i+1] && (lines[i+1][0]==' ' || lines[i+1][0]=='\t')) {
			i++;
			dummy = lines[i];
			while(*dummy==' ' || *dummy=='\t') dummy++;
			tmp = g_strdup_printf("%s %s",dummy2, dummy);
			g_free(dummy2);
			dummy2 = tmp;
		}
		sipmsg_add_header(msg, parts[0], dummy2);
		g_strfreev(parts);
	}
	g_strfreev(lines);
	msg->bodylen = strtol(sipmsg_find_header(msg, "Content-Length"),NULL,10);
	if(msg->response) {
		tmp = sipmsg_find_header(msg, "CSeq");
		if(!tmp) {
			/* SHOULD NOT HAPPEN */
			msg->method = 0;
		} else {
			parts = g_strsplit(tmp, " ", 2);
			msg->method = g_strdup(parts[1]);
			g_strfreev(parts);
		}
	}
	return msg;
}
void process_incoming_invite(struct sipe_core_private *sipe_private,
			     struct sipmsg *msg)
{
	gchar *newTag;
	const gchar *oldHeader;
	gchar *newHeader;
	gboolean is_multiparty = FALSE;
	gboolean was_multiparty = TRUE;
	gboolean just_joined = FALSE;
	gchar *from;
	const gchar *callid         = sipmsg_find_header(msg, "Call-ID");
	const gchar *roster_manager = sipmsg_find_header(msg, "Roster-Manager");
	const gchar *end_points_hdr = sipmsg_find_header(msg, "EndPoints");
	const gchar *trig_invite    = sipmsg_find_header(msg, "TriggeredInvite");
	const gchar *content_type   = sipmsg_find_header(msg, "Content-Type");
	const gchar *subject        = sipmsg_find_header(msg, "Subject");
	GSList *end_points = NULL;
	struct sip_session *session;
	struct sip_dialog *dialog;
	const gchar *ms_text_format;
	gboolean dont_delay = FALSE;

#ifdef HAVE_VV
	if (g_str_has_prefix(content_type, "multipart/alternative")) {
		sipe_mime_parts_foreach(content_type, msg->body, sipe_invite_mime_cb, msg);
		/* Reload Content-Type to get type of the selected message part */
		content_type = sipmsg_find_header(msg, "Content-Type");
	}
#endif

	if (g_str_has_prefix(content_type, "multipart/mixed")) {
		sipe_mime_parts_foreach(content_type, msg->body, sipe_invite_mime_mixed_cb, msg);
		/* Reload Content-Type to get type of the selected message part */
		content_type = sipmsg_find_header(msg, "Content-Type");
	}

	/* Lync 2010 file transfer */
	if (g_str_has_prefix(content_type, "application/ms-filetransfer+xml")) {
		sip_transport_response(sipe_private, msg, 488, "Not Acceptable Here", NULL);
		return;
	}

	/* Invitation to join conference */
	if (g_str_has_prefix(content_type, "application/ms-conf-invite+xml")) {
		process_incoming_invite_conf(sipe_private, msg);
		return;
	}

#ifdef HAVE_VV
	/* Invitation to audio call */
	if (msg->body && strstr(msg->body, "m=audio")) {
		process_incoming_invite_call(sipe_private, msg);
		return;
	}
#endif

	/* Only accept text invitations */
	if (msg->body && !(strstr(msg->body, "m=message") || strstr(msg->body, "m=x-ms-message"))) {
		sip_transport_response(sipe_private, msg, 501, "Not implemented", NULL);
		return;
	}

	// TODO There *must* be a better way to clean up the To header to add a tag...
	SIPE_DEBUG_INFO_NOFORMAT("Adding a Tag to the To Header on Invite Request...");
	oldHeader = sipmsg_find_header(msg, "To");
	newTag = gentag();
	newHeader = g_strdup_printf("%s;tag=%s", oldHeader, newTag);
	g_free(newTag);
	sipmsg_remove_header_now(msg, "To");
	sipmsg_add_header_now(msg, "To", newHeader);
	g_free(newHeader);

	if (end_points_hdr) {
		end_points = sipmsg_parse_endpoints_header(end_points_hdr);

		if (g_slist_length(end_points) > 2) {
			is_multiparty = TRUE;
		}
	}
	if (trig_invite && !g_ascii_strcasecmp(trig_invite, "TRUE")) {
		is_multiparty = TRUE;
	}

	/* Multiparty session */
	session = sipe_session_find_chat_by_callid(sipe_private, callid);
	if (is_multiparty) {

		if (session) {
			if (session->chat_session) {
				/* Update roster manager for existing multiparty session */
				if (roster_manager)
					sipe_chat_set_roster_manager(session, roster_manager);

			} else {
				gchar *chat_title = sipe_chat_get_name();

				/* Convert IM session to multiparty session */
				g_free(session->with);
				session->with = NULL;
				was_multiparty = FALSE;
				session->chat_session = sipe_chat_create_session(SIPE_CHAT_TYPE_MULTIPARTY,
										 roster_manager,
										 chat_title);

				g_free(chat_title);
			}
		} else {
			/* New multiparty session */
			session = sipe_session_add_chat(sipe_private,
							NULL,
							TRUE,
							roster_manager);
		}

		/* Create chat */
		if (!session->chat_session->backend) {
			gchar *self = sip_uri_self(sipe_private);
			session->chat_session->backend = sipe_backend_chat_create(SIPE_CORE_PUBLIC,
										  session->chat_session,
										  session->chat_session->title,
										  self);
			g_free(self);
		}
	}

	/* IM session */
	from = parse_from(sipmsg_find_header(msg, "From"));
	if (!session)
		session = sipe_session_find_or_add_im(sipe_private, from);

	/* session is now initialized */
	g_free(session->callid);
	session->callid = g_strdup(callid);

	if (is_multiparty && end_points) {
		gchar *to = parse_from(sipmsg_find_header(msg, "To"));
		GSList *entry = end_points;
		while (entry) {
			struct sipendpoint *end_point = entry->data;
			entry = entry->next;

			if (!g_ascii_strcasecmp(from, end_point->contact) ||
			    !g_ascii_strcasecmp(to,   end_point->contact))
				continue;

			dialog = sipe_dialog_find(session, end_point->contact);
			if (dialog) {
				g_free(dialog->theirepid);
				dialog->theirepid = end_point->epid;
				end_point->epid = NULL;
			} else {
				dialog = sipe_dialog_add(session);

				dialog->callid = g_strdup(session->callid);
				dialog->with = end_point->contact;
				end_point->contact = NULL;
				dialog->theirepid = end_point->epid;
				end_point->epid = NULL;

				just_joined = TRUE;

				/* send triggered INVITE */
				sipe_im_invite(sipe_private, session, dialog->with, NULL, NULL, NULL, TRUE);
			}
		}
		g_free(to);
	}

	if (end_points) {
		GSList *entry = end_points;
		while (entry) {
			struct sipendpoint *end_point = entry->data;
			entry = entry->next;
			g_free(end_point->contact);
			g_free(end_point->epid);
			g_free(end_point);
		}
		g_slist_free(end_points);
	}

	dialog = sipe_dialog_find(session, from);
	if (dialog) {
		sipe_im_cancel_dangling(sipe_private, session, dialog, from,
					sipe_im_reenqueue_unconfirmed);
		/* dialog is no longer valid */
	} else {
		just_joined = TRUE;
	}

	dialog = sipe_dialog_add(session);
	dialog->with = g_strdup(from);
	dialog->callid = g_strdup(session->callid);
	dialog->is_established = TRUE;
	sipe_dialog_parse(dialog, msg, FALSE);

	if (is_multiparty && !was_multiparty) {
		/* add current IM counterparty to chat */
		sipe_backend_chat_add(session->chat_session->backend,
				      sipe_dialog_first(session)->with,
				      FALSE);
	}

	/* add inviting party to chat */
	if (just_joined && session->chat_session) {
		sipe_backend_chat_add(session->chat_session->backend,
				      from,
				      TRUE);
	}

	if (!is_multiparty && subject)
		sipe_im_topic(sipe_private, session, subject);

	/* ms-text-format: text/plain; charset=UTF-8;msgr=WAAtAE0...DIADQAKAA0ACgA;ms-body=SGk= */

	/* This used only in 2005 official client, not 2007 or Reuters.
	   Disabled for most cases as interfering with audit of messages which only is applied to regular MESSAGEs.
	   Only enabled for 2005 multiparty chats as otherwise the first message got lost completely.
	*/
	/* also enabled for 2005 file transfer. Didn't work otherwise. */
	ms_text_format = sipmsg_find_header(msg, "ms-text-format");
	if (is_multiparty ||
	    (ms_text_format && g_str_has_prefix(ms_text_format, "text/x-msmsgsinvite")) )
	{
		if (ms_text_format) {
			if (g_str_has_prefix(ms_text_format, "text/x-msmsgsinvite"))
			{
				dont_delay = TRUE;
			}
			else if (g_str_has_prefix(ms_text_format, "text/plain") || g_str_has_prefix(ms_text_format, "text/html"))
			{
				/* please do not optimize logic inside as this code may be re-enabled for other cases */
				gchar *html = get_html_message(ms_text_format, NULL);
				if (html) {
					if (is_multiparty) {
						sipe_backend_chat_message(SIPE_CORE_PUBLIC,
									  session->chat_session->backend,
									  from,
									  0,
									  html);
					} else {
						sipe_backend_im_message(SIPE_CORE_PUBLIC,
									from,
									html);
					}
					g_free(html);
					sipmsg_add_header(msg, "Supported", "ms-text-format"); /* accepts received message */
					dont_delay = TRUE;
				}
			}
		}
	}

	g_free(from);

	sipmsg_add_header(msg, "Supported", "com.microsoft.rtc-multiparty");

	if (dont_delay || !SIPE_CORE_PRIVATE_FLAG_IS(MPOP)) {
		send_invite_response(sipe_private, msg);
	} else {
		delayed_invite_response(sipe_private, msg, session->callid);
	}
}
void process_incoming_info(struct sipe_core_private *sipe_private,
			   struct sipmsg *msg)
{
	const gchar *contenttype = sipmsg_find_header(msg, "Content-Type");
	const gchar *callid = sipmsg_find_header(msg, "Call-ID");
	gchar *from;
	struct sip_session *session;

	SIPE_DEBUG_INFO_NOFORMAT("process_incoming_info");

	/* Call Control protocol */
	if (g_str_has_prefix(contenttype, "application/csta+xml"))
	{
		process_incoming_info_csta(sipe_private, msg);
		return;
	}
	else if (g_str_has_prefix(contenttype, "application/xml+conversationinfo"))
	{
		process_incoming_info_conversation(sipe_private, msg);
		return;
	}

	from = parse_from(sipmsg_find_header(msg, "From"));
	session = sipe_session_find_chat_or_im(sipe_private, callid, from);
	if (!session) {
		g_free(from);
		return;
	}

	/* Group Chat uses text/plain */
	if (session->is_groupchat) {
		process_incoming_info_groupchat(sipe_private, msg, session);
		g_free(from);
		return;
	}

	if (g_str_has_prefix(contenttype, "application/x-ms-mim"))
	{
		sipe_xml *xn_action           = sipe_xml_parse(msg->body, msg->bodylen);
		const sipe_xml *xn_request_rm = sipe_xml_child(xn_action, "RequestRM");
		const sipe_xml *xn_set_rm     = sipe_xml_child(xn_action, "SetRM");

		sipmsg_add_header(msg, "Content-Type", "application/x-ms-mim");

		if (xn_request_rm) {
			//const char *rm = sipe_xml_attribute(xn_request_rm, "uri");
			int bid = sipe_xml_int_attribute(xn_request_rm, "bid", 0);
			gchar *body = g_strdup_printf(
				"<?xml version=\"1.0\"?>\r\n"
				"<action xmlns=\"http://schemas.microsoft.com/sip/multiparty/\">"
				"<RequestRMResponse uri=\"sip:%s\" allow=\"%s\"/></action>\r\n",
				sipe_private->username,
				session->bid < bid ? "true" : "false");
			sip_transport_response(sipe_private, msg, 200, "OK", body);
			g_free(body);
		} else if (xn_set_rm) {
			gchar *body;

			sipe_chat_set_roster_manager(session,
						     sipe_xml_attribute(xn_set_rm, "uri"));

			body = g_strdup_printf(
				"<?xml version=\"1.0\"?>\r\n"
				"<action xmlns=\"http://schemas.microsoft.com/sip/multiparty/\">"
				"<SetRMResponse uri=\"sip:%s\"/></action>\r\n",
				sipe_private->username);
			sip_transport_response(sipe_private, msg, 200, "OK", body);
			g_free(body);
		}
		sipe_xml_free(xn_action);

	}
	else
	{
		/* looks like purple lacks typing notification for chat */
		if (!session->chat_session) {
			sipe_xml *xn_keyboard_activity  = sipe_xml_parse(msg->body, msg->bodylen);
			const char *status = sipe_xml_attribute(sipe_xml_child(xn_keyboard_activity, "status"),
								"status");
			if (sipe_strequal(status, "type")) {
				sipe_backend_user_feedback_typing(SIPE_CORE_PUBLIC,
								  from);
			} else if (sipe_strequal(status, "idle")) {
				sipe_backend_user_feedback_typing_stop(SIPE_CORE_PUBLIC,
								       from);
			}
			sipe_xml_free(xn_keyboard_activity);
		}

		sip_transport_response(sipe_private, msg, 200, "OK", NULL);
	}
	g_free(from);
}