mingw: fix build breaks
[siplcs.git] / src / core / sipe-incoming.c
blob6329926eab83d7d44ce138e96c32dd1416bbfd52
1 /**
2 * @file sipe-incoming.c
4 * pidgin-sipe
6 * Copyright (C) 2010-2015 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-ft-lync.h"
44 #include "sipe-groupchat.h"
45 #include "sipe-im.h"
46 #include "sipe-incoming.h"
47 #include "sipe-media.h"
48 #include "sipe-mime.h"
49 #include "sipe-nls.h"
50 #include "sipe-schedule.h"
51 #include "sipe-session.h"
52 #include "sipe-user.h"
53 #include "sipe-utils.h"
54 #include "sipe-xml.h"
56 void process_incoming_bye(struct sipe_core_private *sipe_private,
57 struct sipmsg *msg)
59 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
60 gchar *from = parse_from(sipmsg_find_header(msg, "From"));
61 struct sip_session *session;
62 struct sip_dialog *dialog;
64 #ifdef HAVE_VV
65 if (is_media_session_msg(sipe_private->media_call, msg)) {
66 // BYE ends a media call
67 sipe_media_hangup(sipe_private->media_call);
69 #endif
71 /* collect dialog identification
72 * we need callid, ourtag and theirtag to unambiguously identify dialog
74 /* take data before 'msg' will be modified by sip_transport_response */
75 dialog = g_new0(struct sip_dialog, 1);
76 dialog->callid = g_strdup(callid);
77 dialog->cseq = sipmsg_parse_cseq(msg);
78 dialog->with = g_strdup(from);
79 sipe_dialog_parse(dialog, msg, FALSE);
81 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
83 session = sipe_session_find_chat_or_im(sipe_private, callid, from);
84 if (!session) {
85 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_bye: couldn't find session. Ignoring");
86 sipe_dialog_free(dialog);
87 g_free(from);
88 return;
91 SIPE_DEBUG_INFO("process_incoming_bye: session found (chat ID %s)",
92 (session->chat_session && session->chat_session->id) ?
93 session->chat_session->id : "<NO CHAT>");
95 if (session->chat_session &&
96 (session->chat_session->type == SIPE_CHAT_TYPE_MULTIPARTY) &&
97 session->chat_session->id &&
98 !g_ascii_strcasecmp(from, session->chat_session->id))
99 sipe_chat_set_roster_manager(session, NULL);
101 sipe_im_cancel_unconfirmed(sipe_private, session, callid, from);
103 /* This what BYE is essentially for - terminating dialog */
104 sipe_dialog_remove_3(session, dialog);
105 sipe_dialog_free(dialog);
106 if (session->chat_session) {
107 if ((session->chat_session->type == SIPE_CHAT_TYPE_CONFERENCE) &&
108 !g_ascii_strcasecmp(from, session->im_mcu_uri)) {
109 SIPE_DEBUG_INFO("process_incoming_bye: disconnected from conference %s",
110 session->im_mcu_uri);
111 sipe_conf_immcu_closed(sipe_private, session);
112 } else if (session->chat_session->type == SIPE_CHAT_TYPE_MULTIPARTY) {
113 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_bye: disconnected from multiparty chat");
114 sipe_backend_chat_remove(session->chat_session->backend,
115 from);
119 g_free(from);
122 void process_incoming_cancel(struct sipe_core_private *sipe_private,
123 struct sipmsg *msg)
125 const gchar *callid;
127 #ifdef HAVE_VV
128 if (is_media_session_msg(sipe_private->media_call, msg)) {
129 process_incoming_cancel_call(sipe_private, msg);
130 return;
132 #endif
133 callid = sipmsg_find_header(msg, "Call-ID");
135 if (!sipe_session_find_chat_by_callid(sipe_private, callid))
136 sipe_conf_cancel_unaccepted(sipe_private, msg);
139 void process_incoming_info(struct sipe_core_private *sipe_private,
140 struct sipmsg *msg)
142 const gchar *contenttype = sipmsg_find_header(msg, "Content-Type");
143 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
144 gchar *from;
145 struct sip_session *session;
147 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_info");
149 /* Call Control protocol */
150 if (g_str_has_prefix(contenttype, "application/csta+xml"))
152 process_incoming_info_csta(sipe_private, msg);
153 return;
155 else if (g_str_has_prefix(contenttype, "application/xml+conversationinfo"))
157 process_incoming_info_conversation(sipe_private, msg);
158 return;
161 from = parse_from(sipmsg_find_header(msg, "From"));
162 session = sipe_session_find_chat_or_im(sipe_private, callid, from);
163 if (!session) {
164 g_free(from);
165 return;
168 /* Group Chat uses text/plain */
169 if (session->is_groupchat) {
170 process_incoming_info_groupchat(sipe_private, msg, session);
171 g_free(from);
172 return;
175 if (g_str_has_prefix(contenttype, "application/x-ms-mim"))
177 sipe_xml *xn_action = sipe_xml_parse(msg->body, msg->bodylen);
178 const sipe_xml *xn_request_rm = sipe_xml_child(xn_action, "RequestRM");
179 const sipe_xml *xn_set_rm = sipe_xml_child(xn_action, "SetRM");
181 sipmsg_add_header(msg, "Content-Type", "application/x-ms-mim");
183 if (xn_request_rm) {
184 //const char *rm = sipe_xml_attribute(xn_request_rm, "uri");
185 int bid = sipe_xml_int_attribute(xn_request_rm, "bid", 0);
186 gchar *body = g_strdup_printf(
187 "<?xml version=\"1.0\"?>\r\n"
188 "<action xmlns=\"http://schemas.microsoft.com/sip/multiparty/\">"
189 "<RequestRMResponse uri=\"sip:%s\" allow=\"%s\"/></action>\r\n",
190 sipe_private->username,
191 session->bid < bid ? "true" : "false");
192 sip_transport_response(sipe_private, msg, 200, "OK", body);
193 g_free(body);
194 } else if (xn_set_rm) {
195 gchar *body;
197 sipe_chat_set_roster_manager(session,
198 sipe_xml_attribute(xn_set_rm, "uri"));
200 body = g_strdup_printf(
201 "<?xml version=\"1.0\"?>\r\n"
202 "<action xmlns=\"http://schemas.microsoft.com/sip/multiparty/\">"
203 "<SetRMResponse uri=\"sip:%s\"/></action>\r\n",
204 sipe_private->username);
205 sip_transport_response(sipe_private, msg, 200, "OK", body);
206 g_free(body);
208 sipe_xml_free(xn_action);
211 else
213 /* looks like purple lacks typing notification for chat */
214 if (!session->chat_session) {
215 sipe_xml *xn_keyboard_activity = sipe_xml_parse(msg->body, msg->bodylen);
216 const char *status = sipe_xml_attribute(sipe_xml_child(xn_keyboard_activity, "status"),
217 "status");
218 if (sipe_strequal(status, "type")) {
219 sipe_backend_user_feedback_typing(SIPE_CORE_PUBLIC,
220 from);
221 } else if (sipe_strequal(status, "idle")) {
222 sipe_backend_user_feedback_typing_stop(SIPE_CORE_PUBLIC,
223 from);
225 sipe_xml_free(xn_keyboard_activity);
228 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
230 g_free(from);
233 static gboolean sipe_process_incoming_x_msmsgsinvite(struct sipe_core_private *sipe_private,
234 struct sip_dialog *dialog,
235 GSList *parsed_body)
237 gboolean found = FALSE;
239 if (parsed_body) {
240 const gchar *invitation_command = sipe_utils_nameval_find(parsed_body, "Invitation-Command");
242 if (sipe_strequal(invitation_command, "INVITE")) {
243 sipe_ft_incoming_transfer(sipe_private, dialog, parsed_body);
244 found = TRUE;
245 } else if (sipe_strequal(invitation_command, "CANCEL")) {
246 sipe_ft_incoming_cancel(dialog, parsed_body);
247 found = TRUE;
248 } else if (sipe_strequal(invitation_command, "ACCEPT")) {
249 sipe_ft_incoming_accept(dialog, parsed_body);
250 found = TRUE;
253 return found;
256 #ifdef HAVE_VV
257 static void sipe_invite_mime_cb(gpointer user_data, const GSList *fields,
258 const gchar *body, gsize length)
260 const gchar *type = sipe_utils_nameval_find(fields, "Content-Type");
261 const gchar *cd = sipe_utils_nameval_find(fields, "Content-Disposition");
263 if (!g_str_has_prefix(type, "application/sdp"))
264 return;
266 if (!cd || !strstr(cd, "ms-proxy-2007fallback")) {
267 struct sipmsg *msg = user_data;
268 const gchar* msg_ct = sipmsg_find_header(msg, "Content-Type");
270 if (g_str_has_prefix(msg_ct, "application/sdp")) {
271 /* We have already found suitable alternative and set message's body
272 * and Content-Type accordingly */
273 return;
276 sipmsg_remove_header_now(msg, "Content-Type");
277 sipmsg_add_header_now(msg, "Content-Type", type);
279 /* Replace message body with chosen alternative, so we can continue to
280 * process it as a normal single part message. */
281 g_free(msg->body);
282 msg->body = g_strndup(body, length);
283 msg->bodylen = length;
286 #endif
288 static void send_invite_response(struct sipe_core_private *sipe_private,
289 struct sipmsg *msg)
291 gchar *body = g_strdup_printf(
292 "v=0\r\n"
293 "o=- 0 0 IN IP4 %s\r\n"
294 "s=session\r\n"
295 "c=IN IP4 %s\r\n"
296 "t=0 0\r\n"
297 "m=%s %d sip sip:%s\r\n"
298 "a=accept-types:" SDP_ACCEPT_TYPES "\r\n",
299 sipe_backend_network_ip_address(SIPE_CORE_PUBLIC),
300 sipe_backend_network_ip_address(SIPE_CORE_PUBLIC),
301 SIPE_CORE_PRIVATE_FLAG_IS(OCS2007) ? "message" : "x-ms-message",
302 sip_transport_port(sipe_private),
303 sipe_private->username);
304 sipmsg_add_header(msg, "Content-Type", "application/sdp");
305 sip_transport_response(sipe_private, msg, 200, "OK", body);
306 g_free(body);
309 struct sipe_delayed_invite {
310 gchar *action;
311 struct sipmsg *msg;
314 static void delayed_invite_destroy(gpointer data)
316 struct sipe_delayed_invite *delayed_invite = data;
317 sipmsg_free(delayed_invite->msg);
318 g_free(delayed_invite->action);
319 g_free(delayed_invite);
322 static void delayed_invite_timeout(struct sipe_core_private *sipe_private,
323 gpointer data)
325 struct sipe_delayed_invite *delayed_invite = data;
326 send_invite_response(sipe_private, delayed_invite->msg);
329 static void delayed_invite_response(struct sipe_core_private *sipe_private,
330 struct sipmsg *msg,
331 const gchar *callid)
333 struct sipe_delayed_invite *delayed_invite = g_new0(struct sipe_delayed_invite, 1);
335 delayed_invite->action = g_strdup_printf("<delayed-invite-%s>", callid);
336 delayed_invite->msg = sipmsg_copy(msg);
337 sipe_schedule_seconds(sipe_private,
338 delayed_invite->action,
339 delayed_invite,
341 delayed_invite_timeout,
342 delayed_invite_destroy);
345 void sipe_incoming_cancel_delayed_invite(struct sipe_core_private *sipe_private,
346 struct sip_dialog *dialog)
348 struct sipe_delayed_invite *delayed_invite = dialog->delayed_invite;
349 dialog->delayed_invite = NULL;
350 send_invite_response(sipe_private, delayed_invite->msg);
351 sipe_schedule_cancel(sipe_private, delayed_invite->action);
354 void process_incoming_invite(struct sipe_core_private *sipe_private,
355 struct sipmsg *msg)
357 gchar *newTag;
358 const gchar *oldHeader;
359 gchar *newHeader;
360 gboolean is_multiparty = FALSE;
361 gboolean was_multiparty = TRUE;
362 gboolean just_joined = FALSE;
363 gchar *from;
364 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
365 const gchar *roster_manager = sipmsg_find_header(msg, "Roster-Manager");
366 const gchar *end_points_hdr = sipmsg_find_header(msg, "EndPoints");
367 const gchar *trig_invite = sipmsg_find_header(msg, "TriggeredInvite");
368 const gchar *content_type = sipmsg_find_header(msg, "Content-Type");
369 const gchar *subject = sipmsg_find_header(msg, "Subject");
370 GSList *end_points = NULL;
371 struct sip_session *session;
372 struct sip_dialog *dialog;
373 const gchar *ms_text_format;
374 gboolean dont_delay = FALSE;
376 #ifdef HAVE_VV
377 if (g_str_has_prefix(content_type, "multipart/alternative")) {
378 sipe_mime_parts_foreach(content_type, msg->body, sipe_invite_mime_cb, msg);
379 /* Reload Content-Type to get type of the selected message part */
380 content_type = sipmsg_find_header(msg, "Content-Type");
382 #endif
384 if (g_str_has_prefix(content_type, "multipart/mixed")) {
385 if (sipe_mime_parts_contain(content_type, msg->body,
386 "application/ms-filetransfer+xml")) {
387 /* Lync 2010 file transfer */
388 #ifdef HAVE_XDATA
389 process_incoming_invite_ft_lync(sipe_private, msg);
390 #else
391 sip_transport_response(sipe_private, msg,
392 488, "Not Acceptable Here", NULL);
393 #endif
394 return;
398 /* Invitation to join conference */
399 if (g_str_has_prefix(content_type, "application/ms-conf-invite+xml")) {
400 process_incoming_invite_conf(sipe_private, msg);
401 return;
404 #ifdef HAVE_VV
405 /* Invitation to audio call */
406 if (msg->body && strstr(msg->body, "m=audio")) {
407 process_incoming_invite_call(sipe_private, msg);
408 return;
410 #endif
412 /* Only accept text invitations */
413 if (msg->body && !(strstr(msg->body, "m=message") || strstr(msg->body, "m=x-ms-message"))) {
414 sip_transport_response(sipe_private, msg, 501, "Not implemented", NULL);
415 return;
418 // TODO There *must* be a better way to clean up the To header to add a tag...
419 SIPE_DEBUG_INFO_NOFORMAT("Adding a Tag to the To Header on Invite Request...");
420 oldHeader = sipmsg_find_header(msg, "To");
421 newTag = gentag();
422 newHeader = g_strdup_printf("%s;tag=%s", oldHeader, newTag);
423 g_free(newTag);
424 sipmsg_remove_header_now(msg, "To");
425 sipmsg_add_header_now(msg, "To", newHeader);
426 g_free(newHeader);
428 if (end_points_hdr) {
429 end_points = sipmsg_parse_endpoints_header(end_points_hdr);
431 if (g_slist_length(end_points) > 2) {
432 is_multiparty = TRUE;
435 if (trig_invite && !g_ascii_strcasecmp(trig_invite, "TRUE")) {
436 is_multiparty = TRUE;
439 /* Multiparty session */
440 session = sipe_session_find_chat_by_callid(sipe_private, callid);
441 if (is_multiparty) {
443 if (session) {
444 if (session->chat_session) {
445 /* Update roster manager for existing multiparty session */
446 if (roster_manager)
447 sipe_chat_set_roster_manager(session, roster_manager);
449 } else {
450 gchar *chat_title = sipe_chat_get_name();
452 /* Convert IM session to multiparty session */
453 g_free(session->with);
454 session->with = NULL;
455 was_multiparty = FALSE;
456 session->chat_session = sipe_chat_create_session(SIPE_CHAT_TYPE_MULTIPARTY,
457 roster_manager,
458 chat_title);
460 g_free(chat_title);
462 } else {
463 /* New multiparty session */
464 session = sipe_session_add_chat(sipe_private,
465 NULL,
466 TRUE,
467 roster_manager);
470 /* Create chat */
471 if (!session->chat_session->backend) {
472 gchar *self = sip_uri_self(sipe_private);
473 session->chat_session->backend = sipe_backend_chat_create(SIPE_CORE_PUBLIC,
474 session->chat_session,
475 session->chat_session->title,
476 self);
477 g_free(self);
481 /* IM session */
482 from = parse_from(sipmsg_find_header(msg, "From"));
483 if (!session)
484 session = sipe_session_find_or_add_im(sipe_private, from);
486 /* session is now initialized */
487 g_free(session->callid);
488 session->callid = g_strdup(callid);
490 if (is_multiparty && end_points) {
491 gchar *to = parse_from(sipmsg_find_header(msg, "To"));
492 GSList *entry = end_points;
493 while (entry) {
494 struct sipendpoint *end_point = entry->data;
495 entry = entry->next;
497 if (!g_ascii_strcasecmp(from, end_point->contact) ||
498 !g_ascii_strcasecmp(to, end_point->contact))
499 continue;
501 dialog = sipe_dialog_find(session, end_point->contact);
502 if (dialog) {
503 g_free(dialog->theirepid);
504 dialog->theirepid = end_point->epid;
505 end_point->epid = NULL;
506 } else {
507 dialog = sipe_dialog_add(session);
509 dialog->callid = g_strdup(session->callid);
510 dialog->with = end_point->contact;
511 end_point->contact = NULL;
512 dialog->theirepid = end_point->epid;
513 end_point->epid = NULL;
515 just_joined = TRUE;
517 /* send triggered INVITE */
518 sipe_im_invite(sipe_private, session, dialog->with, NULL, NULL, NULL, TRUE);
521 g_free(to);
524 if (end_points) {
525 GSList *entry = end_points;
526 while (entry) {
527 struct sipendpoint *end_point = entry->data;
528 entry = entry->next;
529 g_free(end_point->contact);
530 g_free(end_point->epid);
531 g_free(end_point);
533 g_slist_free(end_points);
536 dialog = sipe_dialog_find(session, from);
537 if (dialog) {
538 sipe_im_cancel_dangling(sipe_private, session, dialog, from,
539 sipe_im_reenqueue_unconfirmed);
540 /* dialog is no longer valid */
541 } else {
542 just_joined = TRUE;
545 dialog = sipe_dialog_add(session);
546 dialog->with = g_strdup(from);
547 dialog->callid = g_strdup(session->callid);
548 dialog->is_established = TRUE;
549 sipe_dialog_parse(dialog, msg, FALSE);
551 if (is_multiparty && !was_multiparty) {
552 /* add current IM counterparty to chat */
553 sipe_backend_chat_add(session->chat_session->backend,
554 sipe_dialog_first(session)->with,
555 FALSE);
558 /* add inviting party to chat */
559 if (just_joined && session->chat_session) {
560 sipe_backend_chat_add(session->chat_session->backend,
561 from,
562 TRUE);
565 if (!is_multiparty && subject)
566 sipe_im_topic(sipe_private, session, subject);
568 /* ms-text-format: text/plain; charset=UTF-8;msgr=WAAtAE0...DIADQAKAA0ACgA;ms-body=SGk= */
570 /* This used only in 2005 official client, not 2007 or Reuters.
571 Disabled for most cases as interfering with audit of messages which only is applied to regular MESSAGEs.
572 Only enabled for 2005 multiparty chats as otherwise the first message got lost completely.
574 /* also enabled for 2005 file transfer. Didn't work otherwise. */
575 ms_text_format = sipmsg_find_header(msg, "ms-text-format");
576 if (is_multiparty ||
577 (ms_text_format && g_str_has_prefix(ms_text_format, "text/x-msmsgsinvite")) )
579 if (ms_text_format) {
580 if (g_str_has_prefix(ms_text_format, "text/x-msmsgsinvite"))
582 dont_delay = TRUE;
584 else if (g_str_has_prefix(ms_text_format, "text/plain") || g_str_has_prefix(ms_text_format, "text/html"))
586 /* please do not optimize logic inside as this code may be re-enabled for other cases */
587 gchar *html = get_html_message(ms_text_format, NULL);
588 if (html) {
589 if (is_multiparty) {
590 sipe_backend_chat_message(SIPE_CORE_PUBLIC,
591 session->chat_session->backend,
592 from,
594 html);
595 } else {
596 sipe_backend_im_message(SIPE_CORE_PUBLIC,
597 from,
598 html);
600 g_free(html);
601 sipmsg_add_header(msg, "Supported", "ms-text-format"); /* accepts received message */
602 dont_delay = TRUE;
608 g_free(from);
610 sipmsg_add_header(msg, "Supported", "com.microsoft.rtc-multiparty");
612 if (dont_delay || !SIPE_CORE_PRIVATE_FLAG_IS(MPOP)) {
613 send_invite_response(sipe_private, msg);
614 } else {
615 delayed_invite_response(sipe_private, msg, session->callid);
619 void process_incoming_message(struct sipe_core_private *sipe_private,
620 struct sipmsg *msg)
622 gchar *from;
623 const gchar *contenttype;
624 gboolean found = FALSE;
626 from = parse_from(sipmsg_find_header(msg, "From"));
628 if (!from) return;
630 SIPE_DEBUG_INFO("got message from %s: %s", from, msg->body);
632 contenttype = sipmsg_find_header(msg, "Content-Type");
633 if (g_str_has_prefix(contenttype, "text/plain")
634 || g_str_has_prefix(contenttype, "text/html")
635 || g_str_has_prefix(contenttype, "multipart/related")
636 || g_str_has_prefix(contenttype, "multipart/alternative"))
638 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
639 gchar *html = get_html_message(contenttype, msg->body);
641 struct sip_session *session = sipe_session_find_chat_or_im(sipe_private,
642 callid,
643 from);
644 if (session && session->chat_session) {
645 if (session->chat_session->type == SIPE_CHAT_TYPE_CONFERENCE) { /* a conference */
646 gchar *tmp = parse_from(sipmsg_find_header(msg, "Ms-Sender"));
647 gchar *sender = parse_from(tmp);
648 g_free(tmp);
649 sipe_backend_chat_message(SIPE_CORE_PUBLIC,
650 session->chat_session->backend,
651 sender,
653 html);
654 g_free(sender);
655 } else { /* a multiparty chat */
656 sipe_backend_chat_message(SIPE_CORE_PUBLIC,
657 session->chat_session->backend,
658 from,
660 html);
662 } else {
663 sipe_backend_im_message(SIPE_CORE_PUBLIC,
664 from,
665 html);
667 g_free(html);
668 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
669 found = TRUE;
671 } else if (g_str_has_prefix(contenttype, "application/im-iscomposing+xml")) {
672 sipe_xml *isc = sipe_xml_parse(msg->body, msg->bodylen);
673 const sipe_xml *state;
674 gchar *statedata;
676 if (!isc) {
677 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_message: can not parse iscomposing");
678 g_free(from);
679 return;
682 state = sipe_xml_child(isc, "state");
684 if (!state) {
685 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_message: no state found");
686 sipe_xml_free(isc);
687 g_free(from);
688 return;
691 statedata = sipe_xml_data(state);
692 if (statedata) {
693 if (strstr(statedata, "active")) {
694 sipe_backend_user_feedback_typing(SIPE_CORE_PUBLIC,
695 from);
696 } else {
697 sipe_backend_user_feedback_typing_stop(SIPE_CORE_PUBLIC,
698 from);
700 g_free(statedata);
702 sipe_xml_free(isc);
703 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
704 found = TRUE;
705 } else if (g_str_has_prefix(contenttype, "text/x-msmsgsinvite")) {
706 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
707 struct sip_session *session = sipe_session_find_chat_or_im(sipe_private,
708 callid,
709 from);
710 if (session) {
711 struct sip_dialog *dialog = sipe_dialog_find(session, from);
712 GSList *body = sipe_ft_parse_msg_body(msg->body);
713 found = sipe_process_incoming_x_msmsgsinvite(sipe_private, dialog, body);
714 sipe_utils_nameval_free(body);
715 if (found) {
716 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
718 } else {
719 sip_transport_response(sipe_private, msg, 481,
720 "Call Leg/Transaction Does Not Exist", NULL);
721 found = TRUE;
724 if (!found) {
725 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
726 struct sip_session *session = sipe_session_find_chat_or_im(sipe_private,
727 callid,
728 from);
729 if (session) {
730 gchar *errmsg = g_strdup_printf(_("Received a message with unrecognized contents from %s"),
731 from);
732 sipe_user_present_error(sipe_private, session, errmsg);
733 g_free(errmsg);
736 SIPE_DEBUG_INFO("got unknown mime-type '%s'", contenttype);
737 sip_transport_response(sipe_private, msg, 415, "Unsupported media type", NULL);
739 g_free(from);
742 void process_incoming_options(struct sipe_core_private *sipe_private,
743 struct sipmsg *msg)
745 gchar *body;
747 sipmsg_add_header(msg, "Allow", "INVITE, MESSAGE, INFO, SUBSCRIBE, OPTIONS, BYE, CANCEL, NOTIFY, ACK, REFER, BENOTIFY");
748 sipmsg_add_header(msg, "Content-Type", "application/sdp");
750 body = g_strdup_printf(
751 "v=0\r\n"
752 "o=- 0 0 IN IP4 0.0.0.0\r\n"
753 "s=session\r\n"
754 "c=IN IP4 0.0.0.0\r\n"
755 "t=0 0\r\n"
756 "m=%s %d sip sip:%s\r\n"
757 "a=accept-types:" SDP_ACCEPT_TYPES "\r\n",
758 SIPE_CORE_PRIVATE_FLAG_IS(OCS2007) ? "message" : "x-ms-message",
759 sip_transport_port(sipe_private),
760 sipe_private->username);
761 sip_transport_response(sipe_private, msg, 200, "OK", body);
762 g_free(body);
765 void process_incoming_refer(struct sipe_core_private *sipe_private,
766 struct sipmsg *msg)
768 gchar *self = sip_uri_self(sipe_private);
769 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
770 gchar *from = parse_from(sipmsg_find_header(msg, "From"));
771 gchar *refer_to = parse_from(sipmsg_find_header(msg, "Refer-to"));
772 gchar *referred_by = g_strdup(sipmsg_find_header(msg, "Referred-By"));
773 struct sip_session *session;
774 struct sip_dialog *dialog;
776 session = sipe_session_find_chat_by_callid(sipe_private, callid);
777 dialog = sipe_dialog_find(session, from);
779 if (!session || !dialog || !session->chat_session ||
780 (session->chat_session->type != SIPE_CHAT_TYPE_MULTIPARTY) ||
781 !session->chat_session->id ||
782 !sipe_strcase_equal(session->chat_session->id, self)) {
783 sip_transport_response(sipe_private, msg, 500, "Server Internal Error", NULL);
784 } else {
785 sip_transport_response(sipe_private, msg, 202, "Accepted", NULL);
787 sipe_im_invite(sipe_private, session, refer_to, NULL, NULL, referred_by, FALSE);
790 g_free(self);
791 g_free(from);
792 g_free(refer_to);
793 g_free(referred_by);
797 Local Variables:
798 mode: c
799 c-file-style: "bsd"
800 indent-tabs-mode: t
801 tab-width: 8
802 End: