2 * @file sipe-incoming.c
6 * Copyright (C) 2010-2016 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
36 #include "sipe-appshare.h"
39 #include "sip-transport.h"
40 #include "sipe-backend.h"
41 #include "sipe-chat.h"
42 #include "sipe-conf.h"
43 #include "sipe-core.h"
44 #include "sipe-core-private.h"
45 #include "sipe-dialog.h"
47 #include "sipe-ft-lync.h"
48 #include "sipe-groupchat.h"
50 #include "sipe-incoming.h"
51 #include "sipe-media.h"
52 #include "sipe-mime.h"
54 #include "sipe-schedule.h"
55 #include "sipe-session.h"
56 #include "sipe-user.h"
57 #include "sipe-utils.h"
60 void process_incoming_bye(struct sipe_core_private
*sipe_private
,
63 const gchar
*callid
= sipmsg_find_header(msg
, "Call-ID");
64 gchar
*from
= parse_from(sipmsg_find_header(msg
, "From"));
65 struct sip_session
*session
;
66 struct sip_dialog
*dialog
;
69 struct sipe_media_call_private
*call_private
=
70 g_hash_table_lookup(sipe_private
->media_calls
, callid
);
71 if (is_media_session_msg(call_private
, msg
)) {
72 // BYE ends a media call
73 sipe_media_hangup(call_private
);
77 /* collect dialog identification
78 * we need callid, ourtag and theirtag to unambiguously identify dialog
80 /* take data before 'msg' will be modified by sip_transport_response */
81 dialog
= g_new0(struct sip_dialog
, 1);
82 dialog
->callid
= g_strdup(callid
);
83 dialog
->cseq
= sipmsg_parse_cseq(msg
);
84 dialog
->with
= g_strdup(from
);
85 sipe_dialog_parse(dialog
, msg
, FALSE
);
87 sip_transport_response(sipe_private
, msg
, 200, "OK", NULL
);
89 session
= sipe_session_find_chat_or_im(sipe_private
, callid
, from
);
91 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_bye: couldn't find session. Ignoring");
92 sipe_dialog_free(dialog
);
97 SIPE_DEBUG_INFO("process_incoming_bye: session found (chat ID %s)",
98 (session
->chat_session
&& session
->chat_session
->id
) ?
99 session
->chat_session
->id
: "<NO CHAT>");
101 if (session
->chat_session
&&
102 (session
->chat_session
->type
== SIPE_CHAT_TYPE_MULTIPARTY
) &&
103 session
->chat_session
->id
&&
104 !g_ascii_strcasecmp(from
, session
->chat_session
->id
))
105 sipe_chat_set_roster_manager(session
, NULL
);
107 sipe_im_cancel_unconfirmed(sipe_private
, session
, callid
, from
);
109 /* This what BYE is essentially for - terminating dialog */
110 sipe_dialog_remove_3(session
, dialog
);
111 sipe_dialog_free(dialog
);
112 if (session
->chat_session
) {
113 if ((session
->chat_session
->type
== SIPE_CHAT_TYPE_CONFERENCE
) &&
114 !g_ascii_strcasecmp(from
, session
->im_mcu_uri
)) {
115 SIPE_DEBUG_INFO("process_incoming_bye: disconnected from conference %s",
116 session
->im_mcu_uri
);
117 sipe_conf_immcu_closed(sipe_private
, session
);
118 } else if (session
->chat_session
->type
== SIPE_CHAT_TYPE_MULTIPARTY
) {
119 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_bye: disconnected from multiparty chat");
120 sipe_backend_chat_remove(session
->chat_session
->backend
,
128 void process_incoming_cancel(struct sipe_core_private
*sipe_private
,
131 const gchar
*callid
= sipmsg_find_header(msg
, "Call-ID");
134 struct sipe_media_call_private
*call_private
=
135 g_hash_table_lookup(sipe_private
->media_calls
, callid
);
136 if (is_media_session_msg(call_private
, msg
)) {
137 process_incoming_cancel_call(call_private
, msg
);
142 if (!sipe_session_find_chat_by_callid(sipe_private
, callid
))
143 sipe_conf_cancel_unaccepted(sipe_private
, msg
);
146 void process_incoming_info(struct sipe_core_private
*sipe_private
,
149 const gchar
*contenttype
= sipmsg_find_header(msg
, "Content-Type");
150 const gchar
*callid
= sipmsg_find_header(msg
, "Call-ID");
152 struct sip_session
*session
;
154 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_info");
156 /* Call Control protocol */
157 if (g_str_has_prefix(contenttype
, "application/csta+xml"))
159 process_incoming_info_csta(sipe_private
, msg
);
162 else if (g_str_has_prefix(contenttype
, "application/xml+conversationinfo"))
164 process_incoming_info_conversation(sipe_private
, msg
);
168 else if (g_str_has_prefix(contenttype
, "application/ms-filetransfer+xml"))
170 process_incoming_info_ft_lync(sipe_private
, msg
);
175 from
= parse_from(sipmsg_find_header(msg
, "From"));
176 session
= sipe_session_find_chat_or_im(sipe_private
, callid
, from
);
182 /* Group Chat uses text/plain */
183 if (session
->is_groupchat
) {
184 process_incoming_info_groupchat(sipe_private
, msg
, session
);
189 if (g_str_has_prefix(contenttype
, "application/x-ms-mim"))
191 sipe_xml
*xn_action
= sipe_xml_parse(msg
->body
, msg
->bodylen
);
192 const sipe_xml
*xn_request_rm
= sipe_xml_child(xn_action
, "RequestRM");
193 const sipe_xml
*xn_set_rm
= sipe_xml_child(xn_action
, "SetRM");
195 sipmsg_add_header(msg
, "Content-Type", "application/x-ms-mim");
198 //const char *rm = sipe_xml_attribute(xn_request_rm, "uri");
199 int bid
= sipe_xml_int_attribute(xn_request_rm
, "bid", 0);
200 gchar
*body
= g_strdup_printf(
201 "<?xml version=\"1.0\"?>\r\n"
202 "<action xmlns=\"http://schemas.microsoft.com/sip/multiparty/\">"
203 "<RequestRMResponse uri=\"sip:%s\" allow=\"%s\"/></action>\r\n",
204 sipe_private
->username
,
205 session
->bid
< bid
? "true" : "false");
206 sip_transport_response(sipe_private
, msg
, 200, "OK", body
);
208 } else if (xn_set_rm
) {
211 sipe_chat_set_roster_manager(session
,
212 sipe_xml_attribute(xn_set_rm
, "uri"));
214 body
= g_strdup_printf(
215 "<?xml version=\"1.0\"?>\r\n"
216 "<action xmlns=\"http://schemas.microsoft.com/sip/multiparty/\">"
217 "<SetRMResponse uri=\"sip:%s\"/></action>\r\n",
218 sipe_private
->username
);
219 sip_transport_response(sipe_private
, msg
, 200, "OK", body
);
222 sipe_xml_free(xn_action
);
227 /* looks like purple lacks typing notification for chat */
228 if (!session
->chat_session
) {
229 sipe_xml
*xn_keyboard_activity
= sipe_xml_parse(msg
->body
, msg
->bodylen
);
230 const char *status
= sipe_xml_attribute(sipe_xml_child(xn_keyboard_activity
, "status"),
232 if (sipe_strequal(status
, "type")) {
233 sipe_backend_user_feedback_typing(SIPE_CORE_PUBLIC
,
235 } else if (sipe_strequal(status
, "idle")) {
236 sipe_backend_user_feedback_typing_stop(SIPE_CORE_PUBLIC
,
239 sipe_xml_free(xn_keyboard_activity
);
242 sip_transport_response(sipe_private
, msg
, 200, "OK", NULL
);
247 static gboolean
sipe_process_incoming_x_msmsgsinvite(struct sipe_core_private
*sipe_private
,
248 struct sip_dialog
*dialog
,
251 gboolean found
= FALSE
;
254 const gchar
*invitation_command
= sipe_utils_nameval_find(parsed_body
, "Invitation-Command");
256 if (sipe_strequal(invitation_command
, "INVITE")) {
257 sipe_ft_incoming_transfer(sipe_private
, dialog
, parsed_body
);
259 } else if (sipe_strequal(invitation_command
, "CANCEL")) {
260 sipe_ft_incoming_cancel(dialog
, parsed_body
);
262 } else if (sipe_strequal(invitation_command
, "ACCEPT")) {
263 sipe_ft_incoming_accept(dialog
, parsed_body
);
271 static void sipe_invite_mime_cb(gpointer user_data
, const GSList
*fields
,
272 const gchar
*body
, gsize length
)
274 const gchar
*type
= sipe_utils_nameval_find(fields
, "Content-Type");
275 const gchar
*cd
= sipe_utils_nameval_find(fields
, "Content-Disposition");
277 if (!g_str_has_prefix(type
, "application/sdp"))
280 if (!cd
|| !strstr(cd
, "ms-proxy-2007fallback")) {
281 struct sipmsg
*msg
= user_data
;
282 const gchar
* msg_ct
= sipmsg_find_header(msg
, "Content-Type");
284 if (g_str_has_prefix(msg_ct
, "application/sdp")) {
285 /* We have already found suitable alternative and set message's body
286 * and Content-Type accordingly */
290 sipmsg_remove_header_now(msg
, "Content-Type");
291 sipmsg_add_header_now(msg
, "Content-Type", type
);
293 /* Replace message body with chosen alternative, so we can continue to
294 * process it as a normal single part message. */
296 msg
->body
= g_strndup(body
, length
);
297 msg
->bodylen
= length
;
302 static void send_invite_response(struct sipe_core_private
*sipe_private
,
305 gchar
*body
= g_strdup_printf(
307 "o=- 0 0 IN IP4 %s\r\n"
311 "m=%s %d sip sip:%s\r\n"
312 "a=accept-types:" SDP_ACCEPT_TYPES
"\r\n",
313 sip_transport_ip_address(sipe_private
),
314 sip_transport_ip_address(sipe_private
),
315 SIPE_CORE_PRIVATE_FLAG_IS(OCS2007
) ? "message" : "x-ms-message",
316 sip_transport_port(sipe_private
),
317 sipe_private
->username
);
318 sipmsg_add_header(msg
, "Content-Type", "application/sdp");
319 sip_transport_response(sipe_private
, msg
, 200, "OK", body
);
323 struct sipe_delayed_invite
{
328 static void delayed_invite_destroy(gpointer data
)
330 struct sipe_delayed_invite
*delayed_invite
= data
;
331 sipmsg_free(delayed_invite
->msg
);
332 g_free(delayed_invite
->action
);
333 g_free(delayed_invite
);
336 static void delayed_invite_timeout(struct sipe_core_private
*sipe_private
,
339 struct sipe_delayed_invite
*delayed_invite
= data
;
340 send_invite_response(sipe_private
, delayed_invite
->msg
);
343 static void delayed_invite_response(struct sipe_core_private
*sipe_private
,
347 struct sipe_delayed_invite
*delayed_invite
= g_new0(struct sipe_delayed_invite
, 1);
349 delayed_invite
->action
= g_strdup_printf("<delayed-invite-%s>", callid
);
350 delayed_invite
->msg
= sipmsg_copy(msg
);
351 sipe_schedule_seconds(sipe_private
,
352 delayed_invite
->action
,
355 delayed_invite_timeout
,
356 delayed_invite_destroy
);
359 void sipe_incoming_cancel_delayed_invite(struct sipe_core_private
*sipe_private
,
360 struct sip_dialog
*dialog
)
362 struct sipe_delayed_invite
*delayed_invite
= dialog
->delayed_invite
;
363 dialog
->delayed_invite
= NULL
;
364 send_invite_response(sipe_private
, delayed_invite
->msg
);
365 sipe_schedule_cancel(sipe_private
, delayed_invite
->action
);
368 void process_incoming_invite(struct sipe_core_private
*sipe_private
,
372 const gchar
*oldHeader
;
374 gboolean is_multiparty
= FALSE
;
375 gboolean was_multiparty
= TRUE
;
376 gboolean just_joined
= FALSE
;
378 const gchar
*callid
= sipmsg_find_header(msg
, "Call-ID");
379 const gchar
*roster_manager
= sipmsg_find_header(msg
, "Roster-Manager");
380 const gchar
*end_points_hdr
= sipmsg_find_header(msg
, "EndPoints");
381 const gchar
*trig_invite
= sipmsg_find_header(msg
, "TriggeredInvite");
382 const gchar
*content_type
= sipmsg_find_header(msg
, "Content-Type");
383 const gchar
*subject
= sipmsg_find_header(msg
, "Subject");
384 GSList
*end_points
= NULL
;
385 struct sip_session
*session
;
386 struct sip_dialog
*dialog
;
387 const gchar
*ms_text_format
;
388 gboolean dont_delay
= FALSE
;
391 if (g_str_has_prefix(content_type
, "multipart/alternative")) {
392 sipe_mime_parts_foreach(content_type
, msg
->body
, sipe_invite_mime_cb
, msg
);
393 /* Reload Content-Type to get type of the selected message part */
394 content_type
= sipmsg_find_header(msg
, "Content-Type");
398 if (g_str_has_prefix(content_type
, "multipart/mixed")) {
399 if (sipe_mime_parts_contain(content_type
, msg
->body
,
400 "application/ms-filetransfer+xml")) {
401 /* Lync 2010 file transfer */
403 process_incoming_invite_ft_lync(sipe_private
, msg
);
405 sip_transport_response(sipe_private
, msg
,
406 488, "Not Acceptable Here", NULL
);
412 /* Invitation to join conference */
413 if (g_str_has_prefix(content_type
, "application/ms-conf-invite+xml")) {
414 process_incoming_invite_conf(sipe_private
, msg
);
419 /* Application sharing */
420 if (sipe_strcase_equal(content_type
, "application/sdp") && msg
->body
&&
421 strstr(msg
->body
, "m=applicationsharing") &&
422 sipe_strequal(sipmsg_find_header(msg
, "CSeq"), "1 INVITE")) {
423 #if defined(HAVE_XDATA) && defined(HAVE_GIO)
424 process_incoming_invite_appshare(sipe_private
, msg
);
426 sip_transport_response(sipe_private
, msg
,
427 488, "Not Acceptable Here", NULL
);
432 /* Invitation to audio call or file transfer */
434 (strstr(msg
->body
, "m=audio") || strstr(msg
->body
, "m=data") || strstr(msg
->body
, "m=applicationsharing"))) {
435 process_incoming_invite_call(sipe_private
, msg
);
440 /* Only accept text invitations */
441 if (msg
->body
&& !(strstr(msg
->body
, "m=message") || strstr(msg
->body
, "m=x-ms-message"))) {
442 sip_transport_response(sipe_private
, msg
, 501, "Not implemented", NULL
);
446 // TODO There *must* be a better way to clean up the To header to add a tag...
447 SIPE_DEBUG_INFO_NOFORMAT("Adding a Tag to the To Header on Invite Request...");
448 oldHeader
= sipmsg_find_header(msg
, "To");
450 newHeader
= g_strdup_printf("%s;tag=%s", oldHeader
, newTag
);
452 sipmsg_remove_header_now(msg
, "To");
453 sipmsg_add_header_now(msg
, "To", newHeader
);
456 if (end_points_hdr
) {
457 end_points
= sipmsg_parse_endpoints_header(end_points_hdr
);
459 if (g_slist_length(end_points
) > 2) {
460 is_multiparty
= TRUE
;
463 if (trig_invite
&& !g_ascii_strcasecmp(trig_invite
, "TRUE")) {
464 is_multiparty
= TRUE
;
467 /* Multiparty session */
468 session
= sipe_session_find_chat_by_callid(sipe_private
, callid
);
472 if (session
->chat_session
) {
473 /* Update roster manager for existing multiparty session */
475 sipe_chat_set_roster_manager(session
, roster_manager
);
478 gchar
*chat_title
= sipe_chat_get_name();
480 /* Convert IM session to multiparty session */
481 g_free(session
->with
);
482 session
->with
= NULL
;
483 was_multiparty
= FALSE
;
484 session
->chat_session
= sipe_chat_create_session(SIPE_CHAT_TYPE_MULTIPARTY
,
491 /* New multiparty session */
492 session
= sipe_session_add_chat(sipe_private
,
499 if (!session
->chat_session
->backend
) {
500 gchar
*self
= sip_uri_self(sipe_private
);
501 session
->chat_session
->backend
= sipe_backend_chat_create(SIPE_CORE_PUBLIC
,
502 session
->chat_session
,
503 session
->chat_session
->title
,
510 from
= parse_from(sipmsg_find_header(msg
, "From"));
512 session
= sipe_session_find_or_add_im(sipe_private
, from
);
514 /* session is now initialized */
515 g_free(session
->callid
);
516 session
->callid
= g_strdup(callid
);
518 if (is_multiparty
&& end_points
) {
519 gchar
*to
= parse_from(sipmsg_find_header(msg
, "To"));
520 GSList
*entry
= end_points
;
522 struct sipendpoint
*end_point
= entry
->data
;
525 if (!g_ascii_strcasecmp(from
, end_point
->contact
) ||
526 !g_ascii_strcasecmp(to
, end_point
->contact
))
529 dialog
= sipe_dialog_find(session
, end_point
->contact
);
531 g_free(dialog
->theirepid
);
532 dialog
->theirepid
= end_point
->epid
;
533 end_point
->epid
= NULL
;
535 dialog
= sipe_dialog_add(session
);
537 dialog
->callid
= g_strdup(session
->callid
);
538 dialog
->with
= end_point
->contact
;
539 end_point
->contact
= NULL
;
540 dialog
->theirepid
= end_point
->epid
;
541 end_point
->epid
= NULL
;
545 /* send triggered INVITE */
546 sipe_im_invite(sipe_private
, session
, dialog
->with
, NULL
, NULL
, NULL
, TRUE
);
553 GSList
*entry
= end_points
;
555 struct sipendpoint
*end_point
= entry
->data
;
557 g_free(end_point
->contact
);
558 g_free(end_point
->epid
);
561 g_slist_free(end_points
);
564 dialog
= sipe_dialog_find(session
, from
);
566 sipe_im_cancel_dangling(sipe_private
, session
, dialog
, from
,
567 sipe_im_reenqueue_unconfirmed
);
568 /* dialog is no longer valid */
573 dialog
= sipe_dialog_add(session
);
574 dialog
->with
= g_strdup(from
);
575 dialog
->callid
= g_strdup(session
->callid
);
576 dialog
->is_established
= TRUE
;
577 sipe_dialog_parse(dialog
, msg
, FALSE
);
579 if (is_multiparty
&& !was_multiparty
) {
580 /* add current IM counterparty to chat */
581 sipe_backend_chat_add(session
->chat_session
->backend
,
582 sipe_dialog_first(session
)->with
,
586 /* add inviting party to chat */
587 if (just_joined
&& session
->chat_session
) {
588 sipe_backend_chat_add(session
->chat_session
->backend
,
593 if (!is_multiparty
&& subject
)
594 sipe_im_topic(sipe_private
, session
, subject
);
596 /* ms-text-format: text/plain; charset=UTF-8;msgr=WAAtAE0...DIADQAKAA0ACgA;ms-body=SGk= */
598 /* This used only in 2005 official client, not 2007 or Reuters.
599 Disabled for most cases as interfering with audit of messages which only is applied to regular MESSAGEs.
600 Only enabled for 2005 multiparty chats as otherwise the first message got lost completely.
602 /* also enabled for 2005 file transfer. Didn't work otherwise. */
603 ms_text_format
= sipmsg_find_header(msg
, "ms-text-format");
605 (ms_text_format
&& g_str_has_prefix(ms_text_format
, "text/x-msmsgsinvite")) )
607 if (ms_text_format
) {
608 if (g_str_has_prefix(ms_text_format
, "text/x-msmsgsinvite"))
612 else if (g_str_has_prefix(ms_text_format
, "text/plain") || g_str_has_prefix(ms_text_format
, "text/html"))
614 /* please do not optimize logic inside as this code may be re-enabled for other cases */
615 gchar
*html
= get_html_message(ms_text_format
, NULL
);
618 sipe_backend_chat_message(SIPE_CORE_PUBLIC
,
619 session
->chat_session
->backend
,
624 sipe_backend_im_message(SIPE_CORE_PUBLIC
,
629 sipmsg_add_header(msg
, "Supported", "ms-text-format"); /* accepts received message */
638 sipmsg_add_header(msg
, "Supported", "com.microsoft.rtc-multiparty");
640 if (dont_delay
|| !SIPE_CORE_PRIVATE_FLAG_IS(MPOP
)) {
641 send_invite_response(sipe_private
, msg
);
643 delayed_invite_response(sipe_private
, msg
, session
->callid
);
647 void process_incoming_message(struct sipe_core_private
*sipe_private
,
651 const gchar
*contenttype
;
652 gboolean found
= FALSE
;
654 from
= parse_from(sipmsg_find_header(msg
, "From"));
658 SIPE_DEBUG_INFO("got message from %s: %s", from
, msg
->body
);
660 contenttype
= sipmsg_find_header(msg
, "Content-Type");
661 if (g_str_has_prefix(contenttype
, "text/plain")
662 || g_str_has_prefix(contenttype
, "text/html")
663 || g_str_has_prefix(contenttype
, "multipart/related")
664 || g_str_has_prefix(contenttype
, "multipart/alternative"))
666 const gchar
*callid
= sipmsg_find_header(msg
, "Call-ID");
667 gchar
*html
= get_html_message(contenttype
, msg
->body
);
669 struct sip_session
*session
= sipe_session_find_chat_or_im(sipe_private
,
672 if (session
&& session
->chat_session
) {
673 if (session
->chat_session
->type
== SIPE_CHAT_TYPE_CONFERENCE
) { /* a conference */
674 gchar
*tmp
= parse_from(sipmsg_find_header(msg
, "Ms-Sender"));
675 gchar
*sender
= parse_from(tmp
);
677 sipe_backend_chat_message(SIPE_CORE_PUBLIC
,
678 session
->chat_session
->backend
,
683 } else { /* a multiparty chat */
684 sipe_backend_chat_message(SIPE_CORE_PUBLIC
,
685 session
->chat_session
->backend
,
691 sipe_backend_im_message(SIPE_CORE_PUBLIC
,
696 sip_transport_response(sipe_private
, msg
, 200, "OK", NULL
);
699 } else if (g_str_has_prefix(contenttype
, "application/im-iscomposing+xml")) {
700 sipe_xml
*isc
= sipe_xml_parse(msg
->body
, msg
->bodylen
);
701 const sipe_xml
*state
;
705 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_message: can not parse iscomposing");
710 state
= sipe_xml_child(isc
, "state");
713 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_message: no state found");
719 statedata
= sipe_xml_data(state
);
721 if (strstr(statedata
, "active")) {
722 sipe_backend_user_feedback_typing(SIPE_CORE_PUBLIC
,
725 sipe_backend_user_feedback_typing_stop(SIPE_CORE_PUBLIC
,
731 sip_transport_response(sipe_private
, msg
, 200, "OK", NULL
);
733 } else if (g_str_has_prefix(contenttype
, "text/x-msmsgsinvite")) {
734 const gchar
*callid
= sipmsg_find_header(msg
, "Call-ID");
735 struct sip_session
*session
= sipe_session_find_chat_or_im(sipe_private
,
739 struct sip_dialog
*dialog
= sipe_dialog_find(session
, from
);
740 GSList
*body
= sipe_ft_parse_msg_body(msg
->body
);
741 found
= sipe_process_incoming_x_msmsgsinvite(sipe_private
, dialog
, body
);
742 sipe_utils_nameval_free(body
);
744 sip_transport_response(sipe_private
, msg
, 200, "OK", NULL
);
747 sip_transport_response(sipe_private
, msg
, 481,
748 "Call Leg/Transaction Does Not Exist", NULL
);
753 const gchar
*callid
= sipmsg_find_header(msg
, "Call-ID");
754 struct sip_session
*session
= sipe_session_find_chat_or_im(sipe_private
,
758 gchar
*errmsg
= g_strdup_printf(_("Received a message with unrecognized contents from %s"),
760 sipe_user_present_error(sipe_private
, session
, errmsg
);
764 SIPE_DEBUG_INFO("got unknown mime-type '%s'", contenttype
);
765 sip_transport_response(sipe_private
, msg
, 415, "Unsupported media type", NULL
);
770 void process_incoming_options(struct sipe_core_private
*sipe_private
,
775 sipmsg_add_header(msg
, "Allow", "INVITE, MESSAGE, INFO, SUBSCRIBE, OPTIONS, BYE, CANCEL, NOTIFY, ACK, REFER, BENOTIFY");
776 sipmsg_add_header(msg
, "Content-Type", "application/sdp");
778 body
= g_strdup_printf(
780 "o=- 0 0 IN IP4 0.0.0.0\r\n"
782 "c=IN IP4 0.0.0.0\r\n"
784 "m=%s %d sip sip:%s\r\n"
785 "a=accept-types:" SDP_ACCEPT_TYPES
"\r\n",
786 SIPE_CORE_PRIVATE_FLAG_IS(OCS2007
) ? "message" : "x-ms-message",
787 sip_transport_port(sipe_private
),
788 sipe_private
->username
);
789 sip_transport_response(sipe_private
, msg
, 200, "OK", body
);
793 void process_incoming_refer(struct sipe_core_private
*sipe_private
,
796 gchar
*self
= sip_uri_self(sipe_private
);
797 const gchar
*callid
= sipmsg_find_header(msg
, "Call-ID");
798 gchar
*from
= parse_from(sipmsg_find_header(msg
, "From"));
799 gchar
*refer_to
= parse_from(sipmsg_find_header(msg
, "Refer-to"));
800 gchar
*referred_by
= g_strdup(sipmsg_find_header(msg
, "Referred-By"));
801 struct sip_session
*session
;
802 struct sip_dialog
*dialog
;
804 session
= sipe_session_find_chat_by_callid(sipe_private
, callid
);
805 dialog
= sipe_dialog_find(session
, from
);
807 if (!session
|| !dialog
|| !session
->chat_session
||
808 (session
->chat_session
->type
!= SIPE_CHAT_TYPE_MULTIPARTY
) ||
809 !session
->chat_session
->id
||
810 !sipe_strcase_equal(session
->chat_session
->id
, self
)) {
811 sip_transport_response(sipe_private
, msg
, 500, "Server Internal Error", NULL
);
813 sip_transport_response(sipe_private
, msg
, 202, "Accepted", NULL
);
815 sipe_im_invite(sipe_private
, session
, refer_to
, NULL
, NULL
, referred_by
, FALSE
);