2 * @file sipe-incoming.c
6 * Copyright (C) 2010-2017 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
34 #include "sip-transport.h"
35 #include "sipe-appshare.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-ft-lync.h"
44 #include "sipe-groupchat.h"
46 #include "sipe-incoming.h"
47 #include "sipe-media.h"
48 #include "sipe-mime.h"
50 #include "sipe-schedule.h"
51 #include "sipe-session.h"
52 #include "sipe-user.h"
53 #include "sipe-utils.h"
56 void process_incoming_bye(struct sipe_core_private
*sipe_private
,
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
;
65 struct sipe_media_call_private
*call_private
=
66 g_hash_table_lookup(sipe_private
->media_calls
, callid
);
67 if (is_media_session_msg(call_private
, msg
)) {
68 // BYE ends a media call
69 sipe_media_hangup(call_private
);
73 /* collect dialog identification
74 * we need callid, ourtag and theirtag to unambiguously identify dialog
76 /* take data before 'msg' will be modified by sip_transport_response */
77 dialog
= g_new0(struct sip_dialog
, 1);
78 dialog
->callid
= g_strdup(callid
);
79 dialog
->cseq
= sipmsg_parse_cseq(msg
);
80 dialog
->with
= g_strdup(from
);
81 sipe_dialog_parse(dialog
, msg
, FALSE
);
83 sip_transport_response(sipe_private
, msg
, 200, "OK", NULL
);
85 session
= sipe_session_find_chat_or_im(sipe_private
, callid
, from
);
87 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_bye: couldn't find session. Ignoring");
88 sipe_dialog_free(dialog
);
93 SIPE_DEBUG_INFO("process_incoming_bye: session found (chat ID %s)",
94 (session
->chat_session
&& session
->chat_session
->id
) ?
95 session
->chat_session
->id
: "<NO CHAT>");
97 if (session
->chat_session
&&
98 (session
->chat_session
->type
== SIPE_CHAT_TYPE_MULTIPARTY
) &&
99 session
->chat_session
->id
&&
100 !g_ascii_strcasecmp(from
, session
->chat_session
->id
))
101 sipe_chat_set_roster_manager(session
, NULL
);
103 sipe_im_cancel_unconfirmed(sipe_private
, session
, callid
, from
);
105 /* This what BYE is essentially for - terminating dialog */
106 sipe_dialog_remove_3(session
, dialog
);
107 sipe_dialog_free(dialog
);
108 if (session
->chat_session
) {
109 if ((session
->chat_session
->type
== SIPE_CHAT_TYPE_CONFERENCE
) &&
110 !g_ascii_strcasecmp(from
, session
->im_mcu_uri
)) {
111 SIPE_DEBUG_INFO("process_incoming_bye: disconnected from conference %s",
112 session
->im_mcu_uri
);
113 sipe_conf_immcu_closed(sipe_private
, session
);
114 } else if (session
->chat_session
->type
== SIPE_CHAT_TYPE_MULTIPARTY
) {
115 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_bye: disconnected from multiparty chat");
116 sipe_backend_chat_remove(session
->chat_session
->backend
,
124 void process_incoming_cancel(struct sipe_core_private
*sipe_private
,
127 const gchar
*callid
= sipmsg_find_header(msg
, "Call-ID");
130 struct sipe_media_call_private
*call_private
=
131 g_hash_table_lookup(sipe_private
->media_calls
, callid
);
132 if (is_media_session_msg(call_private
, msg
)) {
133 process_incoming_cancel_call(call_private
, msg
);
138 if (!sipe_session_find_chat_by_callid(sipe_private
, callid
))
139 sipe_conf_cancel_unaccepted(sipe_private
, msg
);
142 void process_incoming_info(struct sipe_core_private
*sipe_private
,
145 const gchar
*contenttype
= sipmsg_find_header(msg
, "Content-Type");
146 const gchar
*callid
= sipmsg_find_header(msg
, "Call-ID");
148 struct sip_session
*session
;
150 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_info");
152 /* Call Control protocol */
153 if (g_str_has_prefix(contenttype
, "application/csta+xml"))
155 process_incoming_info_csta(sipe_private
, msg
);
158 else if (g_str_has_prefix(contenttype
, "application/xml+conversationinfo"))
160 process_incoming_info_conversation(sipe_private
, msg
);
164 else if (g_str_has_prefix(contenttype
, "application/ms-filetransfer+xml"))
166 process_incoming_info_ft_lync(sipe_private
, msg
);
171 from
= parse_from(sipmsg_find_header(msg
, "From"));
172 session
= sipe_session_find_chat_or_im(sipe_private
, callid
, from
);
178 /* Group Chat uses text/plain */
179 if (session
->is_groupchat
) {
180 process_incoming_info_groupchat(sipe_private
, msg
, session
);
185 if (g_str_has_prefix(contenttype
, "application/x-ms-mim"))
187 sipe_xml
*xn_action
= sipe_xml_parse(msg
->body
, msg
->bodylen
);
188 const sipe_xml
*xn_request_rm
= sipe_xml_child(xn_action
, "RequestRM");
189 const sipe_xml
*xn_set_rm
= sipe_xml_child(xn_action
, "SetRM");
191 sipmsg_add_header(msg
, "Content-Type", "application/x-ms-mim");
194 //const char *rm = sipe_xml_attribute(xn_request_rm, "uri");
195 int bid
= sipe_xml_int_attribute(xn_request_rm
, "bid", 0);
196 gchar
*body
= g_strdup_printf(
197 "<?xml version=\"1.0\"?>\r\n"
198 "<action xmlns=\"http://schemas.microsoft.com/sip/multiparty/\">"
199 "<RequestRMResponse uri=\"sip:%s\" allow=\"%s\"/></action>\r\n",
200 sipe_private
->username
,
201 session
->bid
< bid
? "true" : "false");
202 sip_transport_response(sipe_private
, msg
, 200, "OK", body
);
204 } else if (xn_set_rm
) {
207 sipe_chat_set_roster_manager(session
,
208 sipe_xml_attribute(xn_set_rm
, "uri"));
210 body
= g_strdup_printf(
211 "<?xml version=\"1.0\"?>\r\n"
212 "<action xmlns=\"http://schemas.microsoft.com/sip/multiparty/\">"
213 "<SetRMResponse uri=\"sip:%s\"/></action>\r\n",
214 sipe_private
->username
);
215 sip_transport_response(sipe_private
, msg
, 200, "OK", body
);
218 sipe_xml_free(xn_action
);
223 /* looks like purple lacks typing notification for chat */
224 if (!session
->chat_session
) {
225 sipe_xml
*xn_keyboard_activity
= sipe_xml_parse(msg
->body
, msg
->bodylen
);
226 const char *status
= sipe_xml_attribute(sipe_xml_child(xn_keyboard_activity
, "status"),
228 if (sipe_strequal(status
, "type")) {
229 sipe_backend_user_feedback_typing(SIPE_CORE_PUBLIC
,
231 } else if (sipe_strequal(status
, "idle")) {
232 sipe_backend_user_feedback_typing_stop(SIPE_CORE_PUBLIC
,
235 sipe_xml_free(xn_keyboard_activity
);
238 sip_transport_response(sipe_private
, msg
, 200, "OK", NULL
);
243 static gboolean
sipe_process_incoming_x_msmsgsinvite(struct sipe_core_private
*sipe_private
,
244 struct sip_dialog
*dialog
,
247 gboolean found
= FALSE
;
250 const gchar
*invitation_command
= sipe_utils_nameval_find(parsed_body
, "Invitation-Command");
252 if (sipe_strequal(invitation_command
, "INVITE")) {
253 sipe_ft_incoming_transfer(sipe_private
, dialog
, parsed_body
);
255 } else if (sipe_strequal(invitation_command
, "CANCEL")) {
256 sipe_ft_incoming_cancel(dialog
, parsed_body
);
258 } else if (sipe_strequal(invitation_command
, "ACCEPT")) {
259 sipe_ft_incoming_accept(dialog
, parsed_body
);
267 static void sipe_invite_mime_cb(gpointer user_data
, const GSList
*fields
,
268 const gchar
*body
, gsize length
)
270 const gchar
*type
= sipe_utils_nameval_find(fields
, "Content-Type");
271 const gchar
*cd
= sipe_utils_nameval_find(fields
, "Content-Disposition");
273 if (!g_str_has_prefix(type
, "application/sdp"))
276 if (!cd
|| !strstr(cd
, "ms-proxy-2007fallback")) {
277 struct sipmsg
*msg
= user_data
;
278 const gchar
* msg_ct
= sipmsg_find_header(msg
, "Content-Type");
280 if (g_str_has_prefix(msg_ct
, "application/sdp")) {
281 /* We have already found suitable alternative and set message's body
282 * and Content-Type accordingly */
286 sipmsg_remove_header_now(msg
, "Content-Type");
287 sipmsg_add_header_now(msg
, "Content-Type", type
);
289 /* Replace message body with chosen alternative, so we can continue to
290 * process it as a normal single part message. */
292 msg
->body
= g_strndup(body
, length
);
293 msg
->bodylen
= length
;
298 static void send_invite_response(struct sipe_core_private
*sipe_private
,
301 gchar
*body
= g_strdup_printf(
303 "o=- 0 0 IN %s %s\r\n"
307 "m=%s %d sip sip:%s\r\n"
308 "a=accept-types:" SDP_ACCEPT_TYPES
"\r\n",
309 sip_transport_sdp_address_marker(sipe_private
),
310 sip_transport_ip_address(sipe_private
),
311 sip_transport_sdp_address_marker(sipe_private
),
312 sip_transport_ip_address(sipe_private
),
313 SIPE_CORE_PRIVATE_FLAG_IS(OCS2007
) ? "message" : "x-ms-message",
314 sip_transport_port(sipe_private
),
315 sipe_private
->username
);
316 sipmsg_add_header(msg
, "Content-Type", "application/sdp");
317 sip_transport_response(sipe_private
, msg
, 200, "OK", body
);
321 struct sipe_delayed_invite
{
326 static void delayed_invite_destroy(gpointer data
)
328 struct sipe_delayed_invite
*delayed_invite
= data
;
329 sipmsg_free(delayed_invite
->msg
);
330 g_free(delayed_invite
->action
);
331 g_free(delayed_invite
);
334 static void delayed_invite_timeout(struct sipe_core_private
*sipe_private
,
337 struct sipe_delayed_invite
*delayed_invite
= data
;
338 send_invite_response(sipe_private
, delayed_invite
->msg
);
341 static void delayed_invite_response(struct sipe_core_private
*sipe_private
,
345 struct sipe_delayed_invite
*delayed_invite
= g_new0(struct sipe_delayed_invite
, 1);
347 delayed_invite
->action
= g_strdup_printf("<delayed-invite-%s>", callid
);
348 delayed_invite
->msg
= sipmsg_copy(msg
);
349 sipe_schedule_seconds(sipe_private
,
350 delayed_invite
->action
,
353 delayed_invite_timeout
,
354 delayed_invite_destroy
);
357 void sipe_incoming_cancel_delayed_invite(struct sipe_core_private
*sipe_private
,
358 struct sip_dialog
*dialog
)
360 struct sipe_delayed_invite
*delayed_invite
= dialog
->delayed_invite
;
361 dialog
->delayed_invite
= NULL
;
362 send_invite_response(sipe_private
, delayed_invite
->msg
);
363 sipe_schedule_cancel(sipe_private
, delayed_invite
->action
);
366 void process_incoming_invite(struct sipe_core_private
*sipe_private
,
370 const gchar
*oldHeader
;
372 gboolean is_multiparty
= FALSE
;
373 gboolean was_multiparty
= TRUE
;
374 gboolean just_joined
= FALSE
;
376 const gchar
*callid
= sipmsg_find_header(msg
, "Call-ID");
377 const gchar
*roster_manager
= sipmsg_find_header(msg
, "Roster-Manager");
378 const gchar
*end_points_hdr
= sipmsg_find_header(msg
, "EndPoints");
379 const gchar
*trig_invite
= sipmsg_find_header(msg
, "TriggeredInvite");
380 const gchar
*content_type
= sipmsg_find_header(msg
, "Content-Type");
381 const gchar
*subject
= sipmsg_find_header(msg
, "Subject");
382 GSList
*end_points
= NULL
;
383 struct sip_session
*session
;
384 struct sip_dialog
*dialog
;
385 const gchar
*ms_text_format
;
386 gboolean dont_delay
= FALSE
;
389 if (g_str_has_prefix(content_type
, "multipart/alternative")) {
390 sipe_mime_parts_foreach(content_type
, msg
->body
, sipe_invite_mime_cb
, msg
);
391 /* Reload Content-Type to get type of the selected message part */
392 content_type
= sipmsg_find_header(msg
, "Content-Type");
396 if (g_str_has_prefix(content_type
, "multipart/mixed")) {
397 if (sipe_mime_parts_contain(content_type
, msg
->body
,
398 "application/ms-filetransfer+xml")) {
399 /* Lync 2010 file transfer */
401 process_incoming_invite_ft_lync(sipe_private
, msg
);
403 sip_transport_response(sipe_private
, msg
,
404 488, "Not Acceptable Here", NULL
);
410 /* Invitation to join conference */
411 if (g_str_has_prefix(content_type
, "application/ms-conf-invite+xml")) {
412 process_incoming_invite_conf(sipe_private
, msg
);
417 /* Application sharing */
418 if (sipe_strcase_equal(content_type
, "application/sdp") && msg
->body
&&
419 strstr(msg
->body
, "m=applicationsharing") &&
420 sipe_strequal(sipmsg_find_header(msg
, "CSeq"), "1 INVITE")) {
422 process_incoming_invite_appshare(sipe_private
, msg
);
424 sip_transport_response(sipe_private
, msg
,
425 488, "Not Acceptable Here", NULL
);
430 /* Invitation to audio call or file transfer */
432 (strstr(msg
->body
, "m=audio") || strstr(msg
->body
, "m=data") || strstr(msg
->body
, "m=applicationsharing"))) {
433 process_incoming_invite_call(sipe_private
, msg
, msg
->body
);
438 /* Only accept text invitations */
439 if (msg
->body
&& !(strstr(msg
->body
, "m=message") || strstr(msg
->body
, "m=x-ms-message"))) {
440 sip_transport_response(sipe_private
, msg
, 501, "Not implemented", NULL
);
444 // TODO There *must* be a better way to clean up the To header to add a tag...
445 SIPE_DEBUG_INFO_NOFORMAT("Adding a Tag to the To Header on Invite Request...");
446 oldHeader
= sipmsg_find_header(msg
, "To");
448 newHeader
= g_strdup_printf("%s;tag=%s", oldHeader
, newTag
);
450 sipmsg_remove_header_now(msg
, "To");
451 sipmsg_add_header_now(msg
, "To", newHeader
);
454 if (end_points_hdr
) {
455 end_points
= sipmsg_parse_endpoints_header(end_points_hdr
);
457 if (g_slist_length(end_points
) > 2) {
458 is_multiparty
= TRUE
;
461 if (trig_invite
&& !g_ascii_strcasecmp(trig_invite
, "TRUE")) {
462 is_multiparty
= TRUE
;
465 /* Multiparty session */
466 session
= sipe_session_find_chat_by_callid(sipe_private
, callid
);
470 if (session
->chat_session
) {
471 /* Update roster manager for existing multiparty session */
473 sipe_chat_set_roster_manager(session
, roster_manager
);
476 gchar
*chat_title
= sipe_chat_get_name();
478 /* Convert IM session to multiparty session */
479 g_free(session
->with
);
480 session
->with
= NULL
;
481 was_multiparty
= FALSE
;
482 session
->chat_session
= sipe_chat_create_session(SIPE_CHAT_TYPE_MULTIPARTY
,
489 /* New multiparty session */
490 session
= sipe_session_add_chat(sipe_private
,
497 if (!session
->chat_session
->backend
) {
498 gchar
*self
= sip_uri_self(sipe_private
);
499 session
->chat_session
->backend
= sipe_backend_chat_create(SIPE_CORE_PUBLIC
,
500 session
->chat_session
,
501 session
->chat_session
->title
,
508 from
= parse_from(sipmsg_find_header(msg
, "From"));
510 session
= sipe_session_find_or_add_im(sipe_private
, from
);
512 /* session is now initialized */
513 g_free(session
->callid
);
514 session
->callid
= g_strdup(callid
);
516 if (is_multiparty
&& end_points
) {
517 gchar
*to
= parse_from(sipmsg_find_header(msg
, "To"));
518 GSList
*entry
= end_points
;
520 struct sipendpoint
*end_point
= entry
->data
;
523 if (!g_ascii_strcasecmp(from
, end_point
->contact
) ||
524 !g_ascii_strcasecmp(to
, end_point
->contact
))
527 dialog
= sipe_dialog_find(session
, end_point
->contact
);
529 g_free(dialog
->theirepid
);
530 dialog
->theirepid
= end_point
->epid
;
531 end_point
->epid
= NULL
;
533 dialog
= sipe_dialog_add(session
);
535 dialog
->callid
= g_strdup(session
->callid
);
536 dialog
->with
= end_point
->contact
;
537 end_point
->contact
= NULL
;
538 dialog
->theirepid
= end_point
->epid
;
539 end_point
->epid
= NULL
;
543 /* send triggered INVITE */
544 sipe_im_invite(sipe_private
, session
, dialog
->with
, NULL
, NULL
, NULL
, TRUE
);
551 GSList
*entry
= end_points
;
553 struct sipendpoint
*end_point
= entry
->data
;
555 g_free(end_point
->contact
);
556 g_free(end_point
->epid
);
559 g_slist_free(end_points
);
562 dialog
= sipe_dialog_find(session
, from
);
564 sipe_im_cancel_dangling(sipe_private
, session
, dialog
, from
,
565 sipe_im_reenqueue_unconfirmed
);
566 /* dialog is no longer valid */
571 dialog
= sipe_dialog_add(session
);
572 dialog
->with
= g_strdup(from
);
573 dialog
->callid
= g_strdup(session
->callid
);
574 dialog
->is_established
= TRUE
;
575 sipe_dialog_parse(dialog
, msg
, FALSE
);
577 if (is_multiparty
&& !was_multiparty
) {
578 /* add current IM counterparty to chat */
579 sipe_backend_chat_add(session
->chat_session
->backend
,
580 sipe_dialog_first(session
)->with
,
584 /* add inviting party to chat */
585 if (just_joined
&& session
->chat_session
) {
586 sipe_backend_chat_add(session
->chat_session
->backend
,
591 if (!is_multiparty
&& subject
)
592 sipe_im_topic(sipe_private
, session
, subject
);
594 /* ms-text-format: text/plain; charset=UTF-8;msgr=WAAtAE0...DIADQAKAA0ACgA;ms-body=SGk= */
596 /* This used only in 2005 official client, not 2007 or Reuters.
597 Disabled for most cases as interfering with audit of messages which only is applied to regular MESSAGEs.
598 Only enabled for 2005 multiparty chats as otherwise the first message got lost completely.
600 /* also enabled for 2005 file transfer. Didn't work otherwise. */
601 ms_text_format
= sipmsg_find_header(msg
, "ms-text-format");
603 (ms_text_format
&& g_str_has_prefix(ms_text_format
, "text/x-msmsgsinvite")) )
605 if (ms_text_format
) {
606 if (g_str_has_prefix(ms_text_format
, "text/x-msmsgsinvite"))
610 else if (g_str_has_prefix(ms_text_format
, "text/plain") || g_str_has_prefix(ms_text_format
, "text/html"))
612 /* please do not optimize logic inside as this code may be re-enabled for other cases */
613 gchar
*html
= get_html_message(ms_text_format
, NULL
);
616 sipe_backend_chat_message(SIPE_CORE_PUBLIC
,
617 session
->chat_session
->backend
,
622 sipe_backend_im_message(SIPE_CORE_PUBLIC
,
627 sipmsg_add_header(msg
, "Supported", "ms-text-format"); /* accepts received message */
636 sipmsg_add_header(msg
, "Supported", "com.microsoft.rtc-multiparty");
638 if (dont_delay
|| !SIPE_CORE_PRIVATE_FLAG_IS(MPOP
)) {
639 send_invite_response(sipe_private
, msg
);
641 delayed_invite_response(sipe_private
, msg
, session
->callid
);
645 void process_incoming_message(struct sipe_core_private
*sipe_private
,
649 const gchar
*contenttype
;
650 gboolean found
= FALSE
;
652 from
= parse_from(sipmsg_find_header(msg
, "From"));
656 SIPE_DEBUG_INFO("got message from %s: %s", from
, msg
->body
);
658 contenttype
= sipmsg_find_header(msg
, "Content-Type");
659 if (g_str_has_prefix(contenttype
, "text/plain")
660 || g_str_has_prefix(contenttype
, "text/html")
661 || g_str_has_prefix(contenttype
, "multipart/related")
662 || g_str_has_prefix(contenttype
, "multipart/alternative"))
664 const gchar
*callid
= sipmsg_find_header(msg
, "Call-ID");
665 gchar
*html
= get_html_message(contenttype
, msg
->body
);
667 struct sip_session
*session
= sipe_session_find_chat_or_im(sipe_private
,
670 if (session
&& session
->chat_session
) {
671 if (session
->chat_session
->type
== SIPE_CHAT_TYPE_CONFERENCE
) { /* a conference */
672 gchar
*tmp
= parse_from(sipmsg_find_header(msg
, "Ms-Sender"));
673 gchar
*sender
= parse_from(tmp
);
675 sipe_backend_chat_message(SIPE_CORE_PUBLIC
,
676 session
->chat_session
->backend
,
681 } else { /* a multiparty chat */
682 sipe_backend_chat_message(SIPE_CORE_PUBLIC
,
683 session
->chat_session
->backend
,
689 sipe_backend_im_message(SIPE_CORE_PUBLIC
,
694 sip_transport_response(sipe_private
, msg
, 200, "OK", NULL
);
697 } else if (g_str_has_prefix(contenttype
, "application/im-iscomposing+xml")) {
698 sipe_xml
*isc
= sipe_xml_parse(msg
->body
, msg
->bodylen
);
699 const sipe_xml
*state
;
703 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_message: can not parse iscomposing");
708 state
= sipe_xml_child(isc
, "state");
711 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_message: no state found");
717 statedata
= sipe_xml_data(state
);
719 if (strstr(statedata
, "active")) {
720 sipe_backend_user_feedback_typing(SIPE_CORE_PUBLIC
,
723 sipe_backend_user_feedback_typing_stop(SIPE_CORE_PUBLIC
,
729 sip_transport_response(sipe_private
, msg
, 200, "OK", NULL
);
731 } else if (g_str_has_prefix(contenttype
, "text/x-msmsgsinvite")) {
732 const gchar
*callid
= sipmsg_find_header(msg
, "Call-ID");
733 struct sip_session
*session
= sipe_session_find_chat_or_im(sipe_private
,
737 struct sip_dialog
*dialog
= sipe_dialog_find(session
, from
);
738 GSList
*body
= sipe_ft_parse_msg_body(msg
->body
);
739 found
= sipe_process_incoming_x_msmsgsinvite(sipe_private
, dialog
, body
);
740 sipe_utils_nameval_free(body
);
742 sip_transport_response(sipe_private
, msg
, 200, "OK", NULL
);
745 sip_transport_response(sipe_private
, msg
, 481,
746 "Call Leg/Transaction Does Not Exist", NULL
);
751 const gchar
*callid
= sipmsg_find_header(msg
, "Call-ID");
752 struct sip_session
*session
= sipe_session_find_chat_or_im(sipe_private
,
756 gchar
*errmsg
= g_strdup_printf(_("Received a message with unrecognized contents from %s"),
758 sipe_user_present_error(sipe_private
, session
, errmsg
);
762 SIPE_DEBUG_INFO("got unknown mime-type '%s'", contenttype
);
763 sip_transport_response(sipe_private
, msg
, 415, "Unsupported media type", NULL
);
768 void process_incoming_options(struct sipe_core_private
*sipe_private
,
773 sipmsg_add_header(msg
, "Allow", "INVITE, MESSAGE, INFO, SUBSCRIBE, OPTIONS, BYE, CANCEL, NOTIFY, ACK, REFER, BENOTIFY");
774 sipmsg_add_header(msg
, "Content-Type", "application/sdp");
776 body
= g_strdup_printf(
778 "o=- 0 0 IN IP4 0.0.0.0\r\n"
780 "c=IN IP4 0.0.0.0\r\n"
782 "m=%s %d sip sip:%s\r\n"
783 "a=accept-types:" SDP_ACCEPT_TYPES
"\r\n",
784 SIPE_CORE_PRIVATE_FLAG_IS(OCS2007
) ? "message" : "x-ms-message",
785 sip_transport_port(sipe_private
),
786 sipe_private
->username
);
787 sip_transport_response(sipe_private
, msg
, 200, "OK", body
);
791 void process_incoming_refer(struct sipe_core_private
*sipe_private
,
794 gchar
*self
= sip_uri_self(sipe_private
);
795 const gchar
*callid
= sipmsg_find_header(msg
, "Call-ID");
796 gchar
*from
= parse_from(sipmsg_find_header(msg
, "From"));
797 gchar
*refer_to
= parse_from(sipmsg_find_header(msg
, "Refer-to"));
798 gchar
*referred_by
= g_strdup(sipmsg_find_header(msg
, "Referred-By"));
799 struct sip_session
*session
;
800 struct sip_dialog
*dialog
;
802 session
= sipe_session_find_chat_by_callid(sipe_private
, callid
);
803 dialog
= sipe_dialog_find(session
, from
);
805 if (!session
|| !dialog
|| !session
->chat_session
||
806 (session
->chat_session
->type
!= SIPE_CHAT_TYPE_MULTIPARTY
) ||
807 !session
->chat_session
->id
||
808 !sipe_strcase_equal(session
->chat_session
->id
, self
)) {
809 sip_transport_response(sipe_private
, msg
, 500, "Server Internal Error", NULL
);
811 sip_transport_response(sipe_private
, msg
, 202, "Accepted", NULL
);
813 sipe_im_invite(sipe_private
, session
, refer_to
, NULL
, NULL
, referred_by
, FALSE
);