conf: allow to reject incoming AV conference call (2nd version)
[siplcs.git] / src / core / sipe-incoming.c
blob1db0e1de33c0dc998b37d3f3a9715ce0e883aa32
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(struct sipe_core_private *sipe_private,
121 struct sipmsg *msg)
123 const gchar *callid;
125 #ifdef HAVE_VV
126 if (is_media_session_msg(sipe_private->media_call, msg)) {
127 process_incoming_cancel_call(sipe_private, msg);
128 return;
130 #endif
131 callid = sipmsg_find_header(msg, "Call-ID");
133 if (!sipe_session_find_chat_by_callid(sipe_private, callid))
134 sipe_conf_cancel_unaccepted(sipe_private, msg);
137 void process_incoming_info(struct sipe_core_private *sipe_private,
138 struct sipmsg *msg)
140 const gchar *contenttype = sipmsg_find_header(msg, "Content-Type");
141 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
142 gchar *from;
143 struct sip_session *session;
145 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_info");
147 /* Call Control protocol */
148 if (g_str_has_prefix(contenttype, "application/csta+xml"))
150 process_incoming_info_csta(sipe_private, msg);
151 return;
153 else if (g_str_has_prefix(contenttype, "application/xml+conversationinfo"))
155 process_incoming_info_conversation(sipe_private, msg);
156 return;
159 from = parse_from(sipmsg_find_header(msg, "From"));
160 session = sipe_session_find_chat_or_im(sipe_private, callid, from);
161 if (!session) {
162 g_free(from);
163 return;
166 /* Group Chat uses text/plain */
167 if (session->is_groupchat) {
168 process_incoming_info_groupchat(sipe_private, msg, session);
169 g_free(from);
170 return;
173 if (g_str_has_prefix(contenttype, "application/x-ms-mim"))
175 sipe_xml *xn_action = sipe_xml_parse(msg->body, msg->bodylen);
176 const sipe_xml *xn_request_rm = sipe_xml_child(xn_action, "RequestRM");
177 const sipe_xml *xn_set_rm = sipe_xml_child(xn_action, "SetRM");
179 sipmsg_add_header(msg, "Content-Type", "application/x-ms-mim");
181 if (xn_request_rm) {
182 //const char *rm = sipe_xml_attribute(xn_request_rm, "uri");
183 int bid = sipe_xml_int_attribute(xn_request_rm, "bid", 0);
184 gchar *body = g_strdup_printf(
185 "<?xml version=\"1.0\"?>\r\n"
186 "<action xmlns=\"http://schemas.microsoft.com/sip/multiparty/\">"
187 "<RequestRMResponse uri=\"sip:%s\" allow=\"%s\"/></action>\r\n",
188 sipe_private->username,
189 session->bid < bid ? "true" : "false");
190 sip_transport_response(sipe_private, msg, 200, "OK", body);
191 g_free(body);
192 } else if (xn_set_rm) {
193 gchar *body;
195 sipe_chat_set_roster_manager(session,
196 sipe_xml_attribute(xn_set_rm, "uri"));
198 body = g_strdup_printf(
199 "<?xml version=\"1.0\"?>\r\n"
200 "<action xmlns=\"http://schemas.microsoft.com/sip/multiparty/\">"
201 "<SetRMResponse uri=\"sip:%s\"/></action>\r\n",
202 sipe_private->username);
203 sip_transport_response(sipe_private, msg, 200, "OK", body);
204 g_free(body);
206 sipe_xml_free(xn_action);
209 else
211 /* looks like purple lacks typing notification for chat */
212 if (!session->chat_session) {
213 sipe_xml *xn_keyboard_activity = sipe_xml_parse(msg->body, msg->bodylen);
214 const char *status = sipe_xml_attribute(sipe_xml_child(xn_keyboard_activity, "status"),
215 "status");
216 if (sipe_strequal(status, "type")) {
217 sipe_backend_user_feedback_typing(SIPE_CORE_PUBLIC,
218 from);
219 } else if (sipe_strequal(status, "idle")) {
220 sipe_backend_user_feedback_typing_stop(SIPE_CORE_PUBLIC,
221 from);
223 sipe_xml_free(xn_keyboard_activity);
226 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
228 g_free(from);
231 static gboolean sipe_process_incoming_x_msmsgsinvite(struct sipe_core_private *sipe_private,
232 struct sip_dialog *dialog,
233 GSList *parsed_body)
235 gboolean found = FALSE;
237 if (parsed_body) {
238 const gchar *invitation_command = sipe_utils_nameval_find(parsed_body, "Invitation-Command");
240 if (sipe_strequal(invitation_command, "INVITE")) {
241 sipe_ft_incoming_transfer(sipe_private, dialog, parsed_body);
242 found = TRUE;
243 } else if (sipe_strequal(invitation_command, "CANCEL")) {
244 sipe_ft_incoming_cancel(dialog, parsed_body);
245 found = TRUE;
246 } else if (sipe_strequal(invitation_command, "ACCEPT")) {
247 sipe_ft_incoming_accept(dialog, parsed_body);
248 found = TRUE;
251 return found;
254 #ifdef HAVE_VV
255 static void sipe_invite_mime_cb(gpointer user_data, const GSList *fields,
256 const gchar *body, gsize length)
258 const gchar *type = sipe_utils_nameval_find(fields, "Content-Type");
259 const gchar *cd = sipe_utils_nameval_find(fields, "Content-Disposition");
261 if (!g_str_has_prefix(type, "application/sdp"))
262 return;
264 if (cd && !strstr(cd, "ms-proxy-2007fallback")) {
265 struct sipmsg *msg = user_data;
266 const gchar* msg_ct = sipmsg_find_header(msg, "Content-Type");
268 if (g_str_has_prefix(msg_ct, "application/sdp")) {
269 /* We have already found suitable alternative and set message's body
270 * and Content-Type accordingly */
271 return;
274 sipmsg_remove_header_now(msg, "Content-Type");
275 sipmsg_add_header_now(msg, "Content-Type", type);
277 /* Replace message body with chosen alternative, so we can continue to
278 * process it as a normal single part message. */
279 g_free(msg->body);
280 msg->body = g_strndup(body, length);
281 msg->bodylen = length;
284 #endif
286 void process_incoming_invite(struct sipe_core_private *sipe_private,
287 struct sipmsg *msg)
289 gchar *body;
290 gchar *newTag;
291 const gchar *oldHeader;
292 gchar *newHeader;
293 gboolean is_multiparty = FALSE;
294 gboolean was_multiparty = TRUE;
295 gboolean just_joined = FALSE;
296 gchar *from;
297 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
298 const gchar *roster_manager = sipmsg_find_header(msg, "Roster-Manager");
299 const gchar *end_points_hdr = sipmsg_find_header(msg, "EndPoints");
300 const gchar *trig_invite = sipmsg_find_header(msg, "TriggeredInvite");
301 const gchar *content_type = sipmsg_find_header(msg, "Content-Type");
302 const gchar *subject = sipmsg_find_header(msg, "Subject");
303 GSList *end_points = NULL;
304 struct sip_session *session;
305 struct sip_dialog *dialog;
306 const gchar *ms_text_format;
308 #ifdef HAVE_VV
309 if (g_str_has_prefix(content_type, "multipart/alternative")) {
310 sipe_mime_parts_foreach(content_type, msg->body, sipe_invite_mime_cb, msg);
311 /* Reload Content-Type to get type of the selected message part */
312 content_type = sipmsg_find_header(msg, "Content-Type");
314 #endif
316 /* Invitation to join conference */
317 if (g_str_has_prefix(content_type, "application/ms-conf-invite+xml")) {
318 process_incoming_invite_conf(sipe_private, msg);
319 return;
322 #ifdef HAVE_VV
323 /* Invitation to audio call */
324 if (msg->body && strstr(msg->body, "m=audio")) {
325 process_incoming_invite_call(sipe_private, msg);
326 return;
328 #endif
330 /* Only accept text invitations */
331 if (msg->body && !(strstr(msg->body, "m=message") || strstr(msg->body, "m=x-ms-message"))) {
332 sip_transport_response(sipe_private, msg, 501, "Not implemented", NULL);
333 return;
336 // TODO There *must* be a better way to clean up the To header to add a tag...
337 SIPE_DEBUG_INFO_NOFORMAT("Adding a Tag to the To Header on Invite Request...");
338 oldHeader = sipmsg_find_header(msg, "To");
339 newTag = gentag();
340 newHeader = g_strdup_printf("%s;tag=%s", oldHeader, newTag);
341 g_free(newTag);
342 sipmsg_remove_header_now(msg, "To");
343 sipmsg_add_header_now(msg, "To", newHeader);
344 g_free(newHeader);
346 if (end_points_hdr) {
347 end_points = sipmsg_parse_endpoints_header(end_points_hdr);
349 if (g_slist_length(end_points) > 2) {
350 is_multiparty = TRUE;
353 if (trig_invite && !g_strcasecmp(trig_invite, "TRUE")) {
354 is_multiparty = TRUE;
357 /* Multiparty session */
358 session = sipe_session_find_chat_by_callid(sipe_private, callid);
359 if (is_multiparty) {
361 if (session) {
362 if (session->chat_session) {
363 /* Update roster manager for existing multiparty session */
364 if (roster_manager)
365 sipe_chat_set_roster_manager(session, roster_manager);
367 } else {
368 gchar *chat_title = sipe_chat_get_name();
370 /* Convert IM session to multiparty session */
371 g_free(session->with);
372 session->with = NULL;
373 was_multiparty = FALSE;
374 session->chat_session = sipe_chat_create_session(SIPE_CHAT_TYPE_MULTIPARTY,
375 roster_manager,
376 chat_title);
378 g_free(chat_title);
380 } else {
381 /* New multiparty session */
382 session = sipe_session_add_chat(sipe_private,
383 NULL,
384 TRUE,
385 roster_manager);
388 /* Create chat */
389 if (!session->chat_session->backend) {
390 gchar *self = sip_uri_self(sipe_private);
391 session->chat_session->backend = sipe_backend_chat_create(SIPE_CORE_PUBLIC,
392 session->chat_session,
393 session->chat_session->title,
394 self);
395 g_free(self);
399 /* IM session */
400 from = parse_from(sipmsg_find_header(msg, "From"));
401 if (!session)
402 session = sipe_session_find_or_add_im(sipe_private, from);
404 /* session is now initialized */
405 g_free(session->callid);
406 session->callid = g_strdup(callid);
408 if (is_multiparty && end_points) {
409 gchar *to = parse_from(sipmsg_find_header(msg, "To"));
410 GSList *entry = end_points;
411 while (entry) {
412 struct sipendpoint *end_point = entry->data;
413 entry = entry->next;
415 if (!g_strcasecmp(from, end_point->contact) ||
416 !g_strcasecmp(to, end_point->contact))
417 continue;
419 dialog = sipe_dialog_find(session, end_point->contact);
420 if (dialog) {
421 g_free(dialog->theirepid);
422 dialog->theirepid = end_point->epid;
423 end_point->epid = NULL;
424 } else {
425 dialog = sipe_dialog_add(session);
427 dialog->callid = g_strdup(session->callid);
428 dialog->with = end_point->contact;
429 end_point->contact = NULL;
430 dialog->theirepid = end_point->epid;
431 end_point->epid = NULL;
433 just_joined = TRUE;
435 /* send triggered INVITE */
436 sipe_im_invite(sipe_private, session, dialog->with, NULL, NULL, NULL, TRUE);
439 g_free(to);
442 if (end_points) {
443 GSList *entry = end_points;
444 while (entry) {
445 struct sipendpoint *end_point = entry->data;
446 entry = entry->next;
447 g_free(end_point->contact);
448 g_free(end_point->epid);
449 g_free(end_point);
451 g_slist_free(end_points);
454 dialog = sipe_dialog_find(session, from);
455 if (dialog) {
456 sipe_im_cancel_dangling(sipe_private, session, dialog, from,
457 sipe_im_reenqueue_unconfirmed);
458 /* dialog is no longer valid */
459 } else {
460 just_joined = TRUE;
463 dialog = sipe_dialog_add(session);
464 dialog->with = g_strdup(from);
465 dialog->callid = g_strdup(session->callid);
466 sipe_dialog_parse(dialog, msg, FALSE);
468 if (is_multiparty && !was_multiparty) {
469 /* add current IM counterparty to chat */
470 sipe_backend_chat_add(session->chat_session->backend,
471 sipe_dialog_first(session)->with,
472 FALSE);
475 /* add inviting party to chat */
476 if (just_joined && session->chat_session) {
477 sipe_backend_chat_add(session->chat_session->backend,
478 from,
479 TRUE);
482 if (!is_multiparty && subject)
483 sipe_im_topic(sipe_private, session, subject);
485 /* ms-text-format: text/plain; charset=UTF-8;msgr=WAAtAE0...DIADQAKAA0ACgA;ms-body=SGk= */
487 /* This used only in 2005 official client, not 2007 or Reuters.
488 Disabled for most cases as interfering with audit of messages which only is applied to regular MESSAGEs.
489 Only enabled for 2005 multiparty chats as otherwise the first message got lost completely.
491 /* also enabled for 2005 file transfer. Didn't work otherwise. */
492 ms_text_format = sipmsg_find_header(msg, "ms-text-format");
493 if (is_multiparty ||
494 (ms_text_format && g_str_has_prefix(ms_text_format, "text/x-msmsgsinvite")) )
496 if (ms_text_format) {
497 if (g_str_has_prefix(ms_text_format, "text/x-msmsgsinvite"))
499 gchar *tmp = sipmsg_find_part_of_header(ms_text_format, "ms-body=", NULL, NULL);
500 if (tmp) {
501 gsize len;
502 gchar *body = (gchar *) g_base64_decode(tmp, &len);
503 GSList *parsed_body = sipe_ft_parse_msg_body(body);
505 dialog = sipe_dialog_find(session, from);
506 sipe_process_incoming_x_msmsgsinvite(sipe_private, dialog, parsed_body);
507 sipe_utils_nameval_free(parsed_body);
508 sipmsg_add_header(msg, "Supported", "ms-text-format"); /* accepts received message */
510 g_free(tmp);
512 else if (g_str_has_prefix(ms_text_format, "text/plain") || g_str_has_prefix(ms_text_format, "text/html"))
514 /* please do not optimize logic inside as this code may be re-enabled for other cases */
515 gchar *html = get_html_message(ms_text_format, NULL);
516 if (html) {
517 if (is_multiparty) {
518 sipe_backend_chat_message(SIPE_CORE_PUBLIC,
519 session->chat_session->backend,
520 from,
521 html);
522 } else {
523 sipe_backend_im_message(SIPE_CORE_PUBLIC,
524 from,
525 html);
527 g_free(html);
528 sipmsg_add_header(msg, "Supported", "ms-text-format"); /* accepts received message */
534 g_free(from);
536 sipmsg_add_header(msg, "Supported", "com.microsoft.rtc-multiparty");
537 sipmsg_add_header(msg, "Content-Type", "application/sdp");
539 body = g_strdup_printf(
540 "v=0\r\n"
541 "o=- 0 0 IN IP4 %s\r\n"
542 "s=session\r\n"
543 "c=IN IP4 %s\r\n"
544 "t=0 0\r\n"
545 "m=%s %d sip sip:%s\r\n"
546 "a=accept-types:" SDP_ACCEPT_TYPES "\r\n",
547 sipe_backend_network_ip_address(),
548 sipe_backend_network_ip_address(),
549 SIPE_CORE_PRIVATE_FLAG_IS(OCS2007) ? "message" : "x-ms-message",
550 sip_transport_port(sipe_private),
551 sipe_private->username);
552 sip_transport_response(sipe_private, msg, 200, "OK", body);
553 g_free(body);
556 void process_incoming_message(struct sipe_core_private *sipe_private,
557 struct sipmsg *msg)
559 gchar *from;
560 const gchar *contenttype;
561 gboolean found = FALSE;
563 from = parse_from(sipmsg_find_header(msg, "From"));
565 if (!from) return;
567 SIPE_DEBUG_INFO("got message from %s: %s", from, msg->body);
569 contenttype = sipmsg_find_header(msg, "Content-Type");
570 if (g_str_has_prefix(contenttype, "text/plain")
571 || g_str_has_prefix(contenttype, "text/html")
572 || g_str_has_prefix(contenttype, "multipart/related")
573 || g_str_has_prefix(contenttype, "multipart/alternative"))
575 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
576 gchar *html = get_html_message(contenttype, msg->body);
578 struct sip_session *session = sipe_session_find_chat_or_im(sipe_private,
579 callid,
580 from);
581 if (session && session->chat_session) {
582 if (session->chat_session->type == SIPE_CHAT_TYPE_CONFERENCE) { /* a conference */
583 gchar *tmp = parse_from(sipmsg_find_header(msg, "Ms-Sender"));
584 gchar *sender = parse_from(tmp);
585 g_free(tmp);
586 sipe_backend_chat_message(SIPE_CORE_PUBLIC,
587 session->chat_session->backend,
588 sender,
589 html);
590 g_free(sender);
591 } else { /* a multiparty chat */
592 sipe_backend_chat_message(SIPE_CORE_PUBLIC,
593 session->chat_session->backend,
594 from,
595 html);
597 } else {
598 sipe_backend_im_message(SIPE_CORE_PUBLIC,
599 from,
600 html);
602 g_free(html);
603 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
604 found = TRUE;
606 } else if (g_str_has_prefix(contenttype, "application/im-iscomposing+xml")) {
607 sipe_xml *isc = sipe_xml_parse(msg->body, msg->bodylen);
608 const sipe_xml *state;
609 gchar *statedata;
611 if (!isc) {
612 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_message: can not parse iscomposing");
613 g_free(from);
614 return;
617 state = sipe_xml_child(isc, "state");
619 if (!state) {
620 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_message: no state found");
621 sipe_xml_free(isc);
622 g_free(from);
623 return;
626 statedata = sipe_xml_data(state);
627 if (statedata) {
628 if (strstr(statedata, "active")) {
629 sipe_backend_user_feedback_typing(SIPE_CORE_PUBLIC,
630 from);
631 } else {
632 sipe_backend_user_feedback_typing_stop(SIPE_CORE_PUBLIC,
633 from);
635 g_free(statedata);
637 sipe_xml_free(isc);
638 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
639 found = TRUE;
640 } else if (g_str_has_prefix(contenttype, "text/x-msmsgsinvite")) {
641 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
642 struct sip_session *session = sipe_session_find_chat_or_im(sipe_private,
643 callid,
644 from);
645 struct sip_dialog *dialog = sipe_dialog_find(session, from);
646 GSList *body = sipe_ft_parse_msg_body(msg->body);
647 found = sipe_process_incoming_x_msmsgsinvite(sipe_private, dialog, body);
648 sipe_utils_nameval_free(body);
649 if (found) {
650 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
653 if (!found) {
654 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
655 struct sip_session *session = sipe_session_find_chat_or_im(sipe_private,
656 callid,
657 from);
658 if (session) {
659 gchar *errmsg = g_strdup_printf(_("Received a message with unrecognized contents from %s"),
660 from);
661 sipe_user_present_error(sipe_private, session, errmsg);
662 g_free(errmsg);
665 SIPE_DEBUG_INFO("got unknown mime-type '%s'", contenttype);
666 sip_transport_response(sipe_private, msg, 415, "Unsupported media type", NULL);
668 g_free(from);
671 void process_incoming_options(struct sipe_core_private *sipe_private,
672 struct sipmsg *msg)
674 gchar *body;
676 sipmsg_add_header(msg, "Allow", "INVITE, MESSAGE, INFO, SUBSCRIBE, OPTIONS, BYE, CANCEL, NOTIFY, ACK, REFER, BENOTIFY");
677 sipmsg_add_header(msg, "Content-Type", "application/sdp");
679 body = g_strdup_printf(
680 "v=0\r\n"
681 "o=- 0 0 IN IP4 0.0.0.0\r\n"
682 "s=session\r\n"
683 "c=IN IP4 0.0.0.0\r\n"
684 "t=0 0\r\n"
685 "m=%s %d sip sip:%s\r\n"
686 "a=accept-types:" SDP_ACCEPT_TYPES "\r\n",
687 SIPE_CORE_PRIVATE_FLAG_IS(OCS2007) ? "message" : "x-ms-message",
688 sip_transport_port(sipe_private),
689 sipe_private->username);
690 sip_transport_response(sipe_private, msg, 200, "OK", body);
691 g_free(body);
694 void process_incoming_refer(struct sipe_core_private *sipe_private,
695 struct sipmsg *msg)
697 gchar *self = sip_uri_self(sipe_private);
698 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
699 gchar *from = parse_from(sipmsg_find_header(msg, "From"));
700 gchar *refer_to = parse_from(sipmsg_find_header(msg, "Refer-to"));
701 gchar *referred_by = g_strdup(sipmsg_find_header(msg, "Referred-By"));
702 struct sip_session *session;
703 struct sip_dialog *dialog;
705 session = sipe_session_find_chat_by_callid(sipe_private, callid);
706 dialog = sipe_dialog_find(session, from);
708 if (!session || !dialog || !session->chat_session ||
709 (session->chat_session->type != SIPE_CHAT_TYPE_MULTIPARTY) ||
710 !session->chat_session->id ||
711 !sipe_strcase_equal(session->chat_session->id, self)) {
712 sip_transport_response(sipe_private, msg, 500, "Server Internal Error", NULL);
713 } else {
714 sip_transport_response(sipe_private, msg, 202, "Accepted", NULL);
716 sipe_im_invite(sipe_private, session, refer_to, NULL, NULL, referred_by, FALSE);
719 g_free(self);
720 g_free(from);
721 g_free(refer_to);
722 g_free(referred_by);
726 Local Variables:
727 mode: c
728 c-file-style: "bsd"
729 indent-tabs-mode: t
730 tab-width: 8
731 End: