soap: fix crash in temporary hack
[siplcs.git] / src / core / sipe-incoming.c
blob2ad4d767bf8b40c53d8934f7e3650c251d7d931b
1 /**
2 * @file sipe-incoming.c
4 * pidgin-sipe
6 * Copyright (C) 2010-2013 SIPE Project <http://sipe.sourceforge.net/>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
27 #include <stdlib.h>
28 #include <string.h>
30 #include <glib.h>
32 #include "sipe-common.h"
33 #include "sipmsg.h"
34 #include "sip-csta.h"
35 #include "sip-transport.h"
36 #include "sipe-backend.h"
37 #include "sipe-chat.h"
38 #include "sipe-conf.h"
39 #include "sipe-core.h"
40 #include "sipe-core-private.h"
41 #include "sipe-dialog.h"
42 #include "sipe-ft.h"
43 #include "sipe-groupchat.h"
44 #include "sipe-im.h"
45 #include "sipe-incoming.h"
46 #include "sipe-media.h"
47 #include "sipe-mime.h"
48 #include "sipe-nls.h"
49 #include "sipe-schedule.h"
50 #include "sipe-session.h"
51 #include "sipe-user.h"
52 #include "sipe-utils.h"
53 #include "sipe-xml.h"
55 void process_incoming_bye(struct sipe_core_private *sipe_private,
56 struct sipmsg *msg)
58 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
59 gchar *from = parse_from(sipmsg_find_header(msg, "From"));
60 struct sip_session *session;
61 struct sip_dialog *dialog;
63 #ifdef HAVE_VV
64 if (is_media_session_msg(sipe_private->media_call, msg)) {
65 // BYE ends a media call
66 sipe_media_hangup(sipe_private->media_call);
68 #endif
70 /* collect dialog identification
71 * we need callid, ourtag and theirtag to unambiguously identify dialog
73 /* take data before 'msg' will be modified by sip_transport_response */
74 dialog = g_new0(struct sip_dialog, 1);
75 dialog->callid = g_strdup(callid);
76 dialog->cseq = sipmsg_parse_cseq(msg);
77 dialog->with = g_strdup(from);
78 sipe_dialog_parse(dialog, msg, FALSE);
80 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
82 session = sipe_session_find_chat_or_im(sipe_private, callid, from);
83 if (!session) {
84 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_bye: couldn't find session. Ignoring");
85 sipe_dialog_free(dialog);
86 g_free(from);
87 return;
90 SIPE_DEBUG_INFO("process_incoming_bye: session found (chat ID %s)",
91 (session->chat_session && session->chat_session->id) ?
92 session->chat_session->id : "<NO CHAT>");
94 if (session->chat_session &&
95 (session->chat_session->type == SIPE_CHAT_TYPE_MULTIPARTY) &&
96 session->chat_session->id &&
97 !g_ascii_strcasecmp(from, session->chat_session->id))
98 sipe_chat_set_roster_manager(session, NULL);
100 sipe_im_cancel_unconfirmed(sipe_private, session, callid, from);
102 /* This what BYE is essentially for - terminating dialog */
103 sipe_dialog_remove_3(session, dialog);
104 sipe_dialog_free(dialog);
105 if (session->chat_session) {
106 if ((session->chat_session->type == SIPE_CHAT_TYPE_CONFERENCE) &&
107 !g_ascii_strcasecmp(from, session->im_mcu_uri)) {
108 SIPE_DEBUG_INFO("process_incoming_bye: disconnected from conference %s",
109 session->im_mcu_uri);
110 sipe_conf_immcu_closed(sipe_private, session);
111 } else if (session->chat_session->type == SIPE_CHAT_TYPE_MULTIPARTY) {
112 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_bye: disconnected from multiparty chat");
113 sipe_backend_chat_remove(session->chat_session->backend,
114 from);
118 g_free(from);
121 void process_incoming_cancel(struct sipe_core_private *sipe_private,
122 struct sipmsg *msg)
124 const gchar *callid;
126 #ifdef HAVE_VV
127 if (is_media_session_msg(sipe_private->media_call, msg)) {
128 process_incoming_cancel_call(sipe_private, msg);
129 return;
131 #endif
132 callid = sipmsg_find_header(msg, "Call-ID");
134 if (!sipe_session_find_chat_by_callid(sipe_private, callid))
135 sipe_conf_cancel_unaccepted(sipe_private, msg);
138 void process_incoming_info(struct sipe_core_private *sipe_private,
139 struct sipmsg *msg)
141 const gchar *contenttype = sipmsg_find_header(msg, "Content-Type");
142 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
143 gchar *from;
144 struct sip_session *session;
146 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_info");
148 /* Call Control protocol */
149 if (g_str_has_prefix(contenttype, "application/csta+xml"))
151 process_incoming_info_csta(sipe_private, msg);
152 return;
154 else if (g_str_has_prefix(contenttype, "application/xml+conversationinfo"))
156 process_incoming_info_conversation(sipe_private, msg);
157 return;
160 from = parse_from(sipmsg_find_header(msg, "From"));
161 session = sipe_session_find_chat_or_im(sipe_private, callid, from);
162 if (!session) {
163 g_free(from);
164 return;
167 /* Group Chat uses text/plain */
168 if (session->is_groupchat) {
169 process_incoming_info_groupchat(sipe_private, msg, session);
170 g_free(from);
171 return;
174 if (g_str_has_prefix(contenttype, "application/x-ms-mim"))
176 sipe_xml *xn_action = sipe_xml_parse(msg->body, msg->bodylen);
177 const sipe_xml *xn_request_rm = sipe_xml_child(xn_action, "RequestRM");
178 const sipe_xml *xn_set_rm = sipe_xml_child(xn_action, "SetRM");
180 sipmsg_add_header(msg, "Content-Type", "application/x-ms-mim");
182 if (xn_request_rm) {
183 //const char *rm = sipe_xml_attribute(xn_request_rm, "uri");
184 int bid = sipe_xml_int_attribute(xn_request_rm, "bid", 0);
185 gchar *body = g_strdup_printf(
186 "<?xml version=\"1.0\"?>\r\n"
187 "<action xmlns=\"http://schemas.microsoft.com/sip/multiparty/\">"
188 "<RequestRMResponse uri=\"sip:%s\" allow=\"%s\"/></action>\r\n",
189 sipe_private->username,
190 session->bid < bid ? "true" : "false");
191 sip_transport_response(sipe_private, msg, 200, "OK", body);
192 g_free(body);
193 } else if (xn_set_rm) {
194 gchar *body;
196 sipe_chat_set_roster_manager(session,
197 sipe_xml_attribute(xn_set_rm, "uri"));
199 body = g_strdup_printf(
200 "<?xml version=\"1.0\"?>\r\n"
201 "<action xmlns=\"http://schemas.microsoft.com/sip/multiparty/\">"
202 "<SetRMResponse uri=\"sip:%s\"/></action>\r\n",
203 sipe_private->username);
204 sip_transport_response(sipe_private, msg, 200, "OK", body);
205 g_free(body);
207 sipe_xml_free(xn_action);
210 else
212 /* looks like purple lacks typing notification for chat */
213 if (!session->chat_session) {
214 sipe_xml *xn_keyboard_activity = sipe_xml_parse(msg->body, msg->bodylen);
215 const char *status = sipe_xml_attribute(sipe_xml_child(xn_keyboard_activity, "status"),
216 "status");
217 if (sipe_strequal(status, "type")) {
218 sipe_backend_user_feedback_typing(SIPE_CORE_PUBLIC,
219 from);
220 } else if (sipe_strequal(status, "idle")) {
221 sipe_backend_user_feedback_typing_stop(SIPE_CORE_PUBLIC,
222 from);
224 sipe_xml_free(xn_keyboard_activity);
227 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
229 g_free(from);
232 static gboolean sipe_process_incoming_x_msmsgsinvite(struct sipe_core_private *sipe_private,
233 struct sip_dialog *dialog,
234 GSList *parsed_body)
236 gboolean found = FALSE;
238 if (parsed_body) {
239 const gchar *invitation_command = sipe_utils_nameval_find(parsed_body, "Invitation-Command");
241 if (sipe_strequal(invitation_command, "INVITE")) {
242 sipe_ft_incoming_transfer(sipe_private, dialog, parsed_body);
243 found = TRUE;
244 } else if (sipe_strequal(invitation_command, "CANCEL")) {
245 sipe_ft_incoming_cancel(dialog, parsed_body);
246 found = TRUE;
247 } else if (sipe_strequal(invitation_command, "ACCEPT")) {
248 sipe_ft_incoming_accept(dialog, parsed_body);
249 found = TRUE;
252 return found;
255 #ifdef HAVE_VV
256 static void sipe_invite_mime_cb(gpointer user_data, const GSList *fields,
257 const gchar *body, gsize length)
259 const gchar *type = sipe_utils_nameval_find(fields, "Content-Type");
260 const gchar *cd = sipe_utils_nameval_find(fields, "Content-Disposition");
262 if (!g_str_has_prefix(type, "application/sdp"))
263 return;
265 if (!cd || !strstr(cd, "ms-proxy-2007fallback")) {
266 struct sipmsg *msg = user_data;
267 const gchar* msg_ct = sipmsg_find_header(msg, "Content-Type");
269 if (g_str_has_prefix(msg_ct, "application/sdp")) {
270 /* We have already found suitable alternative and set message's body
271 * and Content-Type accordingly */
272 return;
275 sipmsg_remove_header_now(msg, "Content-Type");
276 sipmsg_add_header_now(msg, "Content-Type", type);
278 /* Replace message body with chosen alternative, so we can continue to
279 * process it as a normal single part message. */
280 g_free(msg->body);
281 msg->body = g_strndup(body, length);
282 msg->bodylen = length;
285 #endif
287 static void sipe_invite_mime_mixed_cb(gpointer user_data, const GSList *fields,
288 SIPE_UNUSED_PARAMETER const gchar *body, SIPE_UNUSED_PARAMETER gsize length)
290 const gchar *ctype = sipe_utils_nameval_find(fields, "Content-Type");
292 /* Lync 2010 file transfer */
293 if (g_str_has_prefix(ctype, "application/ms-filetransfer+xml")) {
294 struct sipmsg *msg = user_data;
296 sipmsg_remove_header_now(msg, "Content-Type");
297 sipmsg_add_header_now(msg, "Content-Type", ctype);
299 /* Right now, we do not care about the message body, only detect new
300 * file transfer protocol from Content-Type and reply with
301 * 488 Not Acceptable Here to force the old MSOC behavior.
303 * TODO: Extend sipmsg so that it supports multipart messages, as to
304 * implement the new protocol, we need access to both parts of the
305 * message for further processing. */
309 static void send_invite_response(struct sipe_core_private *sipe_private,
310 struct sipmsg *msg)
312 gchar *body = g_strdup_printf(
313 "v=0\r\n"
314 "o=- 0 0 IN IP4 %s\r\n"
315 "s=session\r\n"
316 "c=IN IP4 %s\r\n"
317 "t=0 0\r\n"
318 "m=%s %d sip sip:%s\r\n"
319 "a=accept-types:" SDP_ACCEPT_TYPES "\r\n",
320 sipe_backend_network_ip_address(SIPE_CORE_PUBLIC),
321 sipe_backend_network_ip_address(SIPE_CORE_PUBLIC),
322 SIPE_CORE_PRIVATE_FLAG_IS(OCS2007) ? "message" : "x-ms-message",
323 sip_transport_port(sipe_private),
324 sipe_private->username);
325 sipmsg_add_header(msg, "Content-Type", "application/sdp");
326 sip_transport_response(sipe_private, msg, 200, "OK", body);
327 g_free(body);
330 struct sipe_delayed_invite {
331 gchar *action;
332 struct sipmsg *msg;
335 static void delayed_invite_destroy(gpointer data)
337 struct sipe_delayed_invite *delayed_invite = data;
338 sipmsg_free(delayed_invite->msg);
339 g_free(delayed_invite->action);
340 g_free(delayed_invite);
343 static void delayed_invite_timeout(struct sipe_core_private *sipe_private,
344 gpointer data)
346 struct sipe_delayed_invite *delayed_invite = data;
347 send_invite_response(sipe_private, delayed_invite->msg);
350 static void delayed_invite_response(struct sipe_core_private *sipe_private,
351 struct sipmsg *msg,
352 const gchar *callid)
354 struct sipe_delayed_invite *delayed_invite = g_new0(struct sipe_delayed_invite, 1);
356 delayed_invite->action = g_strdup_printf("<delayed-invite-%s>", callid);
357 delayed_invite->msg = sipmsg_copy(msg);
358 sipe_schedule_seconds(sipe_private,
359 delayed_invite->action,
360 delayed_invite,
362 delayed_invite_timeout,
363 delayed_invite_destroy);
366 void sipe_incoming_cancel_delayed_invite(struct sipe_core_private *sipe_private,
367 struct sip_dialog *dialog)
369 struct sipe_delayed_invite *delayed_invite = dialog->delayed_invite;
370 dialog->delayed_invite = NULL;
371 send_invite_response(sipe_private, delayed_invite->msg);
372 sipe_schedule_cancel(sipe_private, delayed_invite->action);
375 void process_incoming_invite(struct sipe_core_private *sipe_private,
376 struct sipmsg *msg)
378 gchar *newTag;
379 const gchar *oldHeader;
380 gchar *newHeader;
381 gboolean is_multiparty = FALSE;
382 gboolean was_multiparty = TRUE;
383 gboolean just_joined = FALSE;
384 gchar *from;
385 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
386 const gchar *roster_manager = sipmsg_find_header(msg, "Roster-Manager");
387 const gchar *end_points_hdr = sipmsg_find_header(msg, "EndPoints");
388 const gchar *trig_invite = sipmsg_find_header(msg, "TriggeredInvite");
389 const gchar *content_type = sipmsg_find_header(msg, "Content-Type");
390 const gchar *subject = sipmsg_find_header(msg, "Subject");
391 GSList *end_points = NULL;
392 struct sip_session *session;
393 struct sip_dialog *dialog;
394 const gchar *ms_text_format;
395 gboolean dont_delay = FALSE;
397 #ifdef HAVE_VV
398 if (g_str_has_prefix(content_type, "multipart/alternative")) {
399 sipe_mime_parts_foreach(content_type, msg->body, sipe_invite_mime_cb, msg);
400 /* Reload Content-Type to get type of the selected message part */
401 content_type = sipmsg_find_header(msg, "Content-Type");
403 #endif
405 if (g_str_has_prefix(content_type, "multipart/mixed")) {
406 sipe_mime_parts_foreach(content_type, msg->body, sipe_invite_mime_mixed_cb, msg);
407 /* Reload Content-Type to get type of the selected message part */
408 content_type = sipmsg_find_header(msg, "Content-Type");
411 /* Lync 2010 file transfer */
412 if (g_str_has_prefix(content_type, "application/ms-filetransfer+xml")) {
413 sip_transport_response(sipe_private, msg, 488, "Not Acceptable Here", NULL);
414 return;
417 /* Invitation to join conference */
418 if (g_str_has_prefix(content_type, "application/ms-conf-invite+xml")) {
419 process_incoming_invite_conf(sipe_private, msg);
420 return;
423 #ifdef HAVE_VV
424 /* Invitation to audio call */
425 if (msg->body && strstr(msg->body, "m=audio")) {
426 process_incoming_invite_call(sipe_private, msg);
427 return;
429 #endif
431 /* Only accept text invitations */
432 if (msg->body && !(strstr(msg->body, "m=message") || strstr(msg->body, "m=x-ms-message"))) {
433 sip_transport_response(sipe_private, msg, 501, "Not implemented", NULL);
434 return;
437 // TODO There *must* be a better way to clean up the To header to add a tag...
438 SIPE_DEBUG_INFO_NOFORMAT("Adding a Tag to the To Header on Invite Request...");
439 oldHeader = sipmsg_find_header(msg, "To");
440 newTag = gentag();
441 newHeader = g_strdup_printf("%s;tag=%s", oldHeader, newTag);
442 g_free(newTag);
443 sipmsg_remove_header_now(msg, "To");
444 sipmsg_add_header_now(msg, "To", newHeader);
445 g_free(newHeader);
447 if (end_points_hdr) {
448 end_points = sipmsg_parse_endpoints_header(end_points_hdr);
450 if (g_slist_length(end_points) > 2) {
451 is_multiparty = TRUE;
454 if (trig_invite && !g_ascii_strcasecmp(trig_invite, "TRUE")) {
455 is_multiparty = TRUE;
458 /* Multiparty session */
459 session = sipe_session_find_chat_by_callid(sipe_private, callid);
460 if (is_multiparty) {
462 if (session) {
463 if (session->chat_session) {
464 /* Update roster manager for existing multiparty session */
465 if (roster_manager)
466 sipe_chat_set_roster_manager(session, roster_manager);
468 } else {
469 gchar *chat_title = sipe_chat_get_name();
471 /* Convert IM session to multiparty session */
472 g_free(session->with);
473 session->with = NULL;
474 was_multiparty = FALSE;
475 session->chat_session = sipe_chat_create_session(SIPE_CHAT_TYPE_MULTIPARTY,
476 roster_manager,
477 chat_title);
479 g_free(chat_title);
481 } else {
482 /* New multiparty session */
483 session = sipe_session_add_chat(sipe_private,
484 NULL,
485 TRUE,
486 roster_manager);
489 /* Create chat */
490 if (!session->chat_session->backend) {
491 gchar *self = sip_uri_self(sipe_private);
492 session->chat_session->backend = sipe_backend_chat_create(SIPE_CORE_PUBLIC,
493 session->chat_session,
494 session->chat_session->title,
495 self);
496 g_free(self);
500 /* IM session */
501 from = parse_from(sipmsg_find_header(msg, "From"));
502 if (!session)
503 session = sipe_session_find_or_add_im(sipe_private, from);
505 /* session is now initialized */
506 g_free(session->callid);
507 session->callid = g_strdup(callid);
509 if (is_multiparty && end_points) {
510 gchar *to = parse_from(sipmsg_find_header(msg, "To"));
511 GSList *entry = end_points;
512 while (entry) {
513 struct sipendpoint *end_point = entry->data;
514 entry = entry->next;
516 if (!g_ascii_strcasecmp(from, end_point->contact) ||
517 !g_ascii_strcasecmp(to, end_point->contact))
518 continue;
520 dialog = sipe_dialog_find(session, end_point->contact);
521 if (dialog) {
522 g_free(dialog->theirepid);
523 dialog->theirepid = end_point->epid;
524 end_point->epid = NULL;
525 } else {
526 dialog = sipe_dialog_add(session);
528 dialog->callid = g_strdup(session->callid);
529 dialog->with = end_point->contact;
530 end_point->contact = NULL;
531 dialog->theirepid = end_point->epid;
532 end_point->epid = NULL;
534 just_joined = TRUE;
536 /* send triggered INVITE */
537 sipe_im_invite(sipe_private, session, dialog->with, NULL, NULL, NULL, TRUE);
540 g_free(to);
543 if (end_points) {
544 GSList *entry = end_points;
545 while (entry) {
546 struct sipendpoint *end_point = entry->data;
547 entry = entry->next;
548 g_free(end_point->contact);
549 g_free(end_point->epid);
550 g_free(end_point);
552 g_slist_free(end_points);
555 dialog = sipe_dialog_find(session, from);
556 if (dialog) {
557 sipe_im_cancel_dangling(sipe_private, session, dialog, from,
558 sipe_im_reenqueue_unconfirmed);
559 /* dialog is no longer valid */
560 } else {
561 just_joined = TRUE;
564 dialog = sipe_dialog_add(session);
565 dialog->with = g_strdup(from);
566 dialog->callid = g_strdup(session->callid);
567 sipe_dialog_parse(dialog, msg, FALSE);
569 if (is_multiparty && !was_multiparty) {
570 /* add current IM counterparty to chat */
571 sipe_backend_chat_add(session->chat_session->backend,
572 sipe_dialog_first(session)->with,
573 FALSE);
576 /* add inviting party to chat */
577 if (just_joined && session->chat_session) {
578 sipe_backend_chat_add(session->chat_session->backend,
579 from,
580 TRUE);
583 if (!is_multiparty && subject)
584 sipe_im_topic(sipe_private, session, subject);
586 /* ms-text-format: text/plain; charset=UTF-8;msgr=WAAtAE0...DIADQAKAA0ACgA;ms-body=SGk= */
588 /* This used only in 2005 official client, not 2007 or Reuters.
589 Disabled for most cases as interfering with audit of messages which only is applied to regular MESSAGEs.
590 Only enabled for 2005 multiparty chats as otherwise the first message got lost completely.
592 /* also enabled for 2005 file transfer. Didn't work otherwise. */
593 ms_text_format = sipmsg_find_header(msg, "ms-text-format");
594 if (is_multiparty ||
595 (ms_text_format && g_str_has_prefix(ms_text_format, "text/x-msmsgsinvite")) )
597 if (ms_text_format) {
598 if (g_str_has_prefix(ms_text_format, "text/x-msmsgsinvite"))
600 dont_delay = TRUE;
602 else if (g_str_has_prefix(ms_text_format, "text/plain") || g_str_has_prefix(ms_text_format, "text/html"))
604 /* please do not optimize logic inside as this code may be re-enabled for other cases */
605 gchar *html = get_html_message(ms_text_format, NULL);
606 if (html) {
607 if (is_multiparty) {
608 sipe_backend_chat_message(SIPE_CORE_PUBLIC,
609 session->chat_session->backend,
610 from,
612 html);
613 } else {
614 sipe_backend_im_message(SIPE_CORE_PUBLIC,
615 from,
616 html);
618 g_free(html);
619 sipmsg_add_header(msg, "Supported", "ms-text-format"); /* accepts received message */
620 dont_delay = TRUE;
626 g_free(from);
628 sipmsg_add_header(msg, "Supported", "com.microsoft.rtc-multiparty");
630 if (dont_delay || !SIPE_CORE_PRIVATE_FLAG_IS(MPOP)) {
631 send_invite_response(sipe_private, msg);
632 } else {
633 delayed_invite_response(sipe_private, msg, session->callid);
637 void process_incoming_message(struct sipe_core_private *sipe_private,
638 struct sipmsg *msg)
640 gchar *from;
641 const gchar *contenttype;
642 gboolean found = FALSE;
644 from = parse_from(sipmsg_find_header(msg, "From"));
646 if (!from) return;
648 SIPE_DEBUG_INFO("got message from %s: %s", from, msg->body);
650 contenttype = sipmsg_find_header(msg, "Content-Type");
651 if (g_str_has_prefix(contenttype, "text/plain")
652 || g_str_has_prefix(contenttype, "text/html")
653 || g_str_has_prefix(contenttype, "multipart/related")
654 || g_str_has_prefix(contenttype, "multipart/alternative"))
656 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
657 gchar *html = get_html_message(contenttype, msg->body);
659 struct sip_session *session = sipe_session_find_chat_or_im(sipe_private,
660 callid,
661 from);
662 if (session && session->chat_session) {
663 if (session->chat_session->type == SIPE_CHAT_TYPE_CONFERENCE) { /* a conference */
664 gchar *tmp = parse_from(sipmsg_find_header(msg, "Ms-Sender"));
665 gchar *sender = parse_from(tmp);
666 g_free(tmp);
667 sipe_backend_chat_message(SIPE_CORE_PUBLIC,
668 session->chat_session->backend,
669 sender,
671 html);
672 g_free(sender);
673 } else { /* a multiparty chat */
674 sipe_backend_chat_message(SIPE_CORE_PUBLIC,
675 session->chat_session->backend,
676 from,
678 html);
680 } else {
681 sipe_backend_im_message(SIPE_CORE_PUBLIC,
682 from,
683 html);
685 g_free(html);
686 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
687 found = TRUE;
689 } else if (g_str_has_prefix(contenttype, "application/im-iscomposing+xml")) {
690 sipe_xml *isc = sipe_xml_parse(msg->body, msg->bodylen);
691 const sipe_xml *state;
692 gchar *statedata;
694 if (!isc) {
695 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_message: can not parse iscomposing");
696 g_free(from);
697 return;
700 state = sipe_xml_child(isc, "state");
702 if (!state) {
703 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_message: no state found");
704 sipe_xml_free(isc);
705 g_free(from);
706 return;
709 statedata = sipe_xml_data(state);
710 if (statedata) {
711 if (strstr(statedata, "active")) {
712 sipe_backend_user_feedback_typing(SIPE_CORE_PUBLIC,
713 from);
714 } else {
715 sipe_backend_user_feedback_typing_stop(SIPE_CORE_PUBLIC,
716 from);
718 g_free(statedata);
720 sipe_xml_free(isc);
721 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
722 found = TRUE;
723 } else if (g_str_has_prefix(contenttype, "text/x-msmsgsinvite")) {
724 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
725 struct sip_session *session = sipe_session_find_chat_or_im(sipe_private,
726 callid,
727 from);
728 if (session) {
729 struct sip_dialog *dialog = sipe_dialog_find(session, from);
730 GSList *body = sipe_ft_parse_msg_body(msg->body);
731 found = sipe_process_incoming_x_msmsgsinvite(sipe_private, dialog, body);
732 sipe_utils_nameval_free(body);
733 if (found) {
734 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
736 } else {
737 sip_transport_response(sipe_private, msg, 481,
738 "Call Leg/Transaction Does Not Exist", NULL);
739 found = TRUE;
742 if (!found) {
743 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
744 struct sip_session *session = sipe_session_find_chat_or_im(sipe_private,
745 callid,
746 from);
747 if (session) {
748 gchar *errmsg = g_strdup_printf(_("Received a message with unrecognized contents from %s"),
749 from);
750 sipe_user_present_error(sipe_private, session, errmsg);
751 g_free(errmsg);
754 SIPE_DEBUG_INFO("got unknown mime-type '%s'", contenttype);
755 sip_transport_response(sipe_private, msg, 415, "Unsupported media type", NULL);
757 g_free(from);
760 void process_incoming_options(struct sipe_core_private *sipe_private,
761 struct sipmsg *msg)
763 gchar *body;
765 sipmsg_add_header(msg, "Allow", "INVITE, MESSAGE, INFO, SUBSCRIBE, OPTIONS, BYE, CANCEL, NOTIFY, ACK, REFER, BENOTIFY");
766 sipmsg_add_header(msg, "Content-Type", "application/sdp");
768 body = g_strdup_printf(
769 "v=0\r\n"
770 "o=- 0 0 IN IP4 0.0.0.0\r\n"
771 "s=session\r\n"
772 "c=IN IP4 0.0.0.0\r\n"
773 "t=0 0\r\n"
774 "m=%s %d sip sip:%s\r\n"
775 "a=accept-types:" SDP_ACCEPT_TYPES "\r\n",
776 SIPE_CORE_PRIVATE_FLAG_IS(OCS2007) ? "message" : "x-ms-message",
777 sip_transport_port(sipe_private),
778 sipe_private->username);
779 sip_transport_response(sipe_private, msg, 200, "OK", body);
780 g_free(body);
783 void process_incoming_refer(struct sipe_core_private *sipe_private,
784 struct sipmsg *msg)
786 gchar *self = sip_uri_self(sipe_private);
787 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
788 gchar *from = parse_from(sipmsg_find_header(msg, "From"));
789 gchar *refer_to = parse_from(sipmsg_find_header(msg, "Refer-to"));
790 gchar *referred_by = g_strdup(sipmsg_find_header(msg, "Referred-By"));
791 struct sip_session *session;
792 struct sip_dialog *dialog;
794 session = sipe_session_find_chat_by_callid(sipe_private, callid);
795 dialog = sipe_dialog_find(session, from);
797 if (!session || !dialog || !session->chat_session ||
798 (session->chat_session->type != SIPE_CHAT_TYPE_MULTIPARTY) ||
799 !session->chat_session->id ||
800 !sipe_strcase_equal(session->chat_session->id, self)) {
801 sip_transport_response(sipe_private, msg, 500, "Server Internal Error", NULL);
802 } else {
803 sip_transport_response(sipe_private, msg, 202, "Accepted", NULL);
805 sipe_im_invite(sipe_private, session, refer_to, NULL, NULL, referred_by, FALSE);
808 g_free(self);
809 g_free(from);
810 g_free(refer_to);
811 g_free(referred_by);
815 Local Variables:
816 mode: c
817 c-file-style: "bsd"
818 indent-tabs-mode: t
819 tab-width: 8
820 End: