void process_incoming_refer(struct sipe_core_private *sipe_private,
			    struct sipmsg *msg)
{
	gchar *self = sip_uri_self(sipe_private);
	const gchar *callid = sipmsg_find_header(msg, "Call-ID");
	gchar *from = parse_from(sipmsg_find_header(msg, "From"));
	gchar *refer_to = parse_from(sipmsg_find_header(msg, "Refer-to"));
	gchar *referred_by = g_strdup(sipmsg_find_header(msg, "Referred-By"));
	struct sip_session *session;
	struct sip_dialog *dialog;

	session = sipe_session_find_chat_by_callid(sipe_private, callid);
	dialog = sipe_dialog_find(session, from);

	if (!session || !dialog || !session->chat_session ||
	    (session->chat_session->type != SIPE_CHAT_TYPE_MULTIPARTY) ||
	    !session->chat_session->id ||
	    !sipe_strcase_equal(session->chat_session->id, self)) {
		sip_transport_response(sipe_private, msg, 500, "Server Internal Error", NULL);
	} else {
		sip_transport_response(sipe_private, msg, 202, "Accepted", NULL);

		sipe_im_invite(sipe_private, session, refer_to, NULL, NULL, referred_by, FALSE);
	}

	g_free(self);
	g_free(from);
	g_free(refer_to);
	g_free(referred_by);
}
Пример #2
0
void
sipe_process_imdn(struct sipe_core_private *sipe_private,
		  struct sipmsg *msg)
{
	gchar *with = parse_from(sipmsg_find_header(msg, "From"));
	const gchar *callid = sipmsg_find_header(msg, "Call-ID");
	static struct sip_session *session;
	sipe_xml *xn_imdn;
	const sipe_xml *node;
	gchar *message_id;
	gchar *message;

	session = sipe_session_find_chat_or_im(sipe_private, callid, with);
	if (!session) {
		SIPE_DEBUG_INFO("sipe_process_imdn: unable to find conf session with callid=%s", callid);
		g_free(with);
		return;
	}

	xn_imdn = sipe_xml_parse(msg->body, msg->bodylen);
	message_id = sipe_xml_data(sipe_xml_child(xn_imdn, "message-id"));

	message = g_hash_table_lookup(session->conf_unconfirmed_messages, message_id);

	/* recipient */
	for (node = sipe_xml_child(xn_imdn, "recipient"); node; node = sipe_xml_twin(node)) {
		gchar *tmp = parse_from(sipe_xml_attribute(node, "uri"));
		gchar *uri = parse_from(tmp);
		gchar *status = sipe_xml_data(sipe_xml_child(node, "status"));
		guint error = status ? g_ascii_strtoull(status, NULL, 10) : 0;
		/* default to error if missing or conversion failed */
		if ((error == 0) || (error >= 300))
			sipe_user_present_message_undelivered(sipe_private,
							      session,
							      error,
							      -1,
							      uri,
							      message);
		g_free(status);
		g_free(tmp);
		g_free(uri);
	}

	sipe_xml_free(xn_imdn);

	g_hash_table_remove(session->conf_unconfirmed_messages, message_id);
	SIPE_DEBUG_INFO("sipe_process_imdn: removed message %s from conf_unconfirmed_messages(count=%d)",
			message_id, g_hash_table_size(session->conf_unconfirmed_messages));
	g_free(message_id);
	g_free(with);
}
Пример #3
0
Файл: from.c Проект: kusune/from
int from(POP_SESSION *psp, int msg, int width)
{
    int header, state;

    if (pop_sendcmd(psp, POP_CMD_TOP, msg, 0) != POP_OK) {
	fprintf(stderr, "Can not retrieve message %d\n", msg);
	if (psp->status != POP_ERR) {
	    return psp->status;
	}
	pop_session_close(psp);
	exit(EX_PROTOCOL);
    }
    header = 1, state = 0;
    *heading[HEAD_DATE] = NUL;
    *heading[HEAD_FROM] = NUL;
    *heading[HEAD_SUBJ] = NUL;
    *heading[HEAD_MSGID] = NUL;
    *heading[HEAD_SENDER] = NUL;
    do {
	char *p;

	if (pop_recvmlresp(psp) == POP_EXCEPTION) {
	    if (psp->resp != NULL) {
		perror("read error");
	    }
	    exit(EX_PROTOCOL);
	}

	p = psp->resp;

	if (*p == NUL || *p == '\n')	/* null line */
	    continue;
	if (header) {
	    if (isspace((int)*p) && state) {
		strcat(heading[state], "\n");
		strcat(heading[state], p);
	    } else if (strncasecmp(p, "from:", 5) == 0)
		strcpy(heading[state = HEAD_FROM], p);
	    else if (strncasecmp(p, "date:", 5) == 0)
		strcpy(heading[state = HEAD_DATE], p);
	    else if (strncasecmp(p, "subject:", 8) == 0)
		strcpy(heading[state = HEAD_SUBJ], p);
	    else if (strncasecmp(p, "message-id:", 11) == 0)
		strcpy(heading[state = HEAD_MSGID], p);
	    else if (strncasecmp(p, "sender:", 7) == 0)
		strcpy(heading[state = HEAD_SENDER], p);
	    else
		state = 0;
	}
    } while (psp->status == POP_CONT);

    printf("%3d %s %-30s %s\n", msg,
	   parse_date(heading[HEAD_DATE]),
	   parse_from(heading[HEAD_FROM]),
	   parse_subj(heading[HEAD_SUBJ], width - 48));

    return psp->status;
}
Пример #4
0
/** Invite us to the focus callback */
static gboolean
process_invite_conf_focus_response(struct sipe_core_private *sipe_private,
				   struct sipmsg *msg,
				   SIPE_UNUSED_PARAMETER struct transaction *trans)
{
	struct sip_session *session = NULL;
	char *focus_uri = parse_from(sipmsg_find_header(msg, "To"));

	session = sipe_session_find_conference(sipe_private, focus_uri);

	if (!session) {
		SIPE_DEBUG_INFO("process_invite_conf_focus_response: unable to find conf session with focus=%s", focus_uri);
		g_free(focus_uri);
		return FALSE;
	}

	if (!session->focus_dialog) {
		SIPE_DEBUG_INFO_NOFORMAT("process_invite_conf_focus_response: session's focus_dialog is NULL");
		g_free(focus_uri);
		return FALSE;
	}

	sipe_dialog_parse(session->focus_dialog, msg, TRUE);

	if (msg->response >= 200) {
		/* send ACK to focus */
		session->focus_dialog->cseq = 0;
		sip_transport_ack(sipe_private, session->focus_dialog);
		session->focus_dialog->outgoing_invite = NULL;
		session->focus_dialog->is_established = TRUE;
	}

	if (msg->response >= 400) {
		SIPE_DEBUG_INFO_NOFORMAT("process_invite_conf_focus_response: INVITE response is not 200. Failed to join focus.");
		/* @TODO notify user of failure to join focus */
		sipe_session_remove(sipe_private, session);
		g_free(focus_uri);
		return FALSE;
	} else if (msg->response == 200) {
		sipe_xml *xn_response = sipe_xml_parse(msg->body, msg->bodylen);
		const gchar *code = sipe_xml_attribute(xn_response, "code");
		if (sipe_strequal(code, "success")) {
			/* subscribe to focus */
			sipe_subscribe_conference(sipe_private, session, FALSE);
		}
		sipe_xml_free(xn_response);
	}

	g_free(focus_uri);
	return TRUE;
}
Пример #5
0
static gboolean process_info_typing_response(struct sipe_core_private *sipe_private,
					     struct sipmsg *msg,
					     SIPE_UNUSED_PARAMETER struct transaction *trans)
{
	/* Indicates dangling IM session which needs to be dropped */
	if (msg->response == 408 || /* Request timeout */
	    msg->response == 480 || /* Temporarily Unavailable */
	    msg->response == 481) { /* Call/Transaction Does Not Exist */
		gchar *with = parse_from(sipmsg_find_header(msg, "To"));
		struct sip_session *session = sipe_session_find_im(sipe_private, with);
		struct sip_dialog *dialog = sipe_dialog_find(session, with);
		if (dialog)
			sipe_im_cancel_dangling(sipe_private, session, dialog, with,
						sipe_im_cancel_unconfirmed);
		g_free(with);
	}	
	return(TRUE);
}
Пример #6
0
Файл: main.c Проект: runt18/bap
void
predefine(fn_list *ifile) {
	struct rule *r;
	for (;ifile; ifile = ifile->next) {
		parse_from(ifile->filename);
	}
  
	for (r = rules; r; r = r->next) {
		/* struct without rule definitions are created when names are used
		they are != null when the rule was actually defined */
		if (r->rule) 
			r->predefined = 1;
		else
			r->used = 1;

		if (r->next == rules)
			break;
	}
}
Пример #7
0
/** Invite counterparty to join conference callback */
static gboolean
process_invite_conf_response(struct sipe_core_private *sipe_private,
			     struct sipmsg *msg,
			     SIPE_UNUSED_PARAMETER struct transaction *trans)
{
	struct sip_dialog *dialog = g_new0(struct sip_dialog, 1);

	dialog->callid = g_strdup(sipmsg_find_header(msg, "Call-ID"));
	dialog->cseq = sipmsg_parse_cseq(msg);
	dialog->with = parse_from(sipmsg_find_header(msg, "To"));
	sipe_dialog_parse(dialog, msg, TRUE);

	if (msg->response >= 200) {
		/* send ACK to counterparty */
		dialog->cseq--;
		sip_transport_ack(sipe_private, dialog);
		dialog->outgoing_invite = NULL;
		dialog->is_established = TRUE;
	}

	if (msg->response >= 400) {
		SIPE_DEBUG_INFO("process_invite_conf_response: INVITE response is not 200. Failed to invite %s.", dialog->with);
		/* @TODO notify user of failure to invite counterparty */
		sipe_dialog_free(dialog);
		return FALSE;
	}

	if (msg->response >= 200) {
		struct sip_session *session = sipe_session_find_im(sipe_private, dialog->with);
		struct sip_dialog *im_dialog = sipe_dialog_find(session, dialog->with);

		/* close IM session to counterparty */
		if (im_dialog) {
			sip_transport_bye(sipe_private, im_dialog);
			sipe_dialog_remove(session, dialog->with);
		}
	}

	sipe_dialog_free(dialog);
	return TRUE;
}
Пример #8
0
Файл: main.c Проект: runt18/bap
int
main(int argc, char **argv)
{
	int ch;
	int rc = 0;
	struct rule *r;
	fn_list *pre_input = NULL;
  
#ifdef YYDEBUG
	extern int yydebug;

	yydebug = 0;
#endif
	hcreate(MAXRULE);

	while ((ch = getopt(argc, argv, "cdi:kntqS:")) != -1) {
		switch (ch) {
		case 'c':
			cflag++;
			break;

		case 'd':
#ifdef YYDEBUG
			yydebug = 1;
#else
			fprintf(stderr, "Rebuild with -DYYDEBUG to use -d.\n");
#endif
			break;

		case 'k':
			c2flag++;
			break;

		case 'n':
			canon = 0;
			break;

		case 'i': {
			fn_list *ifile = calloc(sizeof(fn_list), 1);
			ifile->filename = optarg;
			ifile->next = pre_input;
			pre_input = ifile;
			break;
		}
      
		case 't':
			tflag++;
			break;

		case 'p':
			permissive = 0;
			break;

		case 'q':
			qflag++;
			break;

		case 'S': 
			top_rule_name = optarg;
			break;
      
		default:
			usage();
		}
	}
	argc -= optind;
	argv += optind;

	if (argc > 1)
		usage();

	predefine(pre_input);    
  
	/* Parse the grammar, perhaps spouting errors. */
	parse_from((argc > 0)? argv[0] : NULL);

	/* If we're not quiet, then output the grammar again. */
	if (!qflag) {
		if (canon)
			canonify(rules);
		for (r = rules; r; r = r->next) {
			if (r->predefined) {
				/* do not output */
			}
			else if (r->rule) {
				printf("%s = ", r->name);
				printobj(r->rule, tflag);
				if (cflag)
					printf(" ; line %d", r->line);
				printf("\n");
			} else {
				printf("; %s UNDEFINED\n", r->name);
			}
			if (r->next == rules)
				break;
		}
		for (r = rules; r; r = r->next) {
			if (r->used == 0 
				&& r->predefined == 0 
				&& r->rule 
				&& strcmp(r->name, top_rule_name))
				printf("; %s defined but not used\n", r->name);
			if (r->next == rules)
				break;
		}
	}
  
	rc = summary();
	hdestroy();
	exit(rc);
}
Пример #9
0
/** Invite us to the focus callback */
static gboolean
process_invite_conf_focus_response(struct sipe_core_private *sipe_private,
				   struct sipmsg *msg,
				   SIPE_UNUSED_PARAMETER struct transaction *trans)
{
	struct sip_session *session = NULL;
	char *focus_uri = parse_from(sipmsg_find_header(msg, "To"));

	session = sipe_session_find_conference(sipe_private, focus_uri);

	if (!session) {
		SIPE_DEBUG_INFO("process_invite_conf_focus_response: unable to find conf session with focus=%s", focus_uri);
		g_free(focus_uri);
		return FALSE;
	}

	if (!session->focus_dialog) {
		SIPE_DEBUG_INFO_NOFORMAT("process_invite_conf_focus_response: session's focus_dialog is NULL");
		g_free(focus_uri);
		return FALSE;
	}

	sipe_dialog_parse(session->focus_dialog, msg, TRUE);

	if (msg->response >= 200) {
		/* send ACK to focus */
		session->focus_dialog->cseq = 0;
		sip_transport_ack(sipe_private, session->focus_dialog);
		session->focus_dialog->outgoing_invite = NULL;
		session->focus_dialog->is_established = TRUE;
	}

	if (msg->response >= 400) {
		gchar *reason = sipmsg_get_ms_diagnostics_reason(msg);

		SIPE_DEBUG_INFO_NOFORMAT("process_invite_conf_focus_response: INVITE response is not 200. Failed to join focus.");
		sipe_backend_notify_error(SIPE_CORE_PUBLIC,
					  _("Failed to join the conference"),
					  reason ? reason : _("no reason given"));
		g_free(reason);

		sipe_session_remove(sipe_private, session);
		g_free(focus_uri);
		return FALSE;
	} else if (msg->response == 200) {
		sipe_xml *xn_response = sipe_xml_parse(msg->body, msg->bodylen);
		const gchar *code = sipe_xml_attribute(xn_response, "code");
		if (sipe_strequal(code, "success")) {
			/* subscribe to focus */
			sipe_subscribe_conference(sipe_private,
						  session->chat_session->id,
						  FALSE);
#ifdef HAVE_VV
			if (session->is_call)
				sipe_core_media_connect_conference(SIPE_CORE_PUBLIC,
								   session->chat_session);
#endif
		}
		sipe_xml_free(xn_response);
	}

	g_free(focus_uri);
	return TRUE;
}
void process_incoming_message(struct sipe_core_private *sipe_private,
			      struct sipmsg *msg)
{
	gchar *from;
	const gchar *contenttype;
	gboolean found = FALSE;

	from = parse_from(sipmsg_find_header(msg, "From"));

	if (!from) return;

	SIPE_DEBUG_INFO("got message from %s: %s", from, msg->body);

	contenttype = sipmsg_find_header(msg, "Content-Type");
	if (g_str_has_prefix(contenttype, "text/plain")
	    || g_str_has_prefix(contenttype, "text/html")
	    || g_str_has_prefix(contenttype, "multipart/related")
	    || g_str_has_prefix(contenttype, "multipart/alternative"))
	{
		const gchar *callid = sipmsg_find_header(msg, "Call-ID");
		gchar *html = get_html_message(contenttype, msg->body);

		struct sip_session *session = sipe_session_find_chat_or_im(sipe_private,
									   callid,
									   from);
		if (session && session->chat_session) {
			if (session->chat_session->type == SIPE_CHAT_TYPE_CONFERENCE) { /* a conference */
				gchar *tmp = parse_from(sipmsg_find_header(msg, "Ms-Sender"));
				gchar *sender = parse_from(tmp);
				g_free(tmp);
				sipe_backend_chat_message(SIPE_CORE_PUBLIC,
							  session->chat_session->backend,
							  sender,
							  0,
							  html);
				g_free(sender);
			} else { /* a multiparty chat */
				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);
		sip_transport_response(sipe_private, msg, 200, "OK", NULL);
		found = TRUE;

	} else if (g_str_has_prefix(contenttype, "application/im-iscomposing+xml")) {
		sipe_xml *isc = sipe_xml_parse(msg->body, msg->bodylen);
		const sipe_xml *state;
		gchar *statedata;

		if (!isc) {
			SIPE_DEBUG_INFO_NOFORMAT("process_incoming_message: can not parse iscomposing");
			g_free(from);
			return;
		}

		state = sipe_xml_child(isc, "state");

		if (!state) {
			SIPE_DEBUG_INFO_NOFORMAT("process_incoming_message: no state found");
			sipe_xml_free(isc);
			g_free(from);
			return;
		}

		statedata = sipe_xml_data(state);
		if (statedata) {
			if (strstr(statedata, "active")) {
				sipe_backend_user_feedback_typing(SIPE_CORE_PUBLIC,
								  from);
			} else {
				sipe_backend_user_feedback_typing_stop(SIPE_CORE_PUBLIC,
								       from);
			}
			g_free(statedata);
		}
		sipe_xml_free(isc);
		sip_transport_response(sipe_private, msg, 200, "OK", NULL);
		found = TRUE;
	} else if (g_str_has_prefix(contenttype, "text/x-msmsgsinvite")) {
		const gchar *callid = sipmsg_find_header(msg, "Call-ID");
		struct sip_session *session = sipe_session_find_chat_or_im(sipe_private,
									   callid,
									   from);
		if (session) {
			struct sip_dialog *dialog = sipe_dialog_find(session, from);
			GSList *body = sipe_ft_parse_msg_body(msg->body);
			found = sipe_process_incoming_x_msmsgsinvite(sipe_private, dialog, body);
			sipe_utils_nameval_free(body);
			if (found) {
				sip_transport_response(sipe_private, msg, 200, "OK", NULL);
			}
		} else {
			sip_transport_response(sipe_private, msg, 481,
					       "Call Leg/Transaction Does Not Exist", NULL);
			found = TRUE;
		}
	}
	if (!found) {
		const gchar *callid = sipmsg_find_header(msg, "Call-ID");
		struct sip_session *session = sipe_session_find_chat_or_im(sipe_private,
									   callid,
									   from);
		if (session) {
			gchar *errmsg = g_strdup_printf(_("Received a message with unrecognized contents from %s"),
							from);
			sipe_user_present_error(sipe_private, session, errmsg);
			g_free(errmsg);
		}

		SIPE_DEBUG_INFO("got unknown mime-type '%s'", contenttype);
		sip_transport_response(sipe_private, msg, 415, "Unsupported media type", NULL);
	}
	g_free(from);
}
void process_incoming_bye(struct sipe_core_private *sipe_private,
			  struct sipmsg *msg)
{
	const gchar *callid = sipmsg_find_header(msg, "Call-ID");
	gchar *from = parse_from(sipmsg_find_header(msg, "From"));
	struct sip_session *session;
	struct sip_dialog *dialog;

#ifdef HAVE_VV
	if (is_media_session_msg(sipe_private->media_call, msg)) {
		// BYE ends a media call
		sipe_media_hangup(sipe_private->media_call);
	}
#endif

	/* collect dialog identification
	 * we need callid, ourtag and theirtag to unambiguously identify dialog
	 */
	/* take data before 'msg' will be modified by sip_transport_response */
	dialog = g_new0(struct sip_dialog, 1);
	dialog->callid = g_strdup(callid);
	dialog->cseq = sipmsg_parse_cseq(msg);
	dialog->with = g_strdup(from);
	sipe_dialog_parse(dialog, msg, FALSE);

	sip_transport_response(sipe_private, msg, 200, "OK", NULL);

	session = sipe_session_find_chat_or_im(sipe_private, callid, from);
	if (!session) {
		SIPE_DEBUG_INFO_NOFORMAT("process_incoming_bye: couldn't find session. Ignoring");
		sipe_dialog_free(dialog);
		g_free(from);
		return;
	}

	SIPE_DEBUG_INFO("process_incoming_bye: session found (chat ID %s)",
			(session->chat_session && session->chat_session->id) ?
			session->chat_session->id : "<NO CHAT>");

	if (session->chat_session &&
	    (session->chat_session->type == SIPE_CHAT_TYPE_MULTIPARTY) &&
	    session->chat_session->id &&
	    !g_ascii_strcasecmp(from, session->chat_session->id))
		sipe_chat_set_roster_manager(session, NULL);

	sipe_im_cancel_unconfirmed(sipe_private, session, callid, from);

	/* This what BYE is essentially for - terminating dialog */
	sipe_dialog_remove_3(session, dialog);
	sipe_dialog_free(dialog);
	if (session->chat_session) {
		if ((session->chat_session->type == SIPE_CHAT_TYPE_CONFERENCE) &&
		    !g_ascii_strcasecmp(from, session->im_mcu_uri)) {
			SIPE_DEBUG_INFO("process_incoming_bye: disconnected from conference %s",
					session->im_mcu_uri);
			sipe_conf_immcu_closed(sipe_private, session);
		} else if (session->chat_session->type == SIPE_CHAT_TYPE_MULTIPARTY) {
			SIPE_DEBUG_INFO_NOFORMAT("process_incoming_bye: disconnected from multiparty chat");
			sipe_backend_chat_remove(session->chat_session->backend,
						 from);
		}
	}

	g_free(from);
}
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);
}