Updated media patches README
[siplcs.git] / src / core / sipe-incoming.c
blob5697b744025fdc3b86d2390593b4c16068b03a61
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-session.h"
50 #include "sipe-user.h"
51 #include "sipe-utils.h"
52 #include "sipe-xml.h"
54 void process_incoming_bye(struct sipe_core_private *sipe_private,
55 struct sipmsg *msg)
57 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
58 gchar *from = parse_from(sipmsg_find_header(msg, "From"));
59 struct sip_session *session;
60 struct sip_dialog *dialog;
62 #ifdef HAVE_VV
63 if (is_media_session_msg(sipe_private->media_call, msg)) {
64 // BYE ends a media call
65 sipe_media_hangup(sipe_private->media_call);
67 #endif
69 /* collect dialog identification
70 * we need callid, ourtag and theirtag to unambiguously identify dialog
72 /* take data before 'msg' will be modified by sip_transport_response */
73 dialog = g_new0(struct sip_dialog, 1);
74 dialog->callid = g_strdup(callid);
75 dialog->cseq = sipmsg_parse_cseq(msg);
76 dialog->with = g_strdup(from);
77 sipe_dialog_parse(dialog, msg, FALSE);
79 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
81 session = sipe_session_find_chat_or_im(sipe_private, callid, from);
82 if (!session) {
83 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_bye: couldn't find session. Ignoring");
84 sipe_dialog_free(dialog);
85 g_free(from);
86 return;
89 SIPE_DEBUG_INFO("process_incoming_bye: session found (chat ID %s)",
90 (session->chat_session && session->chat_session->id) ?
91 session->chat_session->id : "<NO CHAT>");
93 if (session->chat_session &&
94 (session->chat_session->type == SIPE_CHAT_TYPE_MULTIPARTY) &&
95 session->chat_session->id &&
96 !g_strcasecmp(from, session->chat_session->id))
97 sipe_chat_set_roster_manager(session, NULL);
99 sipe_im_cancel_unconfirmed(sipe_private, session, callid, from);
101 /* This what BYE is essentially for - terminating dialog */
102 sipe_dialog_remove_3(session, dialog);
103 sipe_dialog_free(dialog);
104 if (session->chat_session) {
105 if ((session->chat_session->type == SIPE_CHAT_TYPE_CONFERENCE) &&
106 !g_strcasecmp(from, session->im_mcu_uri)) {
107 SIPE_DEBUG_INFO("process_incoming_bye: disconnected from conference %s",
108 session->im_mcu_uri);
109 sipe_conf_immcu_closed(sipe_private, session);
110 } else if (session->chat_session->type == SIPE_CHAT_TYPE_MULTIPARTY) {
111 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_bye: disconnected from multiparty chat");
112 sipe_backend_chat_remove(session->chat_session->backend,
113 from);
117 g_free(from);
120 void process_incoming_cancel(SIPE_UNUSED_PARAMETER struct sipe_core_private *sipe_private,
121 SIPE_UNUSED_PARAMETER struct sipmsg *msg)
123 #ifdef HAVE_VV
124 if (is_media_session_msg(sipe_private->media_call, msg)) {
125 process_incoming_cancel_call(sipe_private, msg);
127 #endif
130 void process_incoming_info(struct sipe_core_private *sipe_private,
131 struct sipmsg *msg)
133 const gchar *contenttype = sipmsg_find_header(msg, "Content-Type");
134 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
135 gchar *from;
136 struct sip_session *session;
138 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_info");
140 /* Call Control protocol */
141 if (g_str_has_prefix(contenttype, "application/csta+xml"))
143 process_incoming_info_csta(sipe_private, msg);
144 return;
146 else if (g_str_has_prefix(contenttype, "application/xml+conversationinfo"))
148 process_incoming_info_conversation(sipe_private, msg);
149 return;
152 from = parse_from(sipmsg_find_header(msg, "From"));
153 session = sipe_session_find_chat_or_im(sipe_private, callid, from);
154 if (!session) {
155 g_free(from);
156 return;
159 /* Group Chat uses text/plain */
160 if (session->is_groupchat) {
161 process_incoming_info_groupchat(sipe_private, msg, session);
162 g_free(from);
163 return;
166 if (g_str_has_prefix(contenttype, "application/x-ms-mim"))
168 sipe_xml *xn_action = sipe_xml_parse(msg->body, msg->bodylen);
169 const sipe_xml *xn_request_rm = sipe_xml_child(xn_action, "RequestRM");
170 const sipe_xml *xn_set_rm = sipe_xml_child(xn_action, "SetRM");
172 sipmsg_add_header(msg, "Content-Type", "application/x-ms-mim");
174 if (xn_request_rm) {
175 //const char *rm = sipe_xml_attribute(xn_request_rm, "uri");
176 int bid = sipe_xml_int_attribute(xn_request_rm, "bid", 0);
177 gchar *body = g_strdup_printf(
178 "<?xml version=\"1.0\"?>\r\n"
179 "<action xmlns=\"http://schemas.microsoft.com/sip/multiparty/\">"
180 "<RequestRMResponse uri=\"sip:%s\" allow=\"%s\"/></action>\r\n",
181 sipe_private->username,
182 session->bid < bid ? "true" : "false");
183 sip_transport_response(sipe_private, msg, 200, "OK", body);
184 g_free(body);
185 } else if (xn_set_rm) {
186 gchar *body;
188 sipe_chat_set_roster_manager(session,
189 sipe_xml_attribute(xn_set_rm, "uri"));
191 body = g_strdup_printf(
192 "<?xml version=\"1.0\"?>\r\n"
193 "<action xmlns=\"http://schemas.microsoft.com/sip/multiparty/\">"
194 "<SetRMResponse uri=\"sip:%s\"/></action>\r\n",
195 sipe_private->username);
196 sip_transport_response(sipe_private, msg, 200, "OK", body);
197 g_free(body);
199 sipe_xml_free(xn_action);
202 else
204 /* looks like purple lacks typing notification for chat */
205 if (!session->chat_session) {
206 sipe_xml *xn_keyboard_activity = sipe_xml_parse(msg->body, msg->bodylen);
207 const char *status = sipe_xml_attribute(sipe_xml_child(xn_keyboard_activity, "status"),
208 "status");
209 if (sipe_strequal(status, "type")) {
210 sipe_backend_user_feedback_typing(SIPE_CORE_PUBLIC,
211 from);
212 } else if (sipe_strequal(status, "idle")) {
213 sipe_backend_user_feedback_typing_stop(SIPE_CORE_PUBLIC,
214 from);
216 sipe_xml_free(xn_keyboard_activity);
219 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
221 g_free(from);
224 static gboolean sipe_process_incoming_x_msmsgsinvite(struct sipe_core_private *sipe_private,
225 struct sip_dialog *dialog,
226 GSList *parsed_body)
228 gboolean found = FALSE;
230 if (parsed_body) {
231 const gchar *invitation_command = sipe_utils_nameval_find(parsed_body, "Invitation-Command");
233 if (sipe_strequal(invitation_command, "INVITE")) {
234 sipe_ft_incoming_transfer(sipe_private, dialog, parsed_body);
235 found = TRUE;
236 } else if (sipe_strequal(invitation_command, "CANCEL")) {
237 sipe_ft_incoming_cancel(dialog, parsed_body);
238 found = TRUE;
239 } else if (sipe_strequal(invitation_command, "ACCEPT")) {
240 sipe_ft_incoming_accept(dialog, parsed_body);
241 found = TRUE;
244 return found;
247 #ifdef HAVE_VV
248 static void sipe_invite_mime_cb(gpointer user_data, const GSList *fields,
249 const gchar *body, gsize length)
251 const gchar *type = sipe_utils_nameval_find(fields, "Content-Type");
252 const gchar *cd = sipe_utils_nameval_find(fields, "Content-Disposition");
254 if (!g_str_has_prefix(type, "application/sdp"))
255 return;
257 if (cd && !strstr(cd, "ms-proxy-2007fallback")) {
258 struct sipmsg *msg = user_data;
259 const gchar* msg_ct = sipmsg_find_header(msg, "Content-Type");
261 if (g_str_has_prefix(msg_ct, "application/sdp")) {
262 /* We have already found suitable alternative and set message's body
263 * and Content-Type accordingly */
264 return;
267 sipmsg_remove_header_now(msg, "Content-Type");
268 sipmsg_add_header_now(msg, "Content-Type", type);
270 /* Replace message body with chosen alternative, so we can continue to
271 * process it as a normal single part message. */
272 g_free(msg->body);
273 msg->body = g_strndup(body, length);
274 msg->bodylen = length;
277 #endif
279 void process_incoming_invite(struct sipe_core_private *sipe_private,
280 struct sipmsg *msg)
282 gchar *body;
283 gchar *newTag;
284 const gchar *oldHeader;
285 gchar *newHeader;
286 gboolean is_multiparty = FALSE;
287 gboolean was_multiparty = TRUE;
288 gboolean just_joined = FALSE;
289 gchar *from;
290 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
291 const gchar *roster_manager = sipmsg_find_header(msg, "Roster-Manager");
292 const gchar *end_points_hdr = sipmsg_find_header(msg, "EndPoints");
293 const gchar *trig_invite = sipmsg_find_header(msg, "TriggeredInvite");
294 const gchar *content_type = sipmsg_find_header(msg, "Content-Type");
295 const gchar *subject = sipmsg_find_header(msg, "Subject");
296 GSList *end_points = NULL;
297 struct sip_session *session;
298 struct sip_dialog *dialog;
299 const gchar *ms_text_format;
301 #ifdef HAVE_VV
302 if (g_str_has_prefix(content_type, "multipart/alternative")) {
303 sipe_mime_parts_foreach(content_type, msg->body, sipe_invite_mime_cb, msg);
304 /* Reload Content-Type to get type of the selected message part */
305 content_type = sipmsg_find_header(msg, "Content-Type");
307 #endif
309 /* Invitation to join conference */
310 if (g_str_has_prefix(content_type, "application/ms-conf-invite+xml")) {
311 process_incoming_invite_conf(sipe_private, msg);
312 return;
315 #ifdef HAVE_VV
316 /* Invitation to audio call */
317 if (msg->body && strstr(msg->body, "m=audio")) {
318 process_incoming_invite_call(sipe_private, msg);
319 return;
321 #endif
323 /* Only accept text invitations */
324 if (msg->body && !(strstr(msg->body, "m=message") || strstr(msg->body, "m=x-ms-message"))) {
325 sip_transport_response(sipe_private, msg, 501, "Not implemented", NULL);
326 return;
329 // TODO There *must* be a better way to clean up the To header to add a tag...
330 SIPE_DEBUG_INFO_NOFORMAT("Adding a Tag to the To Header on Invite Request...");
331 oldHeader = sipmsg_find_header(msg, "To");
332 newTag = gentag();
333 newHeader = g_strdup_printf("%s;tag=%s", oldHeader, newTag);
334 g_free(newTag);
335 sipmsg_remove_header_now(msg, "To");
336 sipmsg_add_header_now(msg, "To", newHeader);
337 g_free(newHeader);
339 if (end_points_hdr) {
340 end_points = sipmsg_parse_endpoints_header(end_points_hdr);
342 if (g_slist_length(end_points) > 2) {
343 is_multiparty = TRUE;
346 if (trig_invite && !g_strcasecmp(trig_invite, "TRUE")) {
347 is_multiparty = TRUE;
350 /* Multiparty session */
351 session = sipe_session_find_chat_by_callid(sipe_private, callid);
352 if (is_multiparty) {
354 if (session) {
355 if (session->chat_session) {
356 /* Update roster manager for existing multiparty session */
357 if (roster_manager)
358 sipe_chat_set_roster_manager(session, roster_manager);
360 } else {
361 gchar *chat_title = sipe_chat_get_name();
363 /* Convert IM session to multiparty session */
364 g_free(session->with);
365 session->with = NULL;
366 was_multiparty = FALSE;
367 session->chat_session = sipe_chat_create_session(SIPE_CHAT_TYPE_MULTIPARTY,
368 roster_manager,
369 chat_title);
371 g_free(chat_title);
373 } else {
374 /* New multiparty session */
375 session = sipe_session_add_chat(sipe_private,
376 NULL,
377 TRUE,
378 roster_manager);
381 /* Create chat */
382 if (!session->chat_session->backend) {
383 gchar *self = sip_uri_self(sipe_private);
384 session->chat_session->backend = sipe_backend_chat_create(SIPE_CORE_PUBLIC,
385 session->chat_session,
386 session->chat_session->title,
387 self);
388 g_free(self);
392 /* IM session */
393 from = parse_from(sipmsg_find_header(msg, "From"));
394 if (!session)
395 session = sipe_session_find_or_add_im(sipe_private, from);
397 /* session is now initialized */
398 g_free(session->callid);
399 session->callid = g_strdup(callid);
401 if (is_multiparty && end_points) {
402 gchar *to = parse_from(sipmsg_find_header(msg, "To"));
403 GSList *entry = end_points;
404 while (entry) {
405 struct sipendpoint *end_point = entry->data;
406 entry = entry->next;
408 if (!g_strcasecmp(from, end_point->contact) ||
409 !g_strcasecmp(to, end_point->contact))
410 continue;
412 dialog = sipe_dialog_find(session, end_point->contact);
413 if (dialog) {
414 g_free(dialog->theirepid);
415 dialog->theirepid = end_point->epid;
416 end_point->epid = NULL;
417 } else {
418 dialog = sipe_dialog_add(session);
420 dialog->callid = g_strdup(session->callid);
421 dialog->with = end_point->contact;
422 end_point->contact = NULL;
423 dialog->theirepid = end_point->epid;
424 end_point->epid = NULL;
426 just_joined = TRUE;
428 /* send triggered INVITE */
429 sipe_im_invite(sipe_private, session, dialog->with, NULL, NULL, NULL, TRUE);
432 g_free(to);
435 if (end_points) {
436 GSList *entry = end_points;
437 while (entry) {
438 struct sipendpoint *end_point = entry->data;
439 entry = entry->next;
440 g_free(end_point->contact);
441 g_free(end_point->epid);
442 g_free(end_point);
444 g_slist_free(end_points);
447 dialog = sipe_dialog_find(session, from);
448 if (dialog) {
449 sipe_im_cancel_dangling(sipe_private, session, dialog, from,
450 sipe_im_reenqueue_unconfirmed);
451 /* dialog is no longer valid */
452 } else {
453 just_joined = TRUE;
456 dialog = sipe_dialog_add(session);
457 dialog->with = g_strdup(from);
458 dialog->callid = g_strdup(session->callid);
459 sipe_dialog_parse(dialog, msg, FALSE);
461 if (is_multiparty && !was_multiparty) {
462 /* add current IM counterparty to chat */
463 sipe_backend_chat_add(session->chat_session->backend,
464 sipe_dialog_first(session)->with,
465 FALSE);
468 /* add inviting party to chat */
469 if (just_joined && session->chat_session) {
470 sipe_backend_chat_add(session->chat_session->backend,
471 from,
472 TRUE);
475 if (!is_multiparty && subject)
476 sipe_im_topic(sipe_private, session, subject);
478 /* ms-text-format: text/plain; charset=UTF-8;msgr=WAAtAE0...DIADQAKAA0ACgA;ms-body=SGk= */
480 /* This used only in 2005 official client, not 2007 or Reuters.
481 Disabled for most cases as interfering with audit of messages which only is applied to regular MESSAGEs.
482 Only enabled for 2005 multiparty chats as otherwise the first message got lost completely.
484 /* also enabled for 2005 file transfer. Didn't work otherwise. */
485 ms_text_format = sipmsg_find_header(msg, "ms-text-format");
486 if (is_multiparty ||
487 (ms_text_format && g_str_has_prefix(ms_text_format, "text/x-msmsgsinvite")) )
489 if (ms_text_format) {
490 if (g_str_has_prefix(ms_text_format, "text/x-msmsgsinvite"))
492 gchar *tmp = sipmsg_find_part_of_header(ms_text_format, "ms-body=", NULL, NULL);
493 if (tmp) {
494 gsize len;
495 gchar *body = (gchar *) g_base64_decode(tmp, &len);
496 GSList *parsed_body = sipe_ft_parse_msg_body(body);
498 dialog = sipe_dialog_find(session, from);
499 sipe_process_incoming_x_msmsgsinvite(sipe_private, dialog, parsed_body);
500 sipe_utils_nameval_free(parsed_body);
501 sipmsg_add_header(msg, "Supported", "ms-text-format"); /* accepts received message */
503 g_free(tmp);
505 else if (g_str_has_prefix(ms_text_format, "text/plain") || g_str_has_prefix(ms_text_format, "text/html"))
507 /* please do not optimize logic inside as this code may be re-enabled for other cases */
508 gchar *html = get_html_message(ms_text_format, NULL);
509 if (html) {
510 if (is_multiparty) {
511 sipe_backend_chat_message(SIPE_CORE_PUBLIC,
512 session->chat_session->backend,
513 from,
514 html);
515 } else {
516 sipe_backend_im_message(SIPE_CORE_PUBLIC,
517 from,
518 html);
520 g_free(html);
521 sipmsg_add_header(msg, "Supported", "ms-text-format"); /* accepts received message */
527 g_free(from);
529 sipmsg_add_header(msg, "Supported", "com.microsoft.rtc-multiparty");
530 sipmsg_add_header(msg, "Content-Type", "application/sdp");
532 body = g_strdup_printf(
533 "v=0\r\n"
534 "o=- 0 0 IN IP4 %s\r\n"
535 "s=session\r\n"
536 "c=IN IP4 %s\r\n"
537 "t=0 0\r\n"
538 "m=%s %d sip sip:%s\r\n"
539 "a=accept-types:" SDP_ACCEPT_TYPES "\r\n",
540 sipe_backend_network_ip_address(),
541 sipe_backend_network_ip_address(),
542 SIPE_CORE_PRIVATE_FLAG_IS(OCS2007) ? "message" : "x-ms-message",
543 sip_transport_port(sipe_private),
544 sipe_private->username);
545 sip_transport_response(sipe_private, msg, 200, "OK", body);
546 g_free(body);
549 void process_incoming_message(struct sipe_core_private *sipe_private,
550 struct sipmsg *msg)
552 gchar *from;
553 const gchar *contenttype;
554 gboolean found = FALSE;
556 from = parse_from(sipmsg_find_header(msg, "From"));
558 if (!from) return;
560 SIPE_DEBUG_INFO("got message from %s: %s", from, msg->body);
562 contenttype = sipmsg_find_header(msg, "Content-Type");
563 if (g_str_has_prefix(contenttype, "text/plain")
564 || g_str_has_prefix(contenttype, "text/html")
565 || g_str_has_prefix(contenttype, "multipart/related")
566 || g_str_has_prefix(contenttype, "multipart/alternative"))
568 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
569 gchar *html = get_html_message(contenttype, msg->body);
571 struct sip_session *session = sipe_session_find_chat_or_im(sipe_private,
572 callid,
573 from);
574 if (session && session->chat_session) {
575 if (session->chat_session->type == SIPE_CHAT_TYPE_CONFERENCE) { /* a conference */
576 gchar *tmp = parse_from(sipmsg_find_header(msg, "Ms-Sender"));
577 gchar *sender = parse_from(tmp);
578 g_free(tmp);
579 sipe_backend_chat_message(SIPE_CORE_PUBLIC,
580 session->chat_session->backend,
581 sender,
582 html);
583 g_free(sender);
584 } else { /* a multiparty chat */
585 sipe_backend_chat_message(SIPE_CORE_PUBLIC,
586 session->chat_session->backend,
587 from,
588 html);
590 } else {
591 sipe_backend_im_message(SIPE_CORE_PUBLIC,
592 from,
593 html);
595 g_free(html);
596 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
597 found = TRUE;
599 } else if (g_str_has_prefix(contenttype, "application/im-iscomposing+xml")) {
600 sipe_xml *isc = sipe_xml_parse(msg->body, msg->bodylen);
601 const sipe_xml *state;
602 gchar *statedata;
604 if (!isc) {
605 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_message: can not parse iscomposing");
606 g_free(from);
607 return;
610 state = sipe_xml_child(isc, "state");
612 if (!state) {
613 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_message: no state found");
614 sipe_xml_free(isc);
615 g_free(from);
616 return;
619 statedata = sipe_xml_data(state);
620 if (statedata) {
621 if (strstr(statedata, "active")) {
622 sipe_backend_user_feedback_typing(SIPE_CORE_PUBLIC,
623 from);
624 } else {
625 sipe_backend_user_feedback_typing_stop(SIPE_CORE_PUBLIC,
626 from);
628 g_free(statedata);
630 sipe_xml_free(isc);
631 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
632 found = TRUE;
633 } else if (g_str_has_prefix(contenttype, "text/x-msmsgsinvite")) {
634 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
635 struct sip_session *session = sipe_session_find_chat_or_im(sipe_private,
636 callid,
637 from);
638 struct sip_dialog *dialog = sipe_dialog_find(session, from);
639 GSList *body = sipe_ft_parse_msg_body(msg->body);
640 found = sipe_process_incoming_x_msmsgsinvite(sipe_private, dialog, body);
641 sipe_utils_nameval_free(body);
642 if (found) {
643 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
646 if (!found) {
647 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
648 struct sip_session *session = sipe_session_find_chat_or_im(sipe_private,
649 callid,
650 from);
651 if (session) {
652 gchar *errmsg = g_strdup_printf(_("Received a message with unrecognized contents from %s"),
653 from);
654 sipe_user_present_error(sipe_private, session, errmsg);
655 g_free(errmsg);
658 SIPE_DEBUG_INFO("got unknown mime-type '%s'", contenttype);
659 sip_transport_response(sipe_private, msg, 415, "Unsupported media type", NULL);
661 g_free(from);
664 void process_incoming_options(struct sipe_core_private *sipe_private,
665 struct sipmsg *msg)
667 gchar *body;
669 sipmsg_add_header(msg, "Allow", "INVITE, MESSAGE, INFO, SUBSCRIBE, OPTIONS, BYE, CANCEL, NOTIFY, ACK, REFER, BENOTIFY");
670 sipmsg_add_header(msg, "Content-Type", "application/sdp");
672 body = g_strdup_printf(
673 "v=0\r\n"
674 "o=- 0 0 IN IP4 0.0.0.0\r\n"
675 "s=session\r\n"
676 "c=IN IP4 0.0.0.0\r\n"
677 "t=0 0\r\n"
678 "m=%s %d sip sip:%s\r\n"
679 "a=accept-types:" SDP_ACCEPT_TYPES "\r\n",
680 SIPE_CORE_PRIVATE_FLAG_IS(OCS2007) ? "message" : "x-ms-message",
681 sip_transport_port(sipe_private),
682 sipe_private->username);
683 sip_transport_response(sipe_private, msg, 200, "OK", body);
684 g_free(body);
687 void process_incoming_refer(struct sipe_core_private *sipe_private,
688 struct sipmsg *msg)
690 gchar *self = sip_uri_self(sipe_private);
691 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
692 gchar *from = parse_from(sipmsg_find_header(msg, "From"));
693 gchar *refer_to = parse_from(sipmsg_find_header(msg, "Refer-to"));
694 gchar *referred_by = g_strdup(sipmsg_find_header(msg, "Referred-By"));
695 struct sip_session *session;
696 struct sip_dialog *dialog;
698 session = sipe_session_find_chat_by_callid(sipe_private, callid);
699 dialog = sipe_dialog_find(session, from);
701 if (!session || !dialog || !session->chat_session ||
702 (session->chat_session->type != SIPE_CHAT_TYPE_MULTIPARTY) ||
703 !session->chat_session->id ||
704 !sipe_strcase_equal(session->chat_session->id, self)) {
705 sip_transport_response(sipe_private, msg, 500, "Server Internal Error", NULL);
706 } else {
707 sip_transport_response(sipe_private, msg, 202, "Accepted", NULL);
709 sipe_im_invite(sipe_private, session, refer_to, NULL, NULL, referred_by, FALSE);
712 g_free(self);
713 g_free(from);
714 g_free(refer_to);
715 g_free(referred_by);
719 Local Variables:
720 mode: c
721 c-file-style: "bsd"
722 indent-tabs-mode: t
723 tab-width: 8
724 End: