Fix sipe_buddy_menu_copy_to_cb when copying buddy not yet in our list
[siplcs.git] / src / core / sipe-incoming.c
blobb4dc0a0808b03531f8dff1246efe74501fc32aa7
1 /**
2 * @file sipe-incoming.c
4 * pidgin-sipe
6 * Copyright (C) 2010 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-incoming.h"
45 #include "sipe-media.h"
46 #include "sipe-nls.h"
47 #include "sipe-session.h"
48 #include "sipe-utils.h"
49 #include "sipe-xml.h"
50 #include "sipe-mime.h"
51 #include "sipe.h"
53 void process_incoming_bye(struct sipe_core_private *sipe_private,
54 struct sipmsg *msg)
56 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
57 gchar *from = parse_from(sipmsg_find_header(msg, "From"));
58 struct sip_session *session;
59 struct sip_dialog *dialog;
61 #ifdef HAVE_VV
62 if (is_media_session_msg(sipe_private->media_call, msg)) {
63 // BYE ends a media call
64 sipe_media_hangup(sipe_private->media_call);
66 #endif
68 /* collect dialog identification
69 * we need callid, ourtag and theirtag to unambiguously identify dialog
71 /* take data before 'msg' will be modified by sip_transport_response */
72 dialog = g_new0(struct sip_dialog, 1);
73 dialog->callid = g_strdup(callid);
74 dialog->cseq = parse_cseq(sipmsg_find_header(msg, "CSeq"));
75 dialog->with = g_strdup(from);
76 sipe_dialog_parse(dialog, msg, FALSE);
78 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
80 session = sipe_session_find_chat_or_im(sipe_private, callid, from);
81 if (!session) {
82 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_bye: couldn't find session. Ignoring");
83 sipe_dialog_free(dialog);
84 g_free(from);
85 return;
88 SIPE_DEBUG_INFO("process_incoming_bye: session found (chat ID %s)",
89 (session->chat_session && session->chat_session->id) ?
90 session->chat_session->id : "<NO CHAT>");
92 if (session->chat_session &&
93 (session->chat_session->type == SIPE_CHAT_TYPE_MULTIPARTY) &&
94 session->chat_session->id &&
95 !g_strcasecmp(from, session->chat_session->id))
96 sipe_chat_set_roster_manager(session, NULL);
98 /* This what BYE is essentially for - terminating dialog */
99 sipe_dialog_remove_3(session, dialog);
100 sipe_dialog_free(dialog);
101 if (session->chat_session) {
102 if ((session->chat_session->type == SIPE_CHAT_TYPE_CONFERENCE) &&
103 !g_strcasecmp(from, session->im_mcu_uri)) {
104 SIPE_DEBUG_INFO("process_incoming_bye: disconnected from conference %s",
105 session->im_mcu_uri);
106 sipe_conf_immcu_closed(sipe_private, session);
107 } else if (session->chat_session->type == SIPE_CHAT_TYPE_MULTIPARTY) {
108 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_bye: disconnected from multiparty chat");
109 sipe_backend_chat_remove(session->chat_session->backend,
110 from);
114 g_free(from);
117 void process_incoming_cancel(SIPE_UNUSED_PARAMETER struct sipe_core_private *sipe_private,
118 SIPE_UNUSED_PARAMETER struct sipmsg *msg)
120 #ifdef HAVE_VV
121 if (is_media_session_msg(sipe_private->media_call, msg)) {
122 process_incoming_cancel_call(sipe_private, msg);
124 #endif
127 void process_incoming_info(struct sipe_core_private *sipe_private,
128 struct sipmsg *msg)
130 const gchar *contenttype = sipmsg_find_header(msg, "Content-Type");
131 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
132 gchar *from;
133 struct sip_session *session;
135 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_info");
137 /* Call Control protocol */
138 if (g_str_has_prefix(contenttype, "application/csta+xml"))
140 process_incoming_info_csta(sipe_private, msg);
141 return;
144 from = parse_from(sipmsg_find_header(msg, "From"));
145 session = sipe_session_find_chat_or_im(sipe_private, callid, from);
146 if (!session) {
147 g_free(from);
148 return;
151 /* Group Chat uses text/plain */
152 if (session->is_groupchat) {
153 process_incoming_info_groupchat(sipe_private, msg, session);
154 g_free(from);
155 return;
158 if (g_str_has_prefix(contenttype, "application/x-ms-mim"))
160 sipe_xml *xn_action = sipe_xml_parse(msg->body, msg->bodylen);
161 const sipe_xml *xn_request_rm = sipe_xml_child(xn_action, "RequestRM");
162 const sipe_xml *xn_set_rm = sipe_xml_child(xn_action, "SetRM");
164 sipmsg_add_header(msg, "Content-Type", "application/x-ms-mim");
166 if (xn_request_rm) {
167 //const char *rm = sipe_xml_attribute(xn_request_rm, "uri");
168 int bid = sipe_xml_int_attribute(xn_request_rm, "bid", 0);
169 gchar *body = g_strdup_printf(
170 "<?xml version=\"1.0\"?>\r\n"
171 "<action xmlns=\"http://schemas.microsoft.com/sip/multiparty/\">"
172 "<RequestRMResponse uri=\"sip:%s\" allow=\"%s\"/></action>\r\n",
173 sipe_private->username,
174 session->bid < bid ? "true" : "false");
175 sip_transport_response(sipe_private, msg, 200, "OK", body);
176 g_free(body);
177 } else if (xn_set_rm) {
178 gchar *body;
180 sipe_chat_set_roster_manager(session,
181 sipe_xml_attribute(xn_set_rm, "uri"));
183 body = g_strdup_printf(
184 "<?xml version=\"1.0\"?>\r\n"
185 "<action xmlns=\"http://schemas.microsoft.com/sip/multiparty/\">"
186 "<SetRMResponse uri=\"sip:%s\"/></action>\r\n",
187 sipe_private->username);
188 sip_transport_response(sipe_private, msg, 200, "OK", body);
189 g_free(body);
191 sipe_xml_free(xn_action);
194 else
196 /* looks like purple lacks typing notification for chat */
197 if (!session->chat_session) {
198 sipe_xml *xn_keyboard_activity = sipe_xml_parse(msg->body, msg->bodylen);
199 const char *status = sipe_xml_attribute(sipe_xml_child(xn_keyboard_activity, "status"),
200 "status");
201 if (sipe_strequal(status, "type")) {
202 sipe_backend_user_feedback_typing(SIPE_CORE_PUBLIC,
203 from);
204 } else if (sipe_strequal(status, "idle")) {
205 sipe_backend_user_feedback_typing_stop(SIPE_CORE_PUBLIC,
206 from);
208 sipe_xml_free(xn_keyboard_activity);
211 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
213 g_free(from);
216 static gboolean sipe_process_incoming_x_msmsgsinvite(struct sipe_core_private *sipe_private,
217 struct sip_dialog *dialog,
218 GSList *parsed_body)
220 gboolean found = FALSE;
222 if (parsed_body) {
223 const gchar *invitation_command = sipe_utils_nameval_find(parsed_body, "Invitation-Command");
225 if (sipe_strequal(invitation_command, "INVITE")) {
226 sipe_ft_incoming_transfer(sipe_private, dialog, parsed_body);
227 found = TRUE;
228 } else if (sipe_strequal(invitation_command, "CANCEL")) {
229 sipe_ft_incoming_cancel(dialog, parsed_body);
230 found = TRUE;
231 } else if (sipe_strequal(invitation_command, "ACCEPT")) {
232 sipe_ft_incoming_accept(dialog, parsed_body);
233 found = TRUE;
236 return found;
239 #ifdef HAVE_VV
240 static void sipe_invite_mime_cb(gpointer user_data, const GSList *fields,
241 const gchar *body, gsize length)
243 const gchar *type = sipe_utils_nameval_find(fields, "Content-Type");
244 const gchar *cd = sipe_utils_nameval_find(fields, "Content-Disposition");
246 if (!g_str_has_prefix(type, "application/sdp"))
247 return;
249 if (cd && !strstr(cd, "ms-proxy-2007fallback")) {
250 struct sipmsg *msg = user_data;
251 const gchar* msg_ct = sipmsg_find_header(msg, "Content-Type");
253 if (g_str_has_prefix(msg_ct, "application/sdp")) {
254 /* We have already found suitable alternative and set message's body
255 * and Content-Type accordingly */
256 return;
259 sipmsg_remove_header_now(msg, "Content-Type");
260 sipmsg_add_header_now(msg, "Content-Type", type);
262 /* Replace message body with chosen alternative, so we can continue to
263 * process it as a normal single part message. */
264 g_free(msg->body);
265 msg->body = g_strndup(body, length);
266 msg->bodylen = length;
269 #endif
271 void process_incoming_invite(struct sipe_core_private *sipe_private,
272 struct sipmsg *msg)
274 gchar *body;
275 gchar *newTag;
276 const gchar *oldHeader;
277 gchar *newHeader;
278 gboolean is_multiparty = FALSE;
279 gboolean is_triggered = FALSE;
280 gboolean was_multiparty = TRUE;
281 gboolean just_joined = FALSE;
282 gchar *from;
283 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
284 const gchar *roster_manager = sipmsg_find_header(msg, "Roster-Manager");
285 const gchar *end_points_hdr = sipmsg_find_header(msg, "EndPoints");
286 const gchar *trig_invite = sipmsg_find_header(msg, "TriggeredInvite");
287 const gchar *content_type = sipmsg_find_header(msg, "Content-Type");
288 GSList *end_points = NULL;
289 struct sip_session *session;
290 struct sip_dialog *dialog;
291 const gchar *ms_text_format;
293 #ifdef HAVE_VV
294 if (g_str_has_prefix(content_type, "multipart/alternative")) {
295 sipe_mime_parts_foreach(content_type, msg->body, sipe_invite_mime_cb, msg);
296 /* Reload Content-Type to get type of the selected message part */
297 content_type = sipmsg_find_header(msg, "Content-Type");
299 #endif
301 /* Invitation to join conference */
302 if (g_str_has_prefix(content_type, "application/ms-conf-invite+xml")) {
303 process_incoming_invite_conf(sipe_private, msg);
304 return;
307 #ifdef HAVE_VV
308 /* Invitation to audio call */
309 if (msg->body && strstr(msg->body, "m=audio")) {
310 process_incoming_invite_call(sipe_private, msg);
311 return;
313 #endif
315 /* Only accept text invitations */
316 if (msg->body && !(strstr(msg->body, "m=message") || strstr(msg->body, "m=x-ms-message"))) {
317 sip_transport_response(sipe_private, msg, 501, "Not implemented", NULL);
318 return;
321 // TODO There *must* be a better way to clean up the To header to add a tag...
322 SIPE_DEBUG_INFO_NOFORMAT("Adding a Tag to the To Header on Invite Request...");
323 oldHeader = sipmsg_find_header(msg, "To");
324 newTag = gentag();
325 newHeader = g_strdup_printf("%s;tag=%s", oldHeader, newTag);
326 sipmsg_remove_header_now(msg, "To");
327 sipmsg_add_header_now(msg, "To", newHeader);
328 g_free(newHeader);
330 if (end_points_hdr) {
331 end_points = sipmsg_parse_endpoints_header(end_points_hdr);
333 if (g_slist_length(end_points) > 2) {
334 is_multiparty = TRUE;
337 if (trig_invite && !g_strcasecmp(trig_invite, "TRUE")) {
338 is_triggered = TRUE;
339 is_multiparty = TRUE;
342 /* Multiparty session */
343 session = sipe_session_find_chat_by_callid(sipe_private, callid);
344 if (is_multiparty) {
346 if (session) {
347 if (session->chat_session) {
348 /* Update roster manager for existing multiparty session */
349 if (roster_manager)
350 sipe_chat_set_roster_manager(session, roster_manager);
352 } else {
353 gchar *chat_title = sipe_chat_get_name();
355 /* Convert IM session to multiparty session */
356 g_free(session->with);
357 session->with = NULL;
358 was_multiparty = FALSE;
359 session->chat_session = sipe_chat_create_session(SIPE_CHAT_TYPE_MULTIPARTY,
360 roster_manager,
361 chat_title);
363 g_free(chat_title);
365 } else {
366 /* New multiparty session */
367 session = sipe_session_add_chat(sipe_private,
368 NULL,
369 TRUE,
370 roster_manager);
373 /* Create chat */
374 if (!session->chat_session->backend) {
375 gchar *self = sip_uri_self(sipe_private);
376 session->chat_session->backend = sipe_backend_chat_create(SIPE_CORE_PUBLIC,
377 session->chat_session,
378 session->chat_session->title,
379 self);
380 g_free(self);
384 /* IM session */
385 from = parse_from(sipmsg_find_header(msg, "From"));
386 if (!session)
387 session = sipe_session_find_or_add_im(sipe_private, from);
389 /* session is now initialized */
390 g_free(session->callid);
391 session->callid = g_strdup(callid);
393 if (is_multiparty && end_points) {
394 gchar *to = parse_from(sipmsg_find_header(msg, "To"));
395 GSList *entry = end_points;
396 while (entry) {
397 struct sipendpoint *end_point = entry->data;
398 entry = entry->next;
400 if (!g_strcasecmp(from, end_point->contact) ||
401 !g_strcasecmp(to, end_point->contact))
402 continue;
404 dialog = sipe_dialog_find(session, end_point->contact);
405 if (dialog) {
406 g_free(dialog->theirepid);
407 dialog->theirepid = end_point->epid;
408 end_point->epid = NULL;
409 } else {
410 dialog = sipe_dialog_add(session);
412 dialog->callid = g_strdup(session->callid);
413 dialog->with = end_point->contact;
414 end_point->contact = NULL;
415 dialog->theirepid = end_point->epid;
416 end_point->epid = NULL;
418 just_joined = TRUE;
420 /* send triggered INVITE */
421 sipe_invite(sipe_private, session, dialog->with, NULL, NULL, NULL, TRUE);
424 g_free(to);
427 if (end_points) {
428 GSList *entry = end_points;
429 while (entry) {
430 struct sipendpoint *end_point = entry->data;
431 entry = entry->next;
432 g_free(end_point->contact);
433 g_free(end_point->epid);
434 g_free(end_point);
436 g_slist_free(end_points);
439 dialog = sipe_dialog_find(session, from);
440 if (dialog) {
441 /* update existing dialog */
442 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_invite, session already has dialog!");
443 g_free(dialog->callid);
444 dialog->callid = g_strdup(session->callid);
445 sipe_dialog_parse_routes(dialog, msg, FALSE);
446 } else {
447 dialog = sipe_dialog_add(session);
449 dialog->callid = g_strdup(session->callid);
450 dialog->with = g_strdup(from);
451 sipe_dialog_parse(dialog, msg, FALSE);
453 if (!dialog->ourtag) {
454 dialog->ourtag = newTag;
455 newTag = NULL;
458 just_joined = TRUE;
460 g_free(newTag);
462 if (is_multiparty && !was_multiparty) {
463 /* add current IM counterparty to chat */
464 sipe_backend_chat_add(session->chat_session->backend,
465 sipe_dialog_first(session)->with,
466 FALSE);
469 /* add inviting party to chat */
470 if (just_joined && session->chat_session) {
471 sipe_backend_chat_add(session->chat_session->backend,
472 from,
473 TRUE);
476 /* ms-text-format: text/plain; charset=UTF-8;msgr=WAAtAE0...DIADQAKAA0ACgA;ms-body=SGk= */
478 /* This used only in 2005 official client, not 2007 or Reuters.
479 Disabled for most cases as interfering with audit of messages which only is applied to regular MESSAGEs.
480 Only enabled for 2005 multiparty chats as otherwise the first message got lost completely.
482 /* also enabled for 2005 file transfer. Didn't work otherwise. */
483 ms_text_format = sipmsg_find_header(msg, "ms-text-format");
484 if (is_multiparty ||
485 (ms_text_format && g_str_has_prefix(ms_text_format, "text/x-msmsgsinvite")) )
487 if (ms_text_format) {
488 if (g_str_has_prefix(ms_text_format, "text/x-msmsgsinvite"))
490 gchar *tmp = sipmsg_find_part_of_header(ms_text_format, "ms-body=", NULL, NULL);
491 if (tmp) {
492 gsize len;
493 gchar *body = (gchar *) g_base64_decode(tmp, &len);
494 GSList *parsed_body = sipe_ft_parse_msg_body(body);
496 dialog = sipe_dialog_find(session, from);
497 sipe_process_incoming_x_msmsgsinvite(sipe_private, dialog, parsed_body);
498 sipe_utils_nameval_free(parsed_body);
499 sipmsg_add_header(msg, "Supported", "ms-text-format"); /* accepts received message */
501 g_free(tmp);
503 else if (g_str_has_prefix(ms_text_format, "text/plain") || g_str_has_prefix(ms_text_format, "text/html"))
505 /* please do not optimize logic inside as this code may be re-enabled for other cases */
506 gchar *html = get_html_message(ms_text_format, NULL);
507 if (html) {
508 if (is_multiparty) {
509 sipe_backend_chat_message(SIPE_CORE_PUBLIC,
510 session->chat_session->backend,
511 from,
512 html);
513 } else {
514 sipe_backend_im_message(SIPE_CORE_PUBLIC,
515 from,
516 html);
518 g_free(html);
519 sipmsg_add_header(msg, "Supported", "ms-text-format"); /* accepts received message */
525 g_free(from);
527 sipmsg_add_header(msg, "Supported", "com.microsoft.rtc-multiparty");
528 sipmsg_add_header(msg, "Content-Type", "application/sdp");
530 body = g_strdup_printf(
531 "v=0\r\n"
532 "o=- 0 0 IN IP4 %s\r\n"
533 "s=session\r\n"
534 "c=IN IP4 %s\r\n"
535 "t=0 0\r\n"
536 "m=%s %d sip sip:%s\r\n"
537 "a=accept-types:" SDP_ACCEPT_TYPES "\r\n",
538 sipe_backend_network_ip_address(),
539 sipe_backend_network_ip_address(),
540 SIPE_CORE_PRIVATE_FLAG_IS(OCS2007) ? "message" : "x-ms-message",
541 sip_transport_port(sipe_private),
542 sipe_private->username);
543 sip_transport_response(sipe_private, msg, 200, "OK", body);
544 g_free(body);
547 void process_incoming_message(struct sipe_core_private *sipe_private,
548 struct sipmsg *msg)
550 gchar *from;
551 const gchar *contenttype;
552 gboolean found = FALSE;
554 from = parse_from(sipmsg_find_header(msg, "From"));
556 if (!from) return;
558 SIPE_DEBUG_INFO("got message from %s: %s", from, msg->body);
560 contenttype = sipmsg_find_header(msg, "Content-Type");
561 if (g_str_has_prefix(contenttype, "text/plain")
562 || g_str_has_prefix(contenttype, "text/html")
563 || g_str_has_prefix(contenttype, "multipart/related")
564 || g_str_has_prefix(contenttype, "multipart/alternative"))
566 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
567 gchar *html = get_html_message(contenttype, msg->body);
569 struct sip_session *session = sipe_session_find_chat_or_im(sipe_private,
570 callid,
571 from);
572 if (session && session->chat_session) {
573 if (session->chat_session->type == SIPE_CHAT_TYPE_CONFERENCE) { /* a conference */
574 gchar *tmp = parse_from(sipmsg_find_header(msg, "Ms-Sender"));
575 gchar *sender = parse_from(tmp);
576 g_free(tmp);
577 sipe_backend_chat_message(SIPE_CORE_PUBLIC,
578 session->chat_session->backend,
579 sender,
580 html);
581 g_free(sender);
582 } else { /* a multiparty chat */
583 sipe_backend_chat_message(SIPE_CORE_PUBLIC,
584 session->chat_session->backend,
585 from,
586 html);
588 } else {
589 sipe_backend_im_message(SIPE_CORE_PUBLIC,
590 from,
591 html);
593 g_free(html);
594 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
595 found = TRUE;
597 } else if (g_str_has_prefix(contenttype, "application/im-iscomposing+xml")) {
598 sipe_xml *isc = sipe_xml_parse(msg->body, msg->bodylen);
599 const sipe_xml *state;
600 gchar *statedata;
602 if (!isc) {
603 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_message: can not parse iscomposing");
604 g_free(from);
605 return;
608 state = sipe_xml_child(isc, "state");
610 if (!state) {
611 SIPE_DEBUG_INFO_NOFORMAT("process_incoming_message: no state found");
612 sipe_xml_free(isc);
613 g_free(from);
614 return;
617 statedata = sipe_xml_data(state);
618 if (statedata) {
619 if (strstr(statedata, "active")) {
620 sipe_backend_user_feedback_typing(SIPE_CORE_PUBLIC,
621 from);
622 } else {
623 sipe_backend_user_feedback_typing_stop(SIPE_CORE_PUBLIC,
624 from);
626 g_free(statedata);
628 sipe_xml_free(isc);
629 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
630 found = TRUE;
631 } else if (g_str_has_prefix(contenttype, "text/x-msmsgsinvite")) {
632 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
633 struct sip_session *session = sipe_session_find_chat_or_im(sipe_private,
634 callid,
635 from);
636 struct sip_dialog *dialog = sipe_dialog_find(session, from);
637 GSList *body = sipe_ft_parse_msg_body(msg->body);
638 found = sipe_process_incoming_x_msmsgsinvite(sipe_private, dialog, body);
639 sipe_utils_nameval_free(body);
640 if (found) {
641 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
644 if (!found) {
645 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
646 struct sip_session *session = sipe_session_find_chat_or_im(sipe_private,
647 callid,
648 from);
649 if (session) {
650 gchar *errmsg = g_strdup_printf(_("Received a message with unrecognized contents from %s"),
651 from);
652 sipe_present_err(sipe_private, session, errmsg);
653 g_free(errmsg);
656 SIPE_DEBUG_INFO("got unknown mime-type '%s'", contenttype);
657 sip_transport_response(sipe_private, msg, 415, "Unsupported media type", NULL);
659 g_free(from);
662 void process_incoming_options(struct sipe_core_private *sipe_private,
663 struct sipmsg *msg)
665 gchar *body;
667 sipmsg_add_header(msg, "Allow", "INVITE, MESSAGE, INFO, SUBSCRIBE, OPTIONS, BYE, CANCEL, NOTIFY, ACK, REFER, BENOTIFY");
668 sipmsg_add_header(msg, "Content-Type", "application/sdp");
670 body = g_strdup_printf(
671 "v=0\r\n"
672 "o=- 0 0 IN IP4 0.0.0.0\r\n"
673 "s=session\r\n"
674 "c=IN IP4 0.0.0.0\r\n"
675 "t=0 0\r\n"
676 "m=%s %d sip sip:%s\r\n"
677 "a=accept-types:" SDP_ACCEPT_TYPES "\r\n",
678 SIPE_CORE_PRIVATE_FLAG_IS(OCS2007) ? "message" : "x-ms-message",
679 sip_transport_port(sipe_private),
680 sipe_private->username);
681 sip_transport_response(sipe_private, msg, 200, "OK", body);
682 g_free(body);
685 void process_incoming_refer(struct sipe_core_private *sipe_private,
686 struct sipmsg *msg)
688 gchar *self = sip_uri_self(sipe_private);
689 const gchar *callid = sipmsg_find_header(msg, "Call-ID");
690 gchar *from = parse_from(sipmsg_find_header(msg, "From"));
691 gchar *refer_to = parse_from(sipmsg_find_header(msg, "Refer-to"));
692 gchar *referred_by = g_strdup(sipmsg_find_header(msg, "Referred-By"));
693 struct sip_session *session;
694 struct sip_dialog *dialog;
696 session = sipe_session_find_chat_by_callid(sipe_private, callid);
697 dialog = sipe_dialog_find(session, from);
699 if (!session || !dialog || !session->chat_session ||
700 (session->chat_session->type != SIPE_CHAT_TYPE_MULTIPARTY) ||
701 !session->chat_session->id ||
702 !sipe_strcase_equal(session->chat_session->id, self)) {
703 sip_transport_response(sipe_private, msg, 500, "Server Internal Error", NULL);
704 } else {
705 sip_transport_response(sipe_private, msg, 202, "Accepted", NULL);
707 sipe_invite(sipe_private, session, refer_to, NULL, NULL, referred_by, FALSE);
710 g_free(self);
711 g_free(from);
712 g_free(refer_to);
713 g_free(referred_by);
717 Local Variables:
718 mode: c
719 c-file-style: "bsd"
720 indent-tabs-mode: t
721 tab-width: 8
722 End: