incoming: use unique name for delayed invite response action
[siplcs.git] / src / core / sipe-incoming.c
blobff1e8bee8d294a1ed27ae3923dcbcd26530efbc5
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 static void delayed_invite_destroy(gpointer data)
310 sipmsg_free(data);
312 static void delayed_invite_timeout(struct sipe_core_private *sipe_private,
313 gpointer data)
315 send_invite_response(sipe_private, data);
316 sipmsg_free(data);
319 static void delayed_invite_response(struct sipe_core_private *sipe_private,
320 struct sipmsg *msg,
321 const gchar *callid)
323 gchar *action = g_strdup_printf("<delayed-invite-%s>", callid);
324 sipe_schedule_seconds(sipe_private,
325 action,
326 sipmsg_copy(msg),
328 delayed_invite_timeout,
329 delayed_invite_destroy);
330 g_free(action);
333 void process_incoming_invite(struct sipe_core_private *sipe_private,
334 struct sipmsg *msg)
336 gchar *newTag;
337 const gchar *oldHeader;
338 gchar *newHeader;
339 gboolean is_multiparty = FALSE;
340 gboolean was_multiparty = TRUE;
341 gboolean just_joined = FALSE;
342 gchar *from;
343 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
344 const gchar *roster_manager = sipmsg_find_header(msg, "Roster-Manager");
345 const gchar *end_points_hdr = sipmsg_find_header(msg, "EndPoints");
346 const gchar *trig_invite = sipmsg_find_header(msg, "TriggeredInvite");
347 const gchar *content_type = sipmsg_find_header(msg, "Content-Type");
348 const gchar *subject = sipmsg_find_header(msg, "Subject");
349 GSList *end_points = NULL;
350 struct sip_session *session;
351 struct sip_dialog *dialog;
352 const gchar *ms_text_format;
353 gboolean dont_delay = FALSE;
355 #ifdef HAVE_VV
356 if (g_str_has_prefix(content_type, "multipart/alternative")) {
357 sipe_mime_parts_foreach(content_type, msg->body, sipe_invite_mime_cb, msg);
358 /* Reload Content-Type to get type of the selected message part */
359 content_type = sipmsg_find_header(msg, "Content-Type");
361 #endif
363 /* Invitation to join conference */
364 if (g_str_has_prefix(content_type, "application/ms-conf-invite+xml")) {
365 process_incoming_invite_conf(sipe_private, msg);
366 return;
369 #ifdef HAVE_VV
370 /* Invitation to audio call */
371 if (msg->body && strstr(msg->body, "m=audio")) {
372 process_incoming_invite_call(sipe_private, msg);
373 return;
375 #endif
377 /* Only accept text invitations */
378 if (msg->body && !(strstr(msg->body, "m=message") || strstr(msg->body, "m=x-ms-message"))) {
379 sip_transport_response(sipe_private, msg, 501, "Not implemented", NULL);
380 return;
383 // TODO There *must* be a better way to clean up the To header to add a tag...
384 SIPE_DEBUG_INFO_NOFORMAT("Adding a Tag to the To Header on Invite Request...");
385 oldHeader = sipmsg_find_header(msg, "To");
386 newTag = gentag();
387 newHeader = g_strdup_printf("%s;tag=%s", oldHeader, newTag);
388 g_free(newTag);
389 sipmsg_remove_header_now(msg, "To");
390 sipmsg_add_header_now(msg, "To", newHeader);
391 g_free(newHeader);
393 if (end_points_hdr) {
394 end_points = sipmsg_parse_endpoints_header(end_points_hdr);
396 if (g_slist_length(end_points) > 2) {
397 is_multiparty = TRUE;
400 if (trig_invite && !g_strcasecmp(trig_invite, "TRUE")) {
401 is_multiparty = TRUE;
404 /* Multiparty session */
405 session = sipe_session_find_chat_by_callid(sipe_private, callid);
406 if (is_multiparty) {
408 if (session) {
409 if (session->chat_session) {
410 /* Update roster manager for existing multiparty session */
411 if (roster_manager)
412 sipe_chat_set_roster_manager(session, roster_manager);
414 } else {
415 gchar *chat_title = sipe_chat_get_name();
417 /* Convert IM session to multiparty session */
418 g_free(session->with);
419 session->with = NULL;
420 was_multiparty = FALSE;
421 session->chat_session = sipe_chat_create_session(SIPE_CHAT_TYPE_MULTIPARTY,
422 roster_manager,
423 chat_title);
425 g_free(chat_title);
427 } else {
428 /* New multiparty session */
429 session = sipe_session_add_chat(sipe_private,
430 NULL,
431 TRUE,
432 roster_manager);
435 /* Create chat */
436 if (!session->chat_session->backend) {
437 gchar *self = sip_uri_self(sipe_private);
438 session->chat_session->backend = sipe_backend_chat_create(SIPE_CORE_PUBLIC,
439 session->chat_session,
440 session->chat_session->title,
441 self);
442 g_free(self);
446 /* IM session */
447 from = parse_from(sipmsg_find_header(msg, "From"));
448 if (!session)
449 session = sipe_session_find_or_add_im(sipe_private, from);
451 /* session is now initialized */
452 g_free(session->callid);
453 session->callid = g_strdup(callid);
455 if (is_multiparty && end_points) {
456 gchar *to = parse_from(sipmsg_find_header(msg, "To"));
457 GSList *entry = end_points;
458 while (entry) {
459 struct sipendpoint *end_point = entry->data;
460 entry = entry->next;
462 if (!g_strcasecmp(from, end_point->contact) ||
463 !g_strcasecmp(to, end_point->contact))
464 continue;
466 dialog = sipe_dialog_find(session, end_point->contact);
467 if (dialog) {
468 g_free(dialog->theirepid);
469 dialog->theirepid = end_point->epid;
470 end_point->epid = NULL;
471 } else {
472 dialog = sipe_dialog_add(session);
474 dialog->callid = g_strdup(session->callid);
475 dialog->with = end_point->contact;
476 end_point->contact = NULL;
477 dialog->theirepid = end_point->epid;
478 end_point->epid = NULL;
480 just_joined = TRUE;
482 /* send triggered INVITE */
483 sipe_im_invite(sipe_private, session, dialog->with, NULL, NULL, NULL, TRUE);
486 g_free(to);
489 if (end_points) {
490 GSList *entry = end_points;
491 while (entry) {
492 struct sipendpoint *end_point = entry->data;
493 entry = entry->next;
494 g_free(end_point->contact);
495 g_free(end_point->epid);
496 g_free(end_point);
498 g_slist_free(end_points);
501 dialog = sipe_dialog_find(session, from);
502 if (dialog) {
503 sipe_im_cancel_dangling(sipe_private, session, dialog, from,
504 sipe_im_reenqueue_unconfirmed);
505 /* dialog is no longer valid */
506 } else {
507 just_joined = TRUE;
510 dialog = sipe_dialog_add(session);
511 dialog->with = g_strdup(from);
512 dialog->callid = g_strdup(session->callid);
513 sipe_dialog_parse(dialog, msg, FALSE);
515 if (is_multiparty && !was_multiparty) {
516 /* add current IM counterparty to chat */
517 sipe_backend_chat_add(session->chat_session->backend,
518 sipe_dialog_first(session)->with,
519 FALSE);
522 /* add inviting party to chat */
523 if (just_joined && session->chat_session) {
524 sipe_backend_chat_add(session->chat_session->backend,
525 from,
526 TRUE);
529 if (!is_multiparty && subject)
530 sipe_im_topic(sipe_private, session, subject);
532 /* ms-text-format: text/plain; charset=UTF-8;msgr=WAAtAE0...DIADQAKAA0ACgA;ms-body=SGk= */
534 /* This used only in 2005 official client, not 2007 or Reuters.
535 Disabled for most cases as interfering with audit of messages which only is applied to regular MESSAGEs.
536 Only enabled for 2005 multiparty chats as otherwise the first message got lost completely.
538 /* also enabled for 2005 file transfer. Didn't work otherwise. */
539 ms_text_format = sipmsg_find_header(msg, "ms-text-format");
540 if (is_multiparty ||
541 (ms_text_format && g_str_has_prefix(ms_text_format, "text/x-msmsgsinvite")) )
543 if (ms_text_format) {
544 if (g_str_has_prefix(ms_text_format, "text/x-msmsgsinvite"))
546 gchar *tmp = sipmsg_find_part_of_header(ms_text_format, "ms-body=", NULL, NULL);
547 if (tmp) {
548 gsize len;
549 gchar *body = (gchar *) g_base64_decode(tmp, &len);
550 GSList *parsed_body = sipe_ft_parse_msg_body(body);
552 dialog = sipe_dialog_find(session, from);
553 sipe_process_incoming_x_msmsgsinvite(sipe_private, dialog, parsed_body);
554 sipe_utils_nameval_free(parsed_body);
555 sipmsg_add_header(msg, "Supported", "ms-text-format"); /* accepts received message */
556 dont_delay = TRUE;
558 g_free(tmp);
560 else if (g_str_has_prefix(ms_text_format, "text/plain") || g_str_has_prefix(ms_text_format, "text/html"))
562 /* please do not optimize logic inside as this code may be re-enabled for other cases */
563 gchar *html = get_html_message(ms_text_format, NULL);
564 if (html) {
565 if (is_multiparty) {
566 sipe_backend_chat_message(SIPE_CORE_PUBLIC,
567 session->chat_session->backend,
568 from,
569 html);
570 } else {
571 sipe_backend_im_message(SIPE_CORE_PUBLIC,
572 from,
573 html);
575 g_free(html);
576 sipmsg_add_header(msg, "Supported", "ms-text-format"); /* accepts received message */
577 dont_delay = TRUE;
583 g_free(from);
585 sipmsg_add_header(msg, "Supported", "com.microsoft.rtc-multiparty");
587 if (dont_delay || !SIPE_CORE_PRIVATE_FLAG_IS(MPOP)) {
588 send_invite_response(sipe_private, msg);
589 } else {
590 delayed_invite_response(sipe_private, msg, session->callid);
594 void process_incoming_message(struct sipe_core_private *sipe_private,
595 struct sipmsg *msg)
597 gchar *from;
598 const gchar *contenttype;
599 gboolean found = FALSE;
601 from = parse_from(sipmsg_find_header(msg, "From"));
603 if (!from) return;
605 SIPE_DEBUG_INFO("got message from %s: %s", from, msg->body);
607 contenttype = sipmsg_find_header(msg, "Content-Type");
608 if (g_str_has_prefix(contenttype, "text/plain")
609 || g_str_has_prefix(contenttype, "text/html")
610 || g_str_has_prefix(contenttype, "multipart/related")
611 || g_str_has_prefix(contenttype, "multipart/alternative"))
613 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
614 gchar *html = get_html_message(contenttype, msg->body);
616 struct sip_session *session = sipe_session_find_chat_or_im(sipe_private,
617 callid,
618 from);
619 if (session && session->chat_session) {
620 if (session->chat_session->type == SIPE_CHAT_TYPE_CONFERENCE) { /* a conference */
621 gchar *tmp = parse_from(sipmsg_find_header(msg, "Ms-Sender"));
622 gchar *sender = parse_from(tmp);
623 g_free(tmp);
624 sipe_backend_chat_message(SIPE_CORE_PUBLIC,
625 session->chat_session->backend,
626 sender,
627 html);
628 g_free(sender);
629 } else { /* a multiparty chat */
630 sipe_backend_chat_message(SIPE_CORE_PUBLIC,
631 session->chat_session->backend,
632 from,
633 html);
635 } else {
636 sipe_backend_im_message(SIPE_CORE_PUBLIC,
637 from,
638 html);
640 g_free(html);
641 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
642 found = TRUE;
644 } else if (g_str_has_prefix(contenttype, "application/im-iscomposing+xml")) {
645 sipe_xml *isc = sipe_xml_parse(msg->body, msg->bodylen);
646 const sipe_xml *state;
647 gchar *statedata;
649 if (!isc) {
650 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_message: can not parse iscomposing");
651 g_free(from);
652 return;
655 state = sipe_xml_child(isc, "state");
657 if (!state) {
658 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_message: no state found");
659 sipe_xml_free(isc);
660 g_free(from);
661 return;
664 statedata = sipe_xml_data(state);
665 if (statedata) {
666 if (strstr(statedata, "active")) {
667 sipe_backend_user_feedback_typing(SIPE_CORE_PUBLIC,
668 from);
669 } else {
670 sipe_backend_user_feedback_typing_stop(SIPE_CORE_PUBLIC,
671 from);
673 g_free(statedata);
675 sipe_xml_free(isc);
676 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
677 found = TRUE;
678 } else if (g_str_has_prefix(contenttype, "text/x-msmsgsinvite")) {
679 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
680 struct sip_session *session = sipe_session_find_chat_or_im(sipe_private,
681 callid,
682 from);
683 struct sip_dialog *dialog = sipe_dialog_find(session, from);
684 GSList *body = sipe_ft_parse_msg_body(msg->body);
685 found = sipe_process_incoming_x_msmsgsinvite(sipe_private, dialog, body);
686 sipe_utils_nameval_free(body);
687 if (found) {
688 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
691 if (!found) {
692 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
693 struct sip_session *session = sipe_session_find_chat_or_im(sipe_private,
694 callid,
695 from);
696 if (session) {
697 gchar *errmsg = g_strdup_printf(_("Received a message with unrecognized contents from %s"),
698 from);
699 sipe_user_present_error(sipe_private, session, errmsg);
700 g_free(errmsg);
703 SIPE_DEBUG_INFO("got unknown mime-type '%s'", contenttype);
704 sip_transport_response(sipe_private, msg, 415, "Unsupported media type", NULL);
706 g_free(from);
709 void process_incoming_options(struct sipe_core_private *sipe_private,
710 struct sipmsg *msg)
712 gchar *body;
714 sipmsg_add_header(msg, "Allow", "INVITE, MESSAGE, INFO, SUBSCRIBE, OPTIONS, BYE, CANCEL, NOTIFY, ACK, REFER, BENOTIFY");
715 sipmsg_add_header(msg, "Content-Type", "application/sdp");
717 body = g_strdup_printf(
718 "v=0\r\n"
719 "o=- 0 0 IN IP4 0.0.0.0\r\n"
720 "s=session\r\n"
721 "c=IN IP4 0.0.0.0\r\n"
722 "t=0 0\r\n"
723 "m=%s %d sip sip:%s\r\n"
724 "a=accept-types:" SDP_ACCEPT_TYPES "\r\n",
725 SIPE_CORE_PRIVATE_FLAG_IS(OCS2007) ? "message" : "x-ms-message",
726 sip_transport_port(sipe_private),
727 sipe_private->username);
728 sip_transport_response(sipe_private, msg, 200, "OK", body);
729 g_free(body);
732 void process_incoming_refer(struct sipe_core_private *sipe_private,
733 struct sipmsg *msg)
735 gchar *self = sip_uri_self(sipe_private);
736 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
737 gchar *from = parse_from(sipmsg_find_header(msg, "From"));
738 gchar *refer_to = parse_from(sipmsg_find_header(msg, "Refer-to"));
739 gchar *referred_by = g_strdup(sipmsg_find_header(msg, "Referred-By"));
740 struct sip_session *session;
741 struct sip_dialog *dialog;
743 session = sipe_session_find_chat_by_callid(sipe_private, callid);
744 dialog = sipe_dialog_find(session, from);
746 if (!session || !dialog || !session->chat_session ||
747 (session->chat_session->type != SIPE_CHAT_TYPE_MULTIPARTY) ||
748 !session->chat_session->id ||
749 !sipe_strcase_equal(session->chat_session->id, self)) {
750 sip_transport_response(sipe_private, msg, 500, "Server Internal Error", NULL);
751 } else {
752 sip_transport_response(sipe_private, msg, 202, "Accepted", NULL);
754 sipe_im_invite(sipe_private, session, refer_to, NULL, NULL, referred_by, FALSE);
757 g_free(self);
758 g_free(from);
759 g_free(refer_to);
760 g_free(referred_by);
764 Local Variables:
765 mode: c
766 c-file-style: "bsd"
767 indent-tabs-mode: t
768 tab-width: 8
769 End: