2 * @file sipe-incoming.c
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
32 #include "sipe-common.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"
43 #include "sipe-groupchat.h"
45 #include "sipe-incoming.h"
46 #include "sipe-media.h"
47 #include "sipe-mime.h"
49 #include "sipe-schedule.h"
50 #include "sipe-session.h"
51 #include "sipe-user.h"
52 #include "sipe-utils.h"
55 void process_incoming_bye(struct sipe_core_private
*sipe_private
,
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
;
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
);
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
);
84 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_bye: couldn't find session. Ignoring");
85 sipe_dialog_free(dialog
);
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
,
121 void process_incoming_cancel(struct sipe_core_private
*sipe_private
,
127 if (is_media_session_msg(sipe_private
->media_call
, msg
)) {
128 process_incoming_cancel_call(sipe_private
, msg
);
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
,
141 const gchar
*contenttype
= sipmsg_find_header(msg
, "Content-Type");
142 const gchar
*callid
= sipmsg_find_header(msg
, "Call-ID");
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
);
154 else if (g_str_has_prefix(contenttype
, "application/xml+conversationinfo"))
156 process_incoming_info_conversation(sipe_private
, msg
);
160 from
= parse_from(sipmsg_find_header(msg
, "From"));
161 session
= sipe_session_find_chat_or_im(sipe_private
, callid
, from
);
167 /* Group Chat uses text/plain */
168 if (session
->is_groupchat
) {
169 process_incoming_info_groupchat(sipe_private
, msg
, session
);
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");
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
);
193 } else if (xn_set_rm
) {
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
);
207 sipe_xml_free(xn_action
);
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"),
217 if (sipe_strequal(status
, "type")) {
218 sipe_backend_user_feedback_typing(SIPE_CORE_PUBLIC
,
220 } else if (sipe_strequal(status
, "idle")) {
221 sipe_backend_user_feedback_typing_stop(SIPE_CORE_PUBLIC
,
224 sipe_xml_free(xn_keyboard_activity
);
227 sip_transport_response(sipe_private
, msg
, 200, "OK", NULL
);
232 static gboolean
sipe_process_incoming_x_msmsgsinvite(struct sipe_core_private
*sipe_private
,
233 struct sip_dialog
*dialog
,
236 gboolean found
= FALSE
;
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
);
244 } else if (sipe_strequal(invitation_command
, "CANCEL")) {
245 sipe_ft_incoming_cancel(dialog
, parsed_body
);
247 } else if (sipe_strequal(invitation_command
, "ACCEPT")) {
248 sipe_ft_incoming_accept(dialog
, parsed_body
);
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"))
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 */
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. */
281 msg
->body
= g_strndup(body
, length
);
282 msg
->bodylen
= length
;
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
,
312 gchar
*body
= g_strdup_printf(
314 "o=- 0 0 IN IP4 %s\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
);
330 struct sipe_delayed_invite
{
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
,
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
,
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
,
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
,
379 const gchar
*oldHeader
;
381 gboolean is_multiparty
= FALSE
;
382 gboolean was_multiparty
= TRUE
;
383 gboolean just_joined
= FALSE
;
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
;
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");
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
);
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
);
424 /* Invitation to audio call */
425 if (msg
->body
&& strstr(msg
->body
, "m=audio")) {
426 process_incoming_invite_call(sipe_private
, msg
);
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
);
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");
441 newHeader
= g_strdup_printf("%s;tag=%s", oldHeader
, newTag
);
443 sipmsg_remove_header_now(msg
, "To");
444 sipmsg_add_header_now(msg
, "To", 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
);
463 if (session
->chat_session
) {
464 /* Update roster manager for existing multiparty session */
466 sipe_chat_set_roster_manager(session
, roster_manager
);
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
,
482 /* New multiparty session */
483 session
= sipe_session_add_chat(sipe_private
,
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
,
501 from
= parse_from(sipmsg_find_header(msg
, "From"));
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
;
513 struct sipendpoint
*end_point
= entry
->data
;
516 if (!g_ascii_strcasecmp(from
, end_point
->contact
) ||
517 !g_ascii_strcasecmp(to
, end_point
->contact
))
520 dialog
= sipe_dialog_find(session
, end_point
->contact
);
522 g_free(dialog
->theirepid
);
523 dialog
->theirepid
= end_point
->epid
;
524 end_point
->epid
= NULL
;
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
;
536 /* send triggered INVITE */
537 sipe_im_invite(sipe_private
, session
, dialog
->with
, NULL
, NULL
, NULL
, TRUE
);
544 GSList
*entry
= end_points
;
546 struct sipendpoint
*end_point
= entry
->data
;
548 g_free(end_point
->contact
);
549 g_free(end_point
->epid
);
552 g_slist_free(end_points
);
555 dialog
= sipe_dialog_find(session
, from
);
557 sipe_im_cancel_dangling(sipe_private
, session
, dialog
, from
,
558 sipe_im_reenqueue_unconfirmed
);
559 /* dialog is no longer valid */
564 dialog
= sipe_dialog_add(session
);
565 dialog
->with
= g_strdup(from
);
566 dialog
->callid
= g_strdup(session
->callid
);
567 dialog
->is_established
= TRUE
;
568 sipe_dialog_parse(dialog
, msg
, FALSE
);
570 if (is_multiparty
&& !was_multiparty
) {
571 /* add current IM counterparty to chat */
572 sipe_backend_chat_add(session
->chat_session
->backend
,
573 sipe_dialog_first(session
)->with
,
577 /* add inviting party to chat */
578 if (just_joined
&& session
->chat_session
) {
579 sipe_backend_chat_add(session
->chat_session
->backend
,
584 if (!is_multiparty
&& subject
)
585 sipe_im_topic(sipe_private
, session
, subject
);
587 /* ms-text-format: text/plain; charset=UTF-8;msgr=WAAtAE0...DIADQAKAA0ACgA;ms-body=SGk= */
589 /* This used only in 2005 official client, not 2007 or Reuters.
590 Disabled for most cases as interfering with audit of messages which only is applied to regular MESSAGEs.
591 Only enabled for 2005 multiparty chats as otherwise the first message got lost completely.
593 /* also enabled for 2005 file transfer. Didn't work otherwise. */
594 ms_text_format
= sipmsg_find_header(msg
, "ms-text-format");
596 (ms_text_format
&& g_str_has_prefix(ms_text_format
, "text/x-msmsgsinvite")) )
598 if (ms_text_format
) {
599 if (g_str_has_prefix(ms_text_format
, "text/x-msmsgsinvite"))
603 else if (g_str_has_prefix(ms_text_format
, "text/plain") || g_str_has_prefix(ms_text_format
, "text/html"))
605 /* please do not optimize logic inside as this code may be re-enabled for other cases */
606 gchar
*html
= get_html_message(ms_text_format
, NULL
);
609 sipe_backend_chat_message(SIPE_CORE_PUBLIC
,
610 session
->chat_session
->backend
,
615 sipe_backend_im_message(SIPE_CORE_PUBLIC
,
620 sipmsg_add_header(msg
, "Supported", "ms-text-format"); /* accepts received message */
629 sipmsg_add_header(msg
, "Supported", "com.microsoft.rtc-multiparty");
631 if (dont_delay
|| !SIPE_CORE_PRIVATE_FLAG_IS(MPOP
)) {
632 send_invite_response(sipe_private
, msg
);
634 delayed_invite_response(sipe_private
, msg
, session
->callid
);
638 void process_incoming_message(struct sipe_core_private
*sipe_private
,
642 const gchar
*contenttype
;
643 gboolean found
= FALSE
;
645 from
= parse_from(sipmsg_find_header(msg
, "From"));
649 SIPE_DEBUG_INFO("got message from %s: %s", from
, msg
->body
);
651 contenttype
= sipmsg_find_header(msg
, "Content-Type");
652 if (g_str_has_prefix(contenttype
, "text/plain")
653 || g_str_has_prefix(contenttype
, "text/html")
654 || g_str_has_prefix(contenttype
, "multipart/related")
655 || g_str_has_prefix(contenttype
, "multipart/alternative"))
657 const gchar
*callid
= sipmsg_find_header(msg
, "Call-ID");
658 gchar
*html
= get_html_message(contenttype
, msg
->body
);
660 struct sip_session
*session
= sipe_session_find_chat_or_im(sipe_private
,
663 if (session
&& session
->chat_session
) {
664 if (session
->chat_session
->type
== SIPE_CHAT_TYPE_CONFERENCE
) { /* a conference */
665 gchar
*tmp
= parse_from(sipmsg_find_header(msg
, "Ms-Sender"));
666 gchar
*sender
= parse_from(tmp
);
668 sipe_backend_chat_message(SIPE_CORE_PUBLIC
,
669 session
->chat_session
->backend
,
674 } else { /* a multiparty chat */
675 sipe_backend_chat_message(SIPE_CORE_PUBLIC
,
676 session
->chat_session
->backend
,
682 sipe_backend_im_message(SIPE_CORE_PUBLIC
,
687 sip_transport_response(sipe_private
, msg
, 200, "OK", NULL
);
690 } else if (g_str_has_prefix(contenttype
, "application/im-iscomposing+xml")) {
691 sipe_xml
*isc
= sipe_xml_parse(msg
->body
, msg
->bodylen
);
692 const sipe_xml
*state
;
696 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_message: can not parse iscomposing");
701 state
= sipe_xml_child(isc
, "state");
704 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_message: no state found");
710 statedata
= sipe_xml_data(state
);
712 if (strstr(statedata
, "active")) {
713 sipe_backend_user_feedback_typing(SIPE_CORE_PUBLIC
,
716 sipe_backend_user_feedback_typing_stop(SIPE_CORE_PUBLIC
,
722 sip_transport_response(sipe_private
, msg
, 200, "OK", NULL
);
724 } else if (g_str_has_prefix(contenttype
, "text/x-msmsgsinvite")) {
725 const gchar
*callid
= sipmsg_find_header(msg
, "Call-ID");
726 struct sip_session
*session
= sipe_session_find_chat_or_im(sipe_private
,
730 struct sip_dialog
*dialog
= sipe_dialog_find(session
, from
);
731 GSList
*body
= sipe_ft_parse_msg_body(msg
->body
);
732 found
= sipe_process_incoming_x_msmsgsinvite(sipe_private
, dialog
, body
);
733 sipe_utils_nameval_free(body
);
735 sip_transport_response(sipe_private
, msg
, 200, "OK", NULL
);
738 sip_transport_response(sipe_private
, msg
, 481,
739 "Call Leg/Transaction Does Not Exist", NULL
);
744 const gchar
*callid
= sipmsg_find_header(msg
, "Call-ID");
745 struct sip_session
*session
= sipe_session_find_chat_or_im(sipe_private
,
749 gchar
*errmsg
= g_strdup_printf(_("Received a message with unrecognized contents from %s"),
751 sipe_user_present_error(sipe_private
, session
, errmsg
);
755 SIPE_DEBUG_INFO("got unknown mime-type '%s'", contenttype
);
756 sip_transport_response(sipe_private
, msg
, 415, "Unsupported media type", NULL
);
761 void process_incoming_options(struct sipe_core_private
*sipe_private
,
766 sipmsg_add_header(msg
, "Allow", "INVITE, MESSAGE, INFO, SUBSCRIBE, OPTIONS, BYE, CANCEL, NOTIFY, ACK, REFER, BENOTIFY");
767 sipmsg_add_header(msg
, "Content-Type", "application/sdp");
769 body
= g_strdup_printf(
771 "o=- 0 0 IN IP4 0.0.0.0\r\n"
773 "c=IN IP4 0.0.0.0\r\n"
775 "m=%s %d sip sip:%s\r\n"
776 "a=accept-types:" SDP_ACCEPT_TYPES
"\r\n",
777 SIPE_CORE_PRIVATE_FLAG_IS(OCS2007
) ? "message" : "x-ms-message",
778 sip_transport_port(sipe_private
),
779 sipe_private
->username
);
780 sip_transport_response(sipe_private
, msg
, 200, "OK", body
);
784 void process_incoming_refer(struct sipe_core_private
*sipe_private
,
787 gchar
*self
= sip_uri_self(sipe_private
);
788 const gchar
*callid
= sipmsg_find_header(msg
, "Call-ID");
789 gchar
*from
= parse_from(sipmsg_find_header(msg
, "From"));
790 gchar
*refer_to
= parse_from(sipmsg_find_header(msg
, "Refer-to"));
791 gchar
*referred_by
= g_strdup(sipmsg_find_header(msg
, "Referred-By"));
792 struct sip_session
*session
;
793 struct sip_dialog
*dialog
;
795 session
= sipe_session_find_chat_by_callid(sipe_private
, callid
);
796 dialog
= sipe_dialog_find(session
, from
);
798 if (!session
|| !dialog
|| !session
->chat_session
||
799 (session
->chat_session
->type
!= SIPE_CHAT_TYPE_MULTIPARTY
) ||
800 !session
->chat_session
->id
||
801 !sipe_strcase_equal(session
->chat_session
->id
, self
)) {
802 sip_transport_response(sipe_private
, msg
, 500, "Server Internal Error", NULL
);
804 sip_transport_response(sipe_private
, msg
, 202, "Accepted", NULL
);
806 sipe_im_invite(sipe_private
, session
, refer_to
, NULL
, NULL
, referred_by
, FALSE
);