2 * @file sipe-incoming.c
6 * Copyright (C) 2010-2012 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 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
,
576 /* add inviting party to chat */
577 if (just_joined
&& session
->chat_session
) {
578 sipe_backend_chat_add(session
->chat_session
->backend
,
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");
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"))
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
);
608 sipe_backend_chat_message(SIPE_CORE_PUBLIC
,
609 session
->chat_session
->backend
,
613 sipe_backend_im_message(SIPE_CORE_PUBLIC
,
618 sipmsg_add_header(msg
, "Supported", "ms-text-format"); /* accepts received message */
627 sipmsg_add_header(msg
, "Supported", "com.microsoft.rtc-multiparty");
629 if (dont_delay
|| !SIPE_CORE_PRIVATE_FLAG_IS(MPOP
)) {
630 send_invite_response(sipe_private
, msg
);
632 delayed_invite_response(sipe_private
, msg
, session
->callid
);
636 void process_incoming_message(struct sipe_core_private
*sipe_private
,
640 const gchar
*contenttype
;
641 gboolean found
= FALSE
;
643 from
= parse_from(sipmsg_find_header(msg
, "From"));
647 SIPE_DEBUG_INFO("got message from %s: %s", from
, msg
->body
);
649 contenttype
= sipmsg_find_header(msg
, "Content-Type");
650 if (g_str_has_prefix(contenttype
, "text/plain")
651 || g_str_has_prefix(contenttype
, "text/html")
652 || g_str_has_prefix(contenttype
, "multipart/related")
653 || g_str_has_prefix(contenttype
, "multipart/alternative"))
655 const gchar
*callid
= sipmsg_find_header(msg
, "Call-ID");
656 gchar
*html
= get_html_message(contenttype
, msg
->body
);
658 struct sip_session
*session
= sipe_session_find_chat_or_im(sipe_private
,
661 if (session
&& session
->chat_session
) {
662 if (session
->chat_session
->type
== SIPE_CHAT_TYPE_CONFERENCE
) { /* a conference */
663 gchar
*tmp
= parse_from(sipmsg_find_header(msg
, "Ms-Sender"));
664 gchar
*sender
= parse_from(tmp
);
666 sipe_backend_chat_message(SIPE_CORE_PUBLIC
,
667 session
->chat_session
->backend
,
671 } else { /* a multiparty chat */
672 sipe_backend_chat_message(SIPE_CORE_PUBLIC
,
673 session
->chat_session
->backend
,
678 sipe_backend_im_message(SIPE_CORE_PUBLIC
,
683 sip_transport_response(sipe_private
, msg
, 200, "OK", NULL
);
686 } else if (g_str_has_prefix(contenttype
, "application/im-iscomposing+xml")) {
687 sipe_xml
*isc
= sipe_xml_parse(msg
->body
, msg
->bodylen
);
688 const sipe_xml
*state
;
692 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_message: can not parse iscomposing");
697 state
= sipe_xml_child(isc
, "state");
700 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_message: no state found");
706 statedata
= sipe_xml_data(state
);
708 if (strstr(statedata
, "active")) {
709 sipe_backend_user_feedback_typing(SIPE_CORE_PUBLIC
,
712 sipe_backend_user_feedback_typing_stop(SIPE_CORE_PUBLIC
,
718 sip_transport_response(sipe_private
, msg
, 200, "OK", NULL
);
720 } else if (g_str_has_prefix(contenttype
, "text/x-msmsgsinvite")) {
721 const gchar
*callid
= sipmsg_find_header(msg
, "Call-ID");
722 struct sip_session
*session
= sipe_session_find_chat_or_im(sipe_private
,
726 struct sip_dialog
*dialog
= sipe_dialog_find(session
, from
);
727 GSList
*body
= sipe_ft_parse_msg_body(msg
->body
);
728 found
= sipe_process_incoming_x_msmsgsinvite(sipe_private
, dialog
, body
);
729 sipe_utils_nameval_free(body
);
731 sip_transport_response(sipe_private
, msg
, 200, "OK", NULL
);
734 sip_transport_response(sipe_private
, msg
, 481,
735 "Call Leg/Transaction Does Not Exist", NULL
);
740 const gchar
*callid
= sipmsg_find_header(msg
, "Call-ID");
741 struct sip_session
*session
= sipe_session_find_chat_or_im(sipe_private
,
745 gchar
*errmsg
= g_strdup_printf(_("Received a message with unrecognized contents from %s"),
747 sipe_user_present_error(sipe_private
, session
, errmsg
);
751 SIPE_DEBUG_INFO("got unknown mime-type '%s'", contenttype
);
752 sip_transport_response(sipe_private
, msg
, 415, "Unsupported media type", NULL
);
757 void process_incoming_options(struct sipe_core_private
*sipe_private
,
762 sipmsg_add_header(msg
, "Allow", "INVITE, MESSAGE, INFO, SUBSCRIBE, OPTIONS, BYE, CANCEL, NOTIFY, ACK, REFER, BENOTIFY");
763 sipmsg_add_header(msg
, "Content-Type", "application/sdp");
765 body
= g_strdup_printf(
767 "o=- 0 0 IN IP4 0.0.0.0\r\n"
769 "c=IN IP4 0.0.0.0\r\n"
771 "m=%s %d sip sip:%s\r\n"
772 "a=accept-types:" SDP_ACCEPT_TYPES
"\r\n",
773 SIPE_CORE_PRIVATE_FLAG_IS(OCS2007
) ? "message" : "x-ms-message",
774 sip_transport_port(sipe_private
),
775 sipe_private
->username
);
776 sip_transport_response(sipe_private
, msg
, 200, "OK", body
);
780 void process_incoming_refer(struct sipe_core_private
*sipe_private
,
783 gchar
*self
= sip_uri_self(sipe_private
);
784 const gchar
*callid
= sipmsg_find_header(msg
, "Call-ID");
785 gchar
*from
= parse_from(sipmsg_find_header(msg
, "From"));
786 gchar
*refer_to
= parse_from(sipmsg_find_header(msg
, "Refer-to"));
787 gchar
*referred_by
= g_strdup(sipmsg_find_header(msg
, "Referred-By"));
788 struct sip_session
*session
;
789 struct sip_dialog
*dialog
;
791 session
= sipe_session_find_chat_by_callid(sipe_private
, callid
);
792 dialog
= sipe_dialog_find(session
, from
);
794 if (!session
|| !dialog
|| !session
->chat_session
||
795 (session
->chat_session
->type
!= SIPE_CHAT_TYPE_MULTIPARTY
) ||
796 !session
->chat_session
->id
||
797 !sipe_strcase_equal(session
->chat_session
->id
, self
)) {
798 sip_transport_response(sipe_private
, msg
, 500, "Server Internal Error", NULL
);
800 sip_transport_response(sipe_private
, msg
, 202, "Accepted", NULL
);
802 sipe_im_invite(sipe_private
, session
, refer_to
, NULL
, NULL
, referred_by
, FALSE
);