filetransfer: do not process incoming invite in "ms-text-format" header
[siplcs.git] / src / core / sipe-incoming.c
blob5d538bdcf809243ccd5f793c645a7f5fdc8d9a10
1 /**
2 * @file sipe-incoming.c
4 * pidgin-sipe
6 * Copyright (C) 2010-2011 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-groupchat.h"
44 #include "sipe-im.h"
45 #include "sipe-incoming.h"
46 #include "sipe-media.h"
47 #include "sipe-mime.h"
48 #include "sipe-nls.h"
49 #include "sipe-schedule.h"
50 #include "sipe-session.h"
51 #include "sipe-user.h"
52 #include "sipe-utils.h"
53 #include "sipe-xml.h"
55 void process_incoming_bye(struct sipe_core_private *sipe_private,
56 struct sipmsg *msg)
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;
63 #ifdef HAVE_VV
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);
68 #endif
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);
83 if (!session) {
84 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_bye: couldn't find session. Ignoring");
85 sipe_dialog_free(dialog);
86 g_free(from);
87 return;
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_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_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,
114 from);
118 g_free(from);
121 void process_incoming_cancel(struct sipe_core_private *sipe_private,
122 struct sipmsg *msg)
124 const gchar *callid;
126 #ifdef HAVE_VV
127 if (is_media_session_msg(sipe_private->media_call, msg)) {
128 process_incoming_cancel_call(sipe_private, msg);
129 return;
131 #endif
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,
139 struct sipmsg *msg)
141 const gchar *contenttype = sipmsg_find_header(msg, "Content-Type");
142 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
143 gchar *from;
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);
152 return;
154 else if (g_str_has_prefix(contenttype, "application/xml+conversationinfo"))
156 process_incoming_info_conversation(sipe_private, msg);
157 return;
160 from = parse_from(sipmsg_find_header(msg, "From"));
161 session = sipe_session_find_chat_or_im(sipe_private, callid, from);
162 if (!session) {
163 g_free(from);
164 return;
167 /* Group Chat uses text/plain */
168 if (session->is_groupchat) {
169 process_incoming_info_groupchat(sipe_private, msg, session);
170 g_free(from);
171 return;
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");
182 if (xn_request_rm) {
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);
192 g_free(body);
193 } else if (xn_set_rm) {
194 gchar *body;
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);
205 g_free(body);
207 sipe_xml_free(xn_action);
210 else
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"),
216 "status");
217 if (sipe_strequal(status, "type")) {
218 sipe_backend_user_feedback_typing(SIPE_CORE_PUBLIC,
219 from);
220 } else if (sipe_strequal(status, "idle")) {
221 sipe_backend_user_feedback_typing_stop(SIPE_CORE_PUBLIC,
222 from);
224 sipe_xml_free(xn_keyboard_activity);
227 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
229 g_free(from);
232 static gboolean sipe_process_incoming_x_msmsgsinvite(struct sipe_core_private *sipe_private,
233 struct sip_dialog *dialog,
234 GSList *parsed_body)
236 gboolean found = FALSE;
238 if (parsed_body) {
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);
243 found = TRUE;
244 } else if (sipe_strequal(invitation_command, "CANCEL")) {
245 sipe_ft_incoming_cancel(dialog, parsed_body);
246 found = TRUE;
247 } else if (sipe_strequal(invitation_command, "ACCEPT")) {
248 sipe_ft_incoming_accept(dialog, parsed_body);
249 found = TRUE;
252 return found;
255 #ifdef HAVE_VV
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"))
263 return;
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 */
272 return;
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. */
280 g_free(msg->body);
281 msg->body = g_strndup(body, length);
282 msg->bodylen = length;
285 #endif
287 static void send_invite_response(struct sipe_core_private *sipe_private,
288 struct sipmsg *msg)
290 gchar *body = g_strdup_printf(
291 "v=0\r\n"
292 "o=- 0 0 IN IP4 %s\r\n"
293 "s=session\r\n"
294 "c=IN IP4 %s\r\n"
295 "t=0 0\r\n"
296 "m=%s %d sip sip:%s\r\n"
297 "a=accept-types:" SDP_ACCEPT_TYPES "\r\n",
298 sipe_backend_network_ip_address(),
299 sipe_backend_network_ip_address(),
300 SIPE_CORE_PRIVATE_FLAG_IS(OCS2007) ? "message" : "x-ms-message",
301 sip_transport_port(sipe_private),
302 sipe_private->username);
303 sipmsg_add_header(msg, "Content-Type", "application/sdp");
304 sip_transport_response(sipe_private, msg, 200, "OK", body);
305 g_free(body);
308 struct sipe_delayed_invite {
309 gchar *action;
310 struct sipmsg *msg;
313 static void delayed_invite_destroy(gpointer data)
315 struct sipe_delayed_invite *delayed_invite = data;
316 sipmsg_free(delayed_invite->msg);
317 g_free(delayed_invite->action);
318 g_free(delayed_invite);
321 static void delayed_invite_timeout(struct sipe_core_private *sipe_private,
322 gpointer data)
324 struct sipe_delayed_invite *delayed_invite = data;
325 send_invite_response(sipe_private, delayed_invite->msg);
328 static void delayed_invite_response(struct sipe_core_private *sipe_private,
329 struct sipmsg *msg,
330 const gchar *callid)
332 struct sipe_delayed_invite *delayed_invite = g_new0(struct sipe_delayed_invite, 1);
334 delayed_invite->action = g_strdup_printf("<delayed-invite-%s>", callid);
335 delayed_invite->msg = sipmsg_copy(msg);
336 sipe_schedule_seconds(sipe_private,
337 delayed_invite->action,
338 delayed_invite,
340 delayed_invite_timeout,
341 delayed_invite_destroy);
344 void sipe_incoming_cancel_delayed_invite(struct sipe_core_private *sipe_private,
345 struct sip_dialog *dialog)
347 struct sipe_delayed_invite *delayed_invite = dialog->delayed_invite;
348 dialog->delayed_invite = NULL;
349 send_invite_response(sipe_private, delayed_invite->msg);
350 sipe_schedule_cancel(sipe_private, delayed_invite->action);
353 void process_incoming_invite(struct sipe_core_private *sipe_private,
354 struct sipmsg *msg)
356 gchar *newTag;
357 const gchar *oldHeader;
358 gchar *newHeader;
359 gboolean is_multiparty = FALSE;
360 gboolean was_multiparty = TRUE;
361 gboolean just_joined = FALSE;
362 gchar *from;
363 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
364 const gchar *roster_manager = sipmsg_find_header(msg, "Roster-Manager");
365 const gchar *end_points_hdr = sipmsg_find_header(msg, "EndPoints");
366 const gchar *trig_invite = sipmsg_find_header(msg, "TriggeredInvite");
367 const gchar *content_type = sipmsg_find_header(msg, "Content-Type");
368 const gchar *subject = sipmsg_find_header(msg, "Subject");
369 GSList *end_points = NULL;
370 struct sip_session *session;
371 struct sip_dialog *dialog;
372 const gchar *ms_text_format;
373 gboolean dont_delay = FALSE;
375 #ifdef HAVE_VV
376 if (g_str_has_prefix(content_type, "multipart/alternative")) {
377 sipe_mime_parts_foreach(content_type, msg->body, sipe_invite_mime_cb, msg);
378 /* Reload Content-Type to get type of the selected message part */
379 content_type = sipmsg_find_header(msg, "Content-Type");
381 #endif
383 /* Invitation to join conference */
384 if (g_str_has_prefix(content_type, "application/ms-conf-invite+xml")) {
385 process_incoming_invite_conf(sipe_private, msg);
386 return;
389 #ifdef HAVE_VV
390 /* Invitation to audio call */
391 if (msg->body && strstr(msg->body, "m=audio")) {
392 process_incoming_invite_call(sipe_private, msg);
393 return;
395 #endif
397 /* Only accept text invitations */
398 if (msg->body && !(strstr(msg->body, "m=message") || strstr(msg->body, "m=x-ms-message"))) {
399 sip_transport_response(sipe_private, msg, 501, "Not implemented", NULL);
400 return;
403 // TODO There *must* be a better way to clean up the To header to add a tag...
404 SIPE_DEBUG_INFO_NOFORMAT("Adding a Tag to the To Header on Invite Request...");
405 oldHeader = sipmsg_find_header(msg, "To");
406 newTag = gentag();
407 newHeader = g_strdup_printf("%s;tag=%s", oldHeader, newTag);
408 g_free(newTag);
409 sipmsg_remove_header_now(msg, "To");
410 sipmsg_add_header_now(msg, "To", newHeader);
411 g_free(newHeader);
413 if (end_points_hdr) {
414 end_points = sipmsg_parse_endpoints_header(end_points_hdr);
416 if (g_slist_length(end_points) > 2) {
417 is_multiparty = TRUE;
420 if (trig_invite && !g_strcasecmp(trig_invite, "TRUE")) {
421 is_multiparty = TRUE;
424 /* Multiparty session */
425 session = sipe_session_find_chat_by_callid(sipe_private, callid);
426 if (is_multiparty) {
428 if (session) {
429 if (session->chat_session) {
430 /* Update roster manager for existing multiparty session */
431 if (roster_manager)
432 sipe_chat_set_roster_manager(session, roster_manager);
434 } else {
435 gchar *chat_title = sipe_chat_get_name();
437 /* Convert IM session to multiparty session */
438 g_free(session->with);
439 session->with = NULL;
440 was_multiparty = FALSE;
441 session->chat_session = sipe_chat_create_session(SIPE_CHAT_TYPE_MULTIPARTY,
442 roster_manager,
443 chat_title);
445 g_free(chat_title);
447 } else {
448 /* New multiparty session */
449 session = sipe_session_add_chat(sipe_private,
450 NULL,
451 TRUE,
452 roster_manager);
455 /* Create chat */
456 if (!session->chat_session->backend) {
457 gchar *self = sip_uri_self(sipe_private);
458 session->chat_session->backend = sipe_backend_chat_create(SIPE_CORE_PUBLIC,
459 session->chat_session,
460 session->chat_session->title,
461 self);
462 g_free(self);
466 /* IM session */
467 from = parse_from(sipmsg_find_header(msg, "From"));
468 if (!session)
469 session = sipe_session_find_or_add_im(sipe_private, from);
471 /* session is now initialized */
472 g_free(session->callid);
473 session->callid = g_strdup(callid);
475 if (is_multiparty && end_points) {
476 gchar *to = parse_from(sipmsg_find_header(msg, "To"));
477 GSList *entry = end_points;
478 while (entry) {
479 struct sipendpoint *end_point = entry->data;
480 entry = entry->next;
482 if (!g_strcasecmp(from, end_point->contact) ||
483 !g_strcasecmp(to, end_point->contact))
484 continue;
486 dialog = sipe_dialog_find(session, end_point->contact);
487 if (dialog) {
488 g_free(dialog->theirepid);
489 dialog->theirepid = end_point->epid;
490 end_point->epid = NULL;
491 } else {
492 dialog = sipe_dialog_add(session);
494 dialog->callid = g_strdup(session->callid);
495 dialog->with = end_point->contact;
496 end_point->contact = NULL;
497 dialog->theirepid = end_point->epid;
498 end_point->epid = NULL;
500 just_joined = TRUE;
502 /* send triggered INVITE */
503 sipe_im_invite(sipe_private, session, dialog->with, NULL, NULL, NULL, TRUE);
506 g_free(to);
509 if (end_points) {
510 GSList *entry = end_points;
511 while (entry) {
512 struct sipendpoint *end_point = entry->data;
513 entry = entry->next;
514 g_free(end_point->contact);
515 g_free(end_point->epid);
516 g_free(end_point);
518 g_slist_free(end_points);
521 dialog = sipe_dialog_find(session, from);
522 if (dialog) {
523 sipe_im_cancel_dangling(sipe_private, session, dialog, from,
524 sipe_im_reenqueue_unconfirmed);
525 /* dialog is no longer valid */
526 } else {
527 just_joined = TRUE;
530 dialog = sipe_dialog_add(session);
531 dialog->with = g_strdup(from);
532 dialog->callid = g_strdup(session->callid);
533 sipe_dialog_parse(dialog, msg, FALSE);
535 if (is_multiparty && !was_multiparty) {
536 /* add current IM counterparty to chat */
537 sipe_backend_chat_add(session->chat_session->backend,
538 sipe_dialog_first(session)->with,
539 FALSE);
542 /* add inviting party to chat */
543 if (just_joined && session->chat_session) {
544 sipe_backend_chat_add(session->chat_session->backend,
545 from,
546 TRUE);
549 if (!is_multiparty && subject)
550 sipe_im_topic(sipe_private, session, subject);
552 /* ms-text-format: text/plain; charset=UTF-8;msgr=WAAtAE0...DIADQAKAA0ACgA;ms-body=SGk= */
554 /* This used only in 2005 official client, not 2007 or Reuters.
555 Disabled for most cases as interfering with audit of messages which only is applied to regular MESSAGEs.
556 Only enabled for 2005 multiparty chats as otherwise the first message got lost completely.
558 /* also enabled for 2005 file transfer. Didn't work otherwise. */
559 ms_text_format = sipmsg_find_header(msg, "ms-text-format");
560 if (is_multiparty ||
561 (ms_text_format && g_str_has_prefix(ms_text_format, "text/x-msmsgsinvite")) )
563 if (ms_text_format) {
564 if (g_str_has_prefix(ms_text_format, "text/x-msmsgsinvite"))
566 dont_delay = TRUE;
568 else if (g_str_has_prefix(ms_text_format, "text/plain") || g_str_has_prefix(ms_text_format, "text/html"))
570 /* please do not optimize logic inside as this code may be re-enabled for other cases */
571 gchar *html = get_html_message(ms_text_format, NULL);
572 if (html) {
573 if (is_multiparty) {
574 sipe_backend_chat_message(SIPE_CORE_PUBLIC,
575 session->chat_session->backend,
576 from,
577 html);
578 } else {
579 sipe_backend_im_message(SIPE_CORE_PUBLIC,
580 from,
581 html);
583 g_free(html);
584 sipmsg_add_header(msg, "Supported", "ms-text-format"); /* accepts received message */
585 dont_delay = TRUE;
591 g_free(from);
593 sipmsg_add_header(msg, "Supported", "com.microsoft.rtc-multiparty");
595 if (dont_delay || !SIPE_CORE_PRIVATE_FLAG_IS(MPOP)) {
596 send_invite_response(sipe_private, msg);
597 } else {
598 delayed_invite_response(sipe_private, msg, session->callid);
602 void process_incoming_message(struct sipe_core_private *sipe_private,
603 struct sipmsg *msg)
605 gchar *from;
606 const gchar *contenttype;
607 gboolean found = FALSE;
609 from = parse_from(sipmsg_find_header(msg, "From"));
611 if (!from) return;
613 SIPE_DEBUG_INFO("got message from %s: %s", from, msg->body);
615 contenttype = sipmsg_find_header(msg, "Content-Type");
616 if (g_str_has_prefix(contenttype, "text/plain")
617 || g_str_has_prefix(contenttype, "text/html")
618 || g_str_has_prefix(contenttype, "multipart/related")
619 || g_str_has_prefix(contenttype, "multipart/alternative"))
621 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
622 gchar *html = get_html_message(contenttype, msg->body);
624 struct sip_session *session = sipe_session_find_chat_or_im(sipe_private,
625 callid,
626 from);
627 if (session && session->chat_session) {
628 if (session->chat_session->type == SIPE_CHAT_TYPE_CONFERENCE) { /* a conference */
629 gchar *tmp = parse_from(sipmsg_find_header(msg, "Ms-Sender"));
630 gchar *sender = parse_from(tmp);
631 g_free(tmp);
632 sipe_backend_chat_message(SIPE_CORE_PUBLIC,
633 session->chat_session->backend,
634 sender,
635 html);
636 g_free(sender);
637 } else { /* a multiparty chat */
638 sipe_backend_chat_message(SIPE_CORE_PUBLIC,
639 session->chat_session->backend,
640 from,
641 html);
643 } else {
644 sipe_backend_im_message(SIPE_CORE_PUBLIC,
645 from,
646 html);
648 g_free(html);
649 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
650 found = TRUE;
652 } else if (g_str_has_prefix(contenttype, "application/im-iscomposing+xml")) {
653 sipe_xml *isc = sipe_xml_parse(msg->body, msg->bodylen);
654 const sipe_xml *state;
655 gchar *statedata;
657 if (!isc) {
658 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_message: can not parse iscomposing");
659 g_free(from);
660 return;
663 state = sipe_xml_child(isc, "state");
665 if (!state) {
666 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_message: no state found");
667 sipe_xml_free(isc);
668 g_free(from);
669 return;
672 statedata = sipe_xml_data(state);
673 if (statedata) {
674 if (strstr(statedata, "active")) {
675 sipe_backend_user_feedback_typing(SIPE_CORE_PUBLIC,
676 from);
677 } else {
678 sipe_backend_user_feedback_typing_stop(SIPE_CORE_PUBLIC,
679 from);
681 g_free(statedata);
683 sipe_xml_free(isc);
684 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
685 found = TRUE;
686 } else if (g_str_has_prefix(contenttype, "text/x-msmsgsinvite")) {
687 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
688 struct sip_session *session = sipe_session_find_chat_or_im(sipe_private,
689 callid,
690 from);
691 struct sip_dialog *dialog = sipe_dialog_find(session, from);
692 GSList *body = sipe_ft_parse_msg_body(msg->body);
693 found = sipe_process_incoming_x_msmsgsinvite(sipe_private, dialog, body);
694 sipe_utils_nameval_free(body);
695 if (found) {
696 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
699 if (!found) {
700 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
701 struct sip_session *session = sipe_session_find_chat_or_im(sipe_private,
702 callid,
703 from);
704 if (session) {
705 gchar *errmsg = g_strdup_printf(_("Received a message with unrecognized contents from %s"),
706 from);
707 sipe_user_present_error(sipe_private, session, errmsg);
708 g_free(errmsg);
711 SIPE_DEBUG_INFO("got unknown mime-type '%s'", contenttype);
712 sip_transport_response(sipe_private, msg, 415, "Unsupported media type", NULL);
714 g_free(from);
717 void process_incoming_options(struct sipe_core_private *sipe_private,
718 struct sipmsg *msg)
720 gchar *body;
722 sipmsg_add_header(msg, "Allow", "INVITE, MESSAGE, INFO, SUBSCRIBE, OPTIONS, BYE, CANCEL, NOTIFY, ACK, REFER, BENOTIFY");
723 sipmsg_add_header(msg, "Content-Type", "application/sdp");
725 body = g_strdup_printf(
726 "v=0\r\n"
727 "o=- 0 0 IN IP4 0.0.0.0\r\n"
728 "s=session\r\n"
729 "c=IN IP4 0.0.0.0\r\n"
730 "t=0 0\r\n"
731 "m=%s %d sip sip:%s\r\n"
732 "a=accept-types:" SDP_ACCEPT_TYPES "\r\n",
733 SIPE_CORE_PRIVATE_FLAG_IS(OCS2007) ? "message" : "x-ms-message",
734 sip_transport_port(sipe_private),
735 sipe_private->username);
736 sip_transport_response(sipe_private, msg, 200, "OK", body);
737 g_free(body);
740 void process_incoming_refer(struct sipe_core_private *sipe_private,
741 struct sipmsg *msg)
743 gchar *self = sip_uri_self(sipe_private);
744 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
745 gchar *from = parse_from(sipmsg_find_header(msg, "From"));
746 gchar *refer_to = parse_from(sipmsg_find_header(msg, "Refer-to"));
747 gchar *referred_by = g_strdup(sipmsg_find_header(msg, "Referred-By"));
748 struct sip_session *session;
749 struct sip_dialog *dialog;
751 session = sipe_session_find_chat_by_callid(sipe_private, callid);
752 dialog = sipe_dialog_find(session, from);
754 if (!session || !dialog || !session->chat_session ||
755 (session->chat_session->type != SIPE_CHAT_TYPE_MULTIPARTY) ||
756 !session->chat_session->id ||
757 !sipe_strcase_equal(session->chat_session->id, self)) {
758 sip_transport_response(sipe_private, msg, 500, "Server Internal Error", NULL);
759 } else {
760 sip_transport_response(sipe_private, msg, 202, "Accepted", NULL);
762 sipe_im_invite(sipe_private, session, refer_to, NULL, NULL, referred_by, FALSE);
765 g_free(self);
766 g_free(from);
767 g_free(refer_to);
768 g_free(referred_by);
772 Local Variables:
773 mode: c
774 c-file-style: "bsd"
775 indent-tabs-mode: t
776 tab-width: 8
777 End: