webticket: cache ADFS token
[siplcs.git] / src / core / sip-csta.c
blob08de83c775d2b0014e8afac5719af02e28f598ce
1 /**
2 * @file sip-csta.c
4 * pidgin-sipe
6 * Copyright (C) 2010-11 SIPE Project <http://sipe.sourceforge.net/>
7 * Copyright (C) 2009 pier11 <pier11@operamail.com>
9 * Implements Remote Call Control (RCC) feature for
10 * integration with legacy enterprise PBX (wired telephony) systems.
11 * Should be applicable to 2005 and 2007(R2) systems.
12 * Inderlying XML protocol CSTA is defined in ECMA-323.
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #include <stdlib.h>
31 #include <string.h>
32 #include <time.h>
34 #include <glib.h>
36 #include "sipe-common.h"
37 #include "sipmsg.h"
38 #include "sip-csta.h"
39 #include "sip-transport.h"
40 #include "sipe-backend.h"
41 #include "sipe-core.h"
42 #include "sipe-core-private.h"
43 #include "sipe-dialog.h"
44 #include "sipe-schedule.h"
45 #include "sipe-utils.h"
46 #include "sipe-xml.h"
48 #define ORIGINATED_CSTA_STATUS "originated"
49 #define DELIVERED_CSTA_STATUS "delivered"
50 #define ESTABLISHED_CSTA_STATUS "established"
52 /**
53 * Data model for interaction with SIP/CSTA Gateway
55 struct sip_csta {
56 gchar *line_uri;
57 /** SIP/CSTA Gateway's SIP URI */
58 gchar *gateway_uri;
59 /** dialog with SIP/CSTA Gateway */
60 struct sip_dialog *dialog;
62 gchar *gateway_status;
63 gchar *monitor_cross_ref_id;
65 gchar *line_status;
66 /** destination tel: URI */
67 gchar *to_tel_uri;
68 gchar *call_id;
69 /* our device ID as reported by SIP/CSTA gateway */
70 gchar *device_id;
73 /**
74 * Sends CSTA RequestSystemStatus request to SIP/CSTA Gateway.
75 * @param line_uri (%s) Ex.: tel:73124;phone-context=dialstring;partition=BE_BRS_INT
77 #define SIP_SEND_CSTA_REQUEST_SYSTEM_STATUS \
78 "<?xml version=\"1.0\"?>"\
79 "<RequestSystemStatus xmlns=\"http://www.ecma-international.org/standards/ecma-323/csta/ed3\">"\
80 "<extensions>"\
81 "<privateData>"\
82 "<private>"\
83 "<lcs:line xmlns:lcs=\"http://schemas.microsoft.com/Lcs/2005/04/RCCExtension\">%s</lcs:line>"\
84 "</private>"\
85 "</privateData>"\
86 "</extensions>"\
87 "</RequestSystemStatus>"
89 /**
90 * Sends CSTA GetCSTAFeatures request to SIP/CSTA Gateway.
91 * @param line_uri (%s) Ex.: tel:73124;phone-context=dialstring;partition=BE_BRS_INT
93 #define SIP_SEND_CSTA_GET_CSTA_FEATURES \
94 "<?xml version=\"1.0\"?>"\
95 "<GetCSTAFeatures xmlns=\"http://www.ecma-international.org/standards/ecma-323/csta/ed3\">"\
96 "<extensions>"\
97 "<privateData>"\
98 "<private>"\
99 "<lcs:line xmlns:lcs=\"http://schemas.microsoft.com/Lcs/2005/04/RCCExtension\">%s</lcs:line>"\
100 "</private>"\
101 "</privateData>"\
102 "</extensions>"\
103 "</GetCSTAFeatures>"
106 * Sends CSTA start monitor request to SIP/CSTA Gateway.
107 * @param line_uri (%s) Ex.: tel:73124;phone-context=dialstring;partition=BE_BRS_INT
109 #define SIP_SEND_CSTA_MONITOR_START \
110 "<?xml version=\"1.0\"?>"\
111 "<MonitorStart xmlns=\"http://www.ecma-international.org/standards/ecma-323/csta/ed3\">"\
112 "<monitorObject>"\
113 "<deviceObject>%s</deviceObject>"\
114 "</monitorObject>"\
115 "</MonitorStart>"
118 * Sends CSTA stop monitor request to SIP/CSTA Gateway.
119 * @param monitor_cross_ref_id (%s) Ex.: 99fda87c
121 #define SIP_SEND_CSTA_MONITOR_STOP \
122 "<?xml version=\"1.0\"?>"\
123 "<MonitorStop xmlns=\"http://www.ecma-international.org/standards/ecma-323/csta/ed3\">"\
124 "<monitorCrossRefID>%s</monitorCrossRefID>"\
125 "</MonitorStop>"
128 * Sends CSTA make call request to SIP/CSTA Gateway.
129 * @param line_uri (%s) Ex.: tel:73124;phone-context=dialstring;partition=BE_BRS_INT
130 * @param to_tel_uri (%s) Ex.: tel:+3222220220
132 #define SIP_SEND_CSTA_MAKE_CALL \
133 "<?xml version=\"1.0\"?>"\
134 "<MakeCall xmlns=\"http://www.ecma-international.org/standards/ecma-323/csta/ed3\">"\
135 "<callingDevice>%s</callingDevice>"\
136 "<calledDirectoryNumber>%s</calledDirectoryNumber>"\
137 "<autoOriginate>doNotPrompt</autoOriginate>"\
138 "</MakeCall>"
141 * Sends CSTA ClearConnection request to SIP/CSTA Gateway.
142 * @param call_id (%s) Ex.: 0_99f261b4
143 * @param device_id (%s) Same as in OriginatedEvent, DeliveredEvent notifications.
144 * Ex.: tel:73124;phone-context=dialstring
146 #define SIP_SEND_CSTA_CLEAR_CONNECTION \
147 "<?xml version=\"1.0\"?>"\
148 "<ClearConnection xmlns=\"http://www.ecma-international.org/standards/ecma-323/csta/ed3\">"\
149 "<connectionToBeCleared>"\
150 "<callID>%s</callID>"\
151 "<deviceID>%s</deviceID>"\
152 "</connectionToBeCleared>"\
153 "</ClearConnection>"
156 static gchar *
157 sip_to_tel_uri0(const gchar *phone)
159 if (!phone || strlen(phone) == 0) return NULL;
161 if (g_str_has_prefix(phone, "tel:")) {
162 return g_strdup(phone);
163 } else {
164 gchar *tel_uri = g_malloc(strlen(phone) + 4 + 1);
165 gchar *dest_p = g_stpcpy(tel_uri, "tel:");
166 for (; *phone; phone++) {
167 if (*phone == ' ') continue;
168 if (*phone == '(') continue;
169 if (*phone == ')') continue;
170 if (*phone == '-') continue;
171 if (*phone == '.') continue;
172 *dest_p++ = *phone;
174 *dest_p = '\0';
175 return tel_uri;
179 gchar *
180 sip_to_tel_uri(const gchar *phone)
182 gchar *res = sip_to_tel_uri0(phone);
183 gchar *v;
184 /* strips everything starting with 'v:' if any */
185 if (res && (v = strstr(res, "v:"))) {
186 gchar *tmp = res;
188 res = g_strndup(res, v - res);
189 g_free(tmp);
190 return res;
192 return res;
195 gchar *
196 sip_tel_uri_denormalize(const gchar *tel_uri)
198 if (!tel_uri) return NULL;
200 if (g_str_has_prefix(tel_uri, "tel:")) {
201 return g_strdup(tel_uri + 4);
202 } else {
203 return g_strdup(tel_uri);
207 static void
208 sip_csta_initialize(struct sipe_core_private *sipe_private,
209 const gchar *line_uri,
210 const gchar *server)
212 if(!sipe_private->csta) {
213 sipe_private->csta = g_new0(struct sip_csta, 1);
214 sipe_private->csta->line_uri = g_strdup(line_uri);
215 sipe_private->csta->gateway_uri = g_strdup(server);
216 } else {
217 SIPE_DEBUG_INFO_NOFORMAT("sip_csta_initialize: sipe_private->csta is already instantiated, exiting.");
221 /** get CSTA feautures's callback */
222 static gboolean
223 process_csta_get_features_response(SIPE_UNUSED_PARAMETER struct sipe_core_private *sipe_private,
224 struct sipmsg *msg,
225 SIPE_UNUSED_PARAMETER struct transaction *trans)
227 if (msg->response >= 400) {
228 SIPE_DEBUG_INFO_NOFORMAT("process_csta_get_features_response: Get CSTA features response is not 200. Failed to get features.");
229 /* @TODO notify user of failure to get CSTA features */
230 return FALSE;
232 else if (msg->response == 200) {
233 SIPE_DEBUG_INFO("process_csta_get_features_response:\n%s", msg->body ? msg->body : "");
236 return TRUE;
239 /** get CSTA feautures */
240 static void
241 sip_csta_get_features(struct sipe_core_private *sipe_private)
243 gchar *hdr;
244 gchar *body;
246 if (!sipe_private->csta || !sipe_private->csta->dialog || !sipe_private->csta->dialog->is_established) {
247 SIPE_DEBUG_INFO_NOFORMAT("sip_csta_get_features: no dialog with CSTA, exiting.");
248 return;
251 hdr = g_strdup(
252 "Content-Disposition: signal;handling=required\r\n"
253 "Content-Type: application/csta+xml\r\n");
255 body = g_strdup_printf(
256 SIP_SEND_CSTA_GET_CSTA_FEATURES,
257 sipe_private->csta->line_uri);
259 sip_transport_info(sipe_private,
260 hdr,
261 body,
262 sipe_private->csta->dialog,
263 process_csta_get_features_response);
264 g_free(body);
265 g_free(hdr);
268 /** Monitor Start's callback */
269 static gboolean
270 process_csta_monitor_start_response(struct sipe_core_private *sipe_private,
271 struct sipmsg *msg,
272 SIPE_UNUSED_PARAMETER struct transaction *trans)
274 SIPE_DEBUG_INFO("process_csta_monitor_start_response:\n%s", msg->body ? msg->body : "");
276 if (!sipe_private->csta) {
277 SIPE_DEBUG_INFO_NOFORMAT("process_csta_monitor_start_response: sipe_private->csta is not initializzed, exiting");
278 return FALSE;
281 if (msg->response >= 400) {
282 SIPE_DEBUG_INFO_NOFORMAT("process_csta_monitor_start_response: Monitor Start response is not 200. Failed to start monitor.");
283 /* @TODO notify user of failure to start monitor */
284 return FALSE;
286 else if (msg->response == 200) {
287 sipe_xml *xml = sipe_xml_parse(msg->body, msg->bodylen);
288 g_free(sipe_private->csta->monitor_cross_ref_id);
289 sipe_private->csta->monitor_cross_ref_id = sipe_xml_data(sipe_xml_child(xml, "monitorCrossRefID"));
290 SIPE_DEBUG_INFO("process_csta_monitor_start_response: monitor_cross_ref_id=%s",
291 sipe_private->csta->monitor_cross_ref_id ? sipe_private->csta->monitor_cross_ref_id : "");
292 sipe_xml_free(xml);
295 return TRUE;
298 /** Monitor Start */
299 static void
300 sip_csta_monitor_start(struct sipe_core_private *sipe_private)
302 gchar *hdr;
303 gchar *body;
305 if (!sipe_private->csta || !sipe_private->csta->dialog || !sipe_private->csta->dialog->is_established) {
306 SIPE_DEBUG_INFO_NOFORMAT("sip_csta_monitor_start: no dialog with CSTA, exiting.");
307 return;
310 hdr = g_strdup(
311 "Content-Disposition: signal;handling=required\r\n"
312 "Content-Type: application/csta+xml\r\n");
314 body = g_strdup_printf(
315 SIP_SEND_CSTA_MONITOR_START,
316 sipe_private->csta->line_uri);
318 sip_transport_info(sipe_private,
319 hdr,
320 body,
321 sipe_private->csta->dialog,
322 process_csta_monitor_start_response);
323 g_free(body);
324 g_free(hdr);
327 /** Monitor Stop */
328 static void
329 sip_csta_monitor_stop(struct sipe_core_private *sipe_private)
331 gchar *hdr;
332 gchar *body;
334 if (!sipe_private->csta || !sipe_private->csta->dialog || !sipe_private->csta->dialog->is_established) {
335 SIPE_DEBUG_INFO_NOFORMAT("sip_csta_monitor_stop: no dialog with CSTA, exiting.");
336 return;
339 if (!sipe_private->csta->monitor_cross_ref_id) {
340 SIPE_DEBUG_INFO_NOFORMAT("sip_csta_monitor_stop: no monitor_cross_ref_id, exiting.");
341 return;
344 hdr = g_strdup(
345 "Content-Disposition: signal;handling=required\r\n"
346 "Content-Type: application/csta+xml\r\n");
348 body = g_strdup_printf(
349 SIP_SEND_CSTA_MONITOR_STOP,
350 sipe_private->csta->monitor_cross_ref_id);
352 sip_transport_info(sipe_private,
353 hdr,
354 body,
355 sipe_private->csta->dialog,
356 NULL);
357 g_free(body);
358 g_free(hdr);
361 static void
362 sipe_invite_csta_gateway(struct sipe_core_private *sipe_private,
363 gpointer unused);
365 /** a callback */
366 static gboolean
367 process_invite_csta_gateway_response(struct sipe_core_private *sipe_private,
368 struct sipmsg *msg,
369 SIPE_UNUSED_PARAMETER struct transaction *trans)
371 SIPE_DEBUG_INFO("process_invite_csta_gateway_response:\n%s", msg->body ? msg->body : "");
373 if (!sipe_private->csta) {
374 SIPE_DEBUG_INFO_NOFORMAT("process_invite_csta_gateway_response: sipe_private->csta is not initializzed, exiting");
375 return FALSE;
378 if (!sipe_private->csta->dialog) {
379 SIPE_DEBUG_INFO_NOFORMAT("process_invite_csta_gateway_response: GSTA dialog is NULL, exiting");
380 return FALSE;
383 sipe_dialog_parse(sipe_private->csta->dialog, msg, TRUE);
385 if (msg->response >= 200) {
386 /* send ACK to CSTA */
387 sipe_private->csta->dialog->cseq = 0;
388 sip_transport_ack(sipe_private, sipe_private->csta->dialog);
389 sipe_private->csta->dialog->outgoing_invite = NULL;
390 sipe_private->csta->dialog->is_established = TRUE;
393 if (msg->response >= 400) {
394 SIPE_DEBUG_INFO_NOFORMAT("process_invite_csta_gateway_response: INVITE response is not 200. Failed to join CSTA.");
395 /* @TODO notify user of failure to join CSTA */
396 return FALSE;
398 else if (msg->response == 200) {
399 sipe_xml *xml = sipe_xml_parse(msg->body, msg->bodylen);
401 g_free(sipe_private->csta->gateway_status);
402 sipe_private->csta->gateway_status = sipe_xml_data(sipe_xml_child(xml, "systemStatus"));
403 SIPE_DEBUG_INFO("process_invite_csta_gateway_response: gateway_status=%s",
404 sipe_private->csta->gateway_status ? sipe_private->csta->gateway_status : "");
405 if (sipe_strcase_equal(sipe_private->csta->gateway_status, "normal")) {
406 if (!sipe_private->csta->monitor_cross_ref_id) {
407 sip_csta_get_features(sipe_private);
408 sip_csta_monitor_start(sipe_private);
410 } else {
411 SIPE_DEBUG_INFO("process_invite_csta_gateway_response: ERROR: CSTA status is %s, won't continue.",
412 sipe_private->csta->gateway_status);
413 /* @TODO notify user of failure to join CSTA */
415 sipe_xml_free(xml);
417 /* schedule re-invite. RFC4028 */
418 if (sipe_private->csta->dialog->expires) {
419 sipe_schedule_seconds(sipe_private,
420 "<+csta>",
421 NULL,
422 sipe_private->csta->dialog->expires - 60, /* 1 minute earlier */
423 sipe_invite_csta_gateway,
424 NULL);
428 return TRUE;
431 /** Creates long living dialog with SIP/CSTA Gateway */
432 /* should be re-entrant as require to sent re-invites every 10 min to refresh */
433 static void
434 sipe_invite_csta_gateway(struct sipe_core_private *sipe_private,
435 SIPE_UNUSED_PARAMETER gpointer unused)
437 gchar *hdr;
438 gchar *contact;
439 gchar *body;
441 if (!sipe_private->csta) {
442 SIPE_DEBUG_INFO_NOFORMAT("sipe_invite_csta_gateway: sipe_private->csta is uninitialized, exiting");
443 return;
446 if(!sipe_private->csta->dialog) {
447 sipe_private->csta->dialog = g_new0(struct sip_dialog, 1);
448 sipe_private->csta->dialog->callid = gencallid();
449 sipe_private->csta->dialog->with = g_strdup(sipe_private->csta->gateway_uri);
451 if (!(sipe_private->csta->dialog->ourtag)) {
452 sipe_private->csta->dialog->ourtag = gentag();
455 contact = get_contact(sipe_private);
456 hdr = g_strdup_printf(
457 "Contact: %s\r\n"
458 "Supported: timer\r\n"
459 "Content-Disposition: signal;handling=required\r\n"
460 "Content-Type: application/csta+xml\r\n",
461 contact);
462 g_free(contact);
464 body = g_strdup_printf(
465 SIP_SEND_CSTA_REQUEST_SYSTEM_STATUS,
466 sipe_private->csta->line_uri);
468 sipe_private->csta->dialog->outgoing_invite =
469 sip_transport_invite(sipe_private,
470 hdr,
471 body,
472 sipe_private->csta->dialog,
473 process_invite_csta_gateway_response);
474 g_free(body);
475 g_free(hdr);
478 void
479 sip_csta_open(struct sipe_core_private *sipe_private,
480 const gchar *line_uri,
481 const gchar *server)
483 sip_csta_initialize(sipe_private, line_uri, server);
484 sipe_invite_csta_gateway(sipe_private, NULL);
487 static void
488 sip_csta_free(struct sip_csta *csta)
490 if (!csta) return;
492 g_free(csta->line_uri);
493 g_free(csta->gateway_uri);
495 sipe_dialog_free(csta->dialog);
497 g_free(csta->gateway_status);
498 g_free(csta->monitor_cross_ref_id);
499 g_free(csta->line_status);
500 g_free(csta->to_tel_uri);
501 g_free(csta->call_id);
502 g_free(csta->device_id);
504 g_free(csta);
507 void
508 sip_csta_close(struct sipe_core_private *sipe_private)
510 if (sipe_private->csta) {
511 sip_csta_monitor_stop(sipe_private);
514 if (sipe_private->csta && sipe_private->csta->dialog) {
515 /* send BYE to CSTA */
516 sip_transport_bye(sipe_private, sipe_private->csta->dialog);
519 sip_csta_free(sipe_private->csta);
524 /** Make Call's callback */
525 static gboolean
526 process_csta_make_call_response(struct sipe_core_private *sipe_private,
527 struct sipmsg *msg,
528 SIPE_UNUSED_PARAMETER struct transaction *trans)
530 SIPE_DEBUG_INFO("process_csta_make_call_response:\n%s", msg->body ? msg->body : "");
532 if (!sipe_private->csta) {
533 SIPE_DEBUG_INFO_NOFORMAT("process_csta_make_call_response: sipe_private->csta is not initializzed, exiting");
534 return FALSE;
537 if (msg->response >= 400) {
538 SIPE_DEBUG_INFO_NOFORMAT("process_csta_make_call_response: Make Call response is not 200. Failed to make call.");
539 /* @TODO notify user of failure to make call */
540 return FALSE;
542 else if (msg->response == 200) {
543 sipe_xml *xml;
544 const sipe_xml *xn_calling_device;
545 gchar *device_id;
547 SIPE_DEBUG_INFO_NOFORMAT("process_csta_make_call_response: SUCCESS");
549 xml = sipe_xml_parse(msg->body, msg->bodylen);
550 xn_calling_device = sipe_xml_child(xml, "callingDevice");
551 device_id = sipe_xml_data(sipe_xml_child(xn_calling_device, "deviceID"));
552 if (sipe_strequal(sipe_private->csta->line_uri, device_id)) {
553 g_free(sipe_private->csta->call_id);
554 sipe_private->csta->call_id = sipe_xml_data(sipe_xml_child(xn_calling_device, "callID"));
555 SIPE_DEBUG_INFO("process_csta_make_call_response: call_id=%s", sipe_private->csta->call_id ? sipe_private->csta->call_id : "");
557 g_free(device_id);
558 sipe_xml_free(xml);
561 return TRUE;
564 /** Make Call */
565 static void sip_csta_make_call(struct sipe_core_private *sipe_private,
566 const gchar* to_tel_uri)
568 gchar *hdr;
569 gchar *body;
571 if (!to_tel_uri) {
572 SIPE_DEBUG_INFO_NOFORMAT("sip_csta_make_call: no tel URI parameter provided, exiting.");
573 return;
576 if (!sipe_private->csta || !sipe_private->csta->dialog || !sipe_private->csta->dialog->is_established) {
577 SIPE_DEBUG_INFO_NOFORMAT("sip_csta_make_call: no dialog with CSTA, exiting.");
578 return;
581 g_free(sipe_private->csta->to_tel_uri);
582 sipe_private->csta->to_tel_uri = g_strdup(to_tel_uri);
584 hdr = g_strdup(
585 "Content-Disposition: signal;handling=required\r\n"
586 "Content-Type: application/csta+xml\r\n");
588 body = g_strdup_printf(
589 SIP_SEND_CSTA_MAKE_CALL,
590 sipe_private->csta->line_uri,
591 sipe_private->csta->to_tel_uri);
593 sip_transport_info(sipe_private,
594 hdr,
595 body,
596 sipe_private->csta->dialog,
597 process_csta_make_call_response);
598 g_free(body);
599 g_free(hdr);
602 static void
603 sip_csta_update_id_and_status(struct sip_csta *csta,
604 const sipe_xml *node,
605 const char *status)
607 gchar *call_id = sipe_xml_data(sipe_xml_child(node, "callID"));
609 if (!sipe_strequal(call_id, csta->call_id)) {
610 SIPE_DEBUG_INFO("sipe_csta_update_id_and_status: callID (%s) does not match", call_id);
612 else
614 /* free old line status */
615 g_free(csta->line_status);
616 csta->line_status = NULL;
618 if (status)
620 /* save deviceID */
621 gchar *device_id = sipe_xml_data(sipe_xml_child(node, "deviceID"));
622 SIPE_DEBUG_INFO("sipe_csta_update_id_and_status: device_id=(%s)", device_id ? device_id : "");
623 if (device_id) {
624 g_free(csta->device_id);
625 csta->device_id = device_id;
628 /* set new line status */
629 csta->line_status = g_strdup(status);
631 else
633 /* clean up cleared connection */
634 g_free(csta->to_tel_uri);
635 csta->to_tel_uri = NULL;
636 g_free(csta->call_id);
637 csta->call_id = NULL;
638 g_free(csta->device_id);
639 csta->device_id = NULL;
643 g_free(call_id);
646 void
647 process_incoming_info_csta(struct sipe_core_private *sipe_private,
648 struct sipmsg *msg)
650 gchar *monitor_cross_ref_id;
651 sipe_xml *xml = sipe_xml_parse(msg->body, msg->bodylen);
653 if (!xml) return;
655 monitor_cross_ref_id = sipe_xml_data(sipe_xml_child(xml, "monitorCrossRefID"));
657 if(!sipe_private->csta || !sipe_strequal(monitor_cross_ref_id, sipe_private->csta->monitor_cross_ref_id))
659 SIPE_DEBUG_INFO("process_incoming_info_csta: monitorCrossRefID (%s) does not match, exiting",
660 monitor_cross_ref_id ? monitor_cross_ref_id : "");
662 else
664 if (sipe_strequal(sipe_xml_name(xml), "OriginatedEvent"))
666 sip_csta_update_id_and_status(sipe_private->csta,
667 sipe_xml_child(xml, "originatedConnection"),
668 ORIGINATED_CSTA_STATUS);
670 else if (sipe_strequal(sipe_xml_name(xml), "DeliveredEvent"))
672 sip_csta_update_id_and_status(sipe_private->csta,
673 sipe_xml_child(xml, "connection"),
674 DELIVERED_CSTA_STATUS);
676 else if (sipe_strequal(sipe_xml_name(xml), "EstablishedEvent"))
678 sip_csta_update_id_and_status(sipe_private->csta,
679 sipe_xml_child(xml, "establishedConnection"),
680 ESTABLISHED_CSTA_STATUS);
682 else if (sipe_strequal(sipe_xml_name(xml), "ConnectionClearedEvent"))
684 sip_csta_update_id_and_status(sipe_private->csta,
685 sipe_xml_child(xml, "droppedConnection"),
686 NULL);
690 g_free(monitor_cross_ref_id);
691 sipe_xml_free(xml);
694 gboolean sip_csta_is_idle(struct sipe_core_private *sipe_private)
696 return(sipe_private->csta && !sipe_private->csta->line_status);
699 void sipe_core_buddy_make_call(struct sipe_core_public *sipe_public,
700 const gchar *phone)
702 if (phone) {
703 gchar *tel_uri = sip_to_tel_uri(phone);
705 SIPE_DEBUG_INFO("sipe_core_buddy_make_call: calling number: %s",
706 tel_uri ? tel_uri : "");
707 sip_csta_make_call(SIPE_CORE_PRIVATE, tel_uri);
709 g_free(tel_uri);
714 Local Variables:
715 mode: c
716 c-file-style: "bsd"
717 indent-tabs-mode: t
718 tab-width: 8
719 End: