Fix sipe_buddy_menu_copy_to_cb when copying buddy not yet in our list
[siplcs.git] / src / core / sip-csta.c
blob1b5cc734430b607ddfc7c6b391ef91e18afe9654
1 /**
2 * @file sip-csta.c
4 * pidgin-sipe
6 * Copyright (C) 2010 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"
47 #include "sipe.h"
49 #define ORIGINATED_CSTA_STATUS "originated"
50 #define DELIVERED_CSTA_STATUS "delivered"
51 #define ESTABLISHED_CSTA_STATUS "established"
54 /**
55 * Sends CSTA RequestSystemStatus request to SIP/CSTA Gateway.
56 * @param line_uri (%s) Ex.: tel:73124;phone-context=dialstring;partition=BE_BRS_INT
58 #define SIP_SEND_CSTA_REQUEST_SYSTEM_STATUS \
59 "<?xml version=\"1.0\"?>"\
60 "<RequestSystemStatus xmlns=\"http://www.ecma-international.org/standards/ecma-323/csta/ed3\">"\
61 "<extensions>"\
62 "<privateData>"\
63 "<private>"\
64 "<lcs:line xmlns:lcs=\"http://schemas.microsoft.com/Lcs/2005/04/RCCExtension\">%s</lcs:line>"\
65 "</private>"\
66 "</privateData>"\
67 "</extensions>"\
68 "</RequestSystemStatus>"
70 /**
71 * Sends CSTA GetCSTAFeatures request to SIP/CSTA Gateway.
72 * @param line_uri (%s) Ex.: tel:73124;phone-context=dialstring;partition=BE_BRS_INT
74 #define SIP_SEND_CSTA_GET_CSTA_FEATURES \
75 "<?xml version=\"1.0\"?>"\
76 "<GetCSTAFeatures xmlns=\"http://www.ecma-international.org/standards/ecma-323/csta/ed3\">"\
77 "<extensions>"\
78 "<privateData>"\
79 "<private>"\
80 "<lcs:line xmlns:lcs=\"http://schemas.microsoft.com/Lcs/2005/04/RCCExtension\">%s</lcs:line>"\
81 "</private>"\
82 "</privateData>"\
83 "</extensions>"\
84 "</GetCSTAFeatures>"
86 /**
87 * Sends CSTA start monitor request to SIP/CSTA Gateway.
88 * @param line_uri (%s) Ex.: tel:73124;phone-context=dialstring;partition=BE_BRS_INT
90 #define SIP_SEND_CSTA_MONITOR_START \
91 "<?xml version=\"1.0\"?>"\
92 "<MonitorStart xmlns=\"http://www.ecma-international.org/standards/ecma-323/csta/ed3\">"\
93 "<monitorObject>"\
94 "<deviceObject>%s</deviceObject>"\
95 "</monitorObject>"\
96 "</MonitorStart>"
98 /**
99 * Sends CSTA stop monitor request to SIP/CSTA Gateway.
100 * @param monitor_cross_ref_id (%s) Ex.: 99fda87c
102 #define SIP_SEND_CSTA_MONITOR_STOP \
103 "<?xml version=\"1.0\"?>"\
104 "<MonitorStop xmlns=\"http://www.ecma-international.org/standards/ecma-323/csta/ed3\">"\
105 "<monitorCrossRefID>%s</monitorCrossRefID>"\
106 "</MonitorStop>"
109 * Sends CSTA make call request to SIP/CSTA Gateway.
110 * @param line_uri (%s) Ex.: tel:73124;phone-context=dialstring;partition=BE_BRS_INT
111 * @param to_tel_uri (%s) Ex.: tel:+3222220220
113 #define SIP_SEND_CSTA_MAKE_CALL \
114 "<?xml version=\"1.0\"?>"\
115 "<MakeCall xmlns=\"http://www.ecma-international.org/standards/ecma-323/csta/ed3\">"\
116 "<callingDevice>%s</callingDevice>"\
117 "<calledDirectoryNumber>%s</calledDirectoryNumber>"\
118 "<autoOriginate>doNotPrompt</autoOriginate>"\
119 "</MakeCall>"
122 * Sends CSTA ClearConnection request to SIP/CSTA Gateway.
123 * @param call_id (%s) Ex.: 0_99f261b4
124 * @param device_id (%s) Same as in OriginatedEvent, DeliveredEvent notifications.
125 * Ex.: tel:73124;phone-context=dialstring
127 #define SIP_SEND_CSTA_CLEAR_CONNECTION \
128 "<?xml version=\"1.0\"?>"\
129 "<ClearConnection xmlns=\"http://www.ecma-international.org/standards/ecma-323/csta/ed3\">"\
130 "<connectionToBeCleared>"\
131 "<callID>%s</callID>"\
132 "<deviceID>%s</deviceID>"\
133 "</connectionToBeCleared>"\
134 "</ClearConnection>"
137 static gchar *
138 sip_to_tel_uri0(const gchar *phone)
140 if (!phone || strlen(phone) == 0) return NULL;
142 if (g_str_has_prefix(phone, "tel:")) {
143 return g_strdup(phone);
144 } else {
145 gchar *tel_uri = g_malloc(strlen(phone) + 4 + 1);
146 gchar *dest_p = g_stpcpy(tel_uri, "tel:");
147 for (; *phone; phone++) {
148 if (*phone == ' ') continue;
149 if (*phone == '(') continue;
150 if (*phone == ')') continue;
151 if (*phone == '-') continue;
152 if (*phone == '.') continue;
153 *dest_p++ = *phone;
155 *dest_p = '\0';
156 return tel_uri;
160 gchar *
161 sip_to_tel_uri(const gchar *phone)
163 gchar *res = sip_to_tel_uri0(phone);
164 gchar *v;
165 /* strips everything starting with 'v:' if any */
166 if (res && (v = strstr(res, "v:"))) {
167 gchar *tmp = res;
169 res = g_strndup(res, v - res);
170 g_free(tmp);
171 return res;
173 return res;
176 gchar *
177 sip_tel_uri_denormalize(const gchar *tel_uri)
179 if (!tel_uri) return NULL;
181 if (g_str_has_prefix(tel_uri, "tel:")) {
182 return g_strdup(tel_uri + 4);
183 } else {
184 return g_strdup(tel_uri);
188 static void
189 sip_csta_initialize(struct sipe_core_private *sipe_private,
190 const gchar *line_uri,
191 const gchar *server)
193 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
194 if(!sip->csta) {
195 sip->csta = g_new0(struct sip_csta, 1);
196 sip->csta->line_uri = g_strdup(line_uri);
197 sip->csta->gateway_uri = g_strdup(server);
198 } else {
199 SIPE_DEBUG_INFO_NOFORMAT("sip_csta_initialize: sip->csta is already instantiated, exiting.");
203 /** get CSTA feautures's callback */
204 static gboolean
205 process_csta_get_features_response(SIPE_UNUSED_PARAMETER struct sipe_core_private *sipe_private,
206 struct sipmsg *msg,
207 SIPE_UNUSED_PARAMETER struct transaction *trans)
209 if (msg->response >= 400) {
210 SIPE_DEBUG_INFO_NOFORMAT("process_csta_get_features_response: Get CSTA features response is not 200. Failed to get features.");
211 /* @TODO notify user of failure to get CSTA features */
212 return FALSE;
214 else if (msg->response == 200) {
215 SIPE_DEBUG_INFO("process_csta_get_features_response:\n%s", msg->body ? msg->body : "");
218 return TRUE;
221 /** get CSTA feautures */
222 static void
223 sip_csta_get_features(struct sipe_core_private *sipe_private)
225 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
226 gchar *hdr;
227 gchar *body;
229 if (!sip->csta || !sip->csta->dialog || !sip->csta->dialog->is_established) {
230 SIPE_DEBUG_INFO_NOFORMAT("sip_csta_get_features: no dialog with CSTA, exiting.");
231 return;
234 hdr = g_strdup(
235 "Content-Disposition: signal;handling=required\r\n"
236 "Content-Type: application/csta+xml\r\n");
238 body = g_strdup_printf(
239 SIP_SEND_CSTA_GET_CSTA_FEATURES,
240 sip->csta->line_uri);
242 sip_transport_info(sipe_private,
243 hdr,
244 body,
245 sip->csta->dialog,
246 process_csta_get_features_response);
247 g_free(body);
248 g_free(hdr);
251 /** Monitor Start's callback */
252 static gboolean
253 process_csta_monitor_start_response(struct sipe_core_private *sipe_private,
254 struct sipmsg *msg,
255 SIPE_UNUSED_PARAMETER struct transaction *trans)
257 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
259 SIPE_DEBUG_INFO("process_csta_monitor_start_response:\n%s", msg->body ? msg->body : "");
261 if (!sip->csta) {
262 SIPE_DEBUG_INFO_NOFORMAT("process_csta_monitor_start_response: sip->csta is not initializzed, exiting");
263 return FALSE;
266 if (msg->response >= 400) {
267 SIPE_DEBUG_INFO_NOFORMAT("process_csta_monitor_start_response: Monitor Start response is not 200. Failed to start monitor.");
268 /* @TODO notify user of failure to start monitor */
269 return FALSE;
271 else if (msg->response == 200) {
272 sipe_xml *xml = sipe_xml_parse(msg->body, msg->bodylen);
273 g_free(sip->csta->monitor_cross_ref_id);
274 sip->csta->monitor_cross_ref_id = sipe_xml_data(sipe_xml_child(xml, "monitorCrossRefID"));
275 SIPE_DEBUG_INFO("process_csta_monitor_start_response: monitor_cross_ref_id=%s",
276 sip->csta->monitor_cross_ref_id ? sip->csta->monitor_cross_ref_id : "");
277 sipe_xml_free(xml);
280 return TRUE;
283 /** Monitor Start */
284 static void
285 sip_csta_monitor_start(struct sipe_core_private *sipe_private)
287 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
288 gchar *hdr;
289 gchar *body;
291 if (!sip->csta || !sip->csta->dialog || !sip->csta->dialog->is_established) {
292 SIPE_DEBUG_INFO_NOFORMAT("sip_csta_monitor_start: no dialog with CSTA, exiting.");
293 return;
296 hdr = g_strdup(
297 "Content-Disposition: signal;handling=required\r\n"
298 "Content-Type: application/csta+xml\r\n");
300 body = g_strdup_printf(
301 SIP_SEND_CSTA_MONITOR_START,
302 sip->csta->line_uri);
304 sip_transport_info(sipe_private,
305 hdr,
306 body,
307 sip->csta->dialog,
308 process_csta_monitor_start_response);
309 g_free(body);
310 g_free(hdr);
313 /** Monitor Stop */
314 static void
315 sip_csta_monitor_stop(struct sipe_core_private *sipe_private)
317 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
318 gchar *hdr;
319 gchar *body;
321 if (!sip->csta || !sip->csta->dialog || !sip->csta->dialog->is_established) {
322 SIPE_DEBUG_INFO_NOFORMAT("sip_csta_monitor_stop: no dialog with CSTA, exiting.");
323 return;
326 if (!sip->csta->monitor_cross_ref_id) {
327 SIPE_DEBUG_INFO_NOFORMAT("sip_csta_monitor_stop: no monitor_cross_ref_id, exiting.");
328 return;
331 hdr = g_strdup(
332 "Content-Disposition: signal;handling=required\r\n"
333 "Content-Type: application/csta+xml\r\n");
335 body = g_strdup_printf(
336 SIP_SEND_CSTA_MONITOR_STOP,
337 sip->csta->monitor_cross_ref_id);
339 sip_transport_info(sipe_private,
340 hdr,
341 body,
342 sip->csta->dialog,
343 NULL);
344 g_free(body);
345 g_free(hdr);
348 static void
349 sipe_invite_csta_gateway(struct sipe_core_private *sipe_private,
350 gpointer unused);
352 /** a callback */
353 static gboolean
354 process_invite_csta_gateway_response(struct sipe_core_private *sipe_private,
355 struct sipmsg *msg,
356 SIPE_UNUSED_PARAMETER struct transaction *trans)
358 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
360 SIPE_DEBUG_INFO("process_invite_csta_gateway_response:\n%s", msg->body ? msg->body : "");
362 if (!sip->csta) {
363 SIPE_DEBUG_INFO_NOFORMAT("process_invite_csta_gateway_response: sip->csta is not initializzed, exiting");
364 return FALSE;
367 if (!sip->csta->dialog) {
368 SIPE_DEBUG_INFO_NOFORMAT("process_invite_csta_gateway_response: GSTA dialog is NULL, exiting");
369 return FALSE;
372 sipe_dialog_parse(sip->csta->dialog, msg, TRUE);
374 if (msg->response >= 200) {
375 /* send ACK to CSTA */
376 sip->csta->dialog->cseq = 0;
377 sip_transport_ack(sipe_private, sip->csta->dialog);
378 sip->csta->dialog->outgoing_invite = NULL;
379 sip->csta->dialog->is_established = TRUE;
382 if (msg->response >= 400) {
383 SIPE_DEBUG_INFO_NOFORMAT("process_invite_csta_gateway_response: INVITE response is not 200. Failed to join CSTA.");
384 /* @TODO notify user of failure to join CSTA */
385 return FALSE;
387 else if (msg->response == 200) {
388 sipe_xml *xml = sipe_xml_parse(msg->body, msg->bodylen);
390 g_free(sip->csta->gateway_status);
391 sip->csta->gateway_status = sipe_xml_data(sipe_xml_child(xml, "systemStatus"));
392 SIPE_DEBUG_INFO("process_invite_csta_gateway_response: gateway_status=%s",
393 sip->csta->gateway_status ? sip->csta->gateway_status : "");
394 if (sipe_strcase_equal(sip->csta->gateway_status, "normal")) {
395 if (!sip->csta->monitor_cross_ref_id) {
396 sip_csta_get_features(sipe_private);
397 sip_csta_monitor_start(sipe_private);
399 } else {
400 SIPE_DEBUG_INFO("process_invite_csta_gateway_response: ERROR: CSTA status is %s, won't continue.",
401 sip->csta->gateway_status);
402 /* @TODO notify user of failure to join CSTA */
404 sipe_xml_free(xml);
406 /* schedule re-invite. RFC4028 */
407 if (sip->csta->dialog->expires) {
408 sipe_schedule_seconds(sipe_private,
409 "<+csta>",
410 NULL,
411 sip->csta->dialog->expires - 60, /* 1 minute earlier */
412 sipe_invite_csta_gateway,
413 NULL);
417 return TRUE;
420 /** Creates long living dialog with SIP/CSTA Gateway */
421 /* should be re-entrant as require to sent re-invites every 10 min to refresh */
422 static void
423 sipe_invite_csta_gateway(struct sipe_core_private *sipe_private,
424 SIPE_UNUSED_PARAMETER gpointer unused)
426 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
427 gchar *hdr;
428 gchar *contact;
429 gchar *body;
431 if (!sip->csta) {
432 SIPE_DEBUG_INFO_NOFORMAT("sipe_invite_csta_gateway: sip->csta is uninitialized, exiting");
433 return;
436 if(!sip->csta->dialog) {
437 sip->csta->dialog = g_new0(struct sip_dialog, 1);
438 sip->csta->dialog->callid = gencallid();
439 sip->csta->dialog->with = g_strdup(sip->csta->gateway_uri);
441 if (!(sip->csta->dialog->ourtag)) {
442 sip->csta->dialog->ourtag = gentag();
445 contact = get_contact(sipe_private);
446 hdr = g_strdup_printf(
447 "Contact: %s\r\n"
448 "Supported: timer\r\n"
449 "Content-Disposition: signal;handling=required\r\n"
450 "Content-Type: application/csta+xml\r\n",
451 contact);
452 g_free(contact);
454 body = g_strdup_printf(
455 SIP_SEND_CSTA_REQUEST_SYSTEM_STATUS,
456 sip->csta->line_uri);
458 sip->csta->dialog->outgoing_invite =
459 sip_transport_invite(sipe_private,
460 hdr,
461 body,
462 sip->csta->dialog,
463 process_invite_csta_gateway_response);
464 g_free(body);
465 g_free(hdr);
468 void
469 sip_csta_open(struct sipe_core_private *sipe_private,
470 const gchar *line_uri,
471 const gchar *server)
473 sip_csta_initialize(sipe_private, line_uri, server);
474 sipe_invite_csta_gateway(sipe_private, NULL);
477 static void
478 sip_csta_free(struct sip_csta *csta)
480 if (!csta) return;
482 g_free(csta->line_uri);
483 g_free(csta->gateway_uri);
485 sipe_dialog_free(csta->dialog);
487 g_free(csta->gateway_status);
488 g_free(csta->monitor_cross_ref_id);
489 g_free(csta->line_status);
490 g_free(csta->to_tel_uri);
491 g_free(csta->call_id);
492 g_free(csta->device_id);
494 g_free(csta);
497 void
498 sip_csta_close(struct sipe_core_private *sipe_private)
500 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
501 if (sip->csta) {
502 sip_csta_monitor_stop(sipe_private);
505 if (sip->csta && sip->csta->dialog) {
506 /* send BYE to CSTA */
507 sip_transport_bye(sipe_private, sip->csta->dialog);
510 sip_csta_free(sip->csta);
515 /** Make Call's callback */
516 static gboolean
517 process_csta_make_call_response(struct sipe_core_private *sipe_private,
518 struct sipmsg *msg,
519 SIPE_UNUSED_PARAMETER struct transaction *trans)
521 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
523 SIPE_DEBUG_INFO("process_csta_make_call_response:\n%s", msg->body ? msg->body : "");
525 if (!sip->csta) {
526 SIPE_DEBUG_INFO_NOFORMAT("process_csta_make_call_response: sip->csta is not initializzed, exiting");
527 return FALSE;
530 if (msg->response >= 400) {
531 SIPE_DEBUG_INFO_NOFORMAT("process_csta_make_call_response: Make Call response is not 200. Failed to make call.");
532 /* @TODO notify user of failure to make call */
533 return FALSE;
535 else if (msg->response == 200) {
536 sipe_xml *xml;
537 const sipe_xml *xn_calling_device;
538 gchar *device_id;
540 SIPE_DEBUG_INFO_NOFORMAT("process_csta_make_call_response: SUCCESS");
542 xml = sipe_xml_parse(msg->body, msg->bodylen);
543 xn_calling_device = sipe_xml_child(xml, "callingDevice");
544 device_id = sipe_xml_data(sipe_xml_child(xn_calling_device, "deviceID"));
545 if (sipe_strequal(sip->csta->line_uri, device_id)) {
546 g_free(sip->csta->call_id);
547 sip->csta->call_id = sipe_xml_data(sipe_xml_child(xn_calling_device, "callID"));
548 SIPE_DEBUG_INFO("process_csta_make_call_response: call_id=%s", sip->csta->call_id ? sip->csta->call_id : "");
550 g_free(device_id);
551 sipe_xml_free(xml);
554 return TRUE;
557 /** Make Call */
558 void
559 sip_csta_make_call(struct sipe_core_private *sipe_private,
560 const gchar* to_tel_uri)
562 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
563 gchar *hdr;
564 gchar *body;
566 if (!to_tel_uri) {
567 SIPE_DEBUG_INFO_NOFORMAT("sip_csta_make_call: no tel URI parameter provided, exiting.");
568 return;
571 if (!sip->csta || !sip->csta->dialog || !sip->csta->dialog->is_established) {
572 SIPE_DEBUG_INFO_NOFORMAT("sip_csta_make_call: no dialog with CSTA, exiting.");
573 return;
576 g_free(sip->csta->to_tel_uri);
577 sip->csta->to_tel_uri = g_strdup(to_tel_uri);
579 hdr = g_strdup(
580 "Content-Disposition: signal;handling=required\r\n"
581 "Content-Type: application/csta+xml\r\n");
583 body = g_strdup_printf(
584 SIP_SEND_CSTA_MAKE_CALL,
585 sip->csta->line_uri,
586 sip->csta->to_tel_uri);
588 sip_transport_info(sipe_private,
589 hdr,
590 body,
591 sip->csta->dialog,
592 process_csta_make_call_response);
593 g_free(body);
594 g_free(hdr);
597 static void
598 sip_csta_update_id_and_status(struct sip_csta *csta,
599 const sipe_xml *node,
600 const char *status)
602 gchar *call_id = sipe_xml_data(sipe_xml_child(node, "callID"));
604 if (!sipe_strequal(call_id, csta->call_id)) {
605 SIPE_DEBUG_INFO("sipe_csta_update_id_and_status: callID (%s) does not match", call_id);
607 else
609 /* free old line status */
610 g_free(csta->line_status);
611 csta->line_status = NULL;
613 if (status)
615 /* save deviceID */
616 gchar *device_id = sipe_xml_data(sipe_xml_child(node, "deviceID"));
617 SIPE_DEBUG_INFO("sipe_csta_update_id_and_status: device_id=(%s)", device_id ? device_id : "");
618 if (device_id) {
619 g_free(csta->device_id);
620 csta->device_id = device_id;
623 /* set new line status */
624 csta->line_status = g_strdup(status);
626 else
628 /* clean up cleared connection */
629 g_free(csta->to_tel_uri);
630 csta->to_tel_uri = NULL;
631 g_free(csta->call_id);
632 csta->call_id = NULL;
633 g_free(csta->device_id);
634 csta->device_id = NULL;
638 g_free(call_id);
641 void
642 process_incoming_info_csta(struct sipe_core_private *sipe_private,
643 struct sipmsg *msg)
645 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
646 gchar *monitor_cross_ref_id;
647 sipe_xml *xml = sipe_xml_parse(msg->body, msg->bodylen);
649 if (!xml) return;
651 monitor_cross_ref_id = sipe_xml_data(sipe_xml_child(xml, "monitorCrossRefID"));
653 if(!sip->csta || !sipe_strequal(monitor_cross_ref_id, sip->csta->monitor_cross_ref_id))
655 SIPE_DEBUG_INFO("process_incoming_info_csta: monitorCrossRefID (%s) does not match, exiting",
656 monitor_cross_ref_id ? monitor_cross_ref_id : "");
658 else
660 if (sipe_strequal(sipe_xml_name(xml), "OriginatedEvent"))
662 sip_csta_update_id_and_status(sip->csta,
663 sipe_xml_child(xml, "originatedConnection"),
664 ORIGINATED_CSTA_STATUS);
666 else if (sipe_strequal(sipe_xml_name(xml), "DeliveredEvent"))
668 sip_csta_update_id_and_status(sip->csta,
669 sipe_xml_child(xml, "connection"),
670 DELIVERED_CSTA_STATUS);
672 else if (sipe_strequal(sipe_xml_name(xml), "EstablishedEvent"))
674 sip_csta_update_id_and_status(sip->csta,
675 sipe_xml_child(xml, "establishedConnection"),
676 ESTABLISHED_CSTA_STATUS);
678 else if (sipe_strequal(sipe_xml_name(xml), "ConnectionClearedEvent"))
680 sip_csta_update_id_and_status(sip->csta,
681 sipe_xml_child(xml, "droppedConnection"),
682 NULL);
686 g_free(monitor_cross_ref_id);
687 sipe_xml_free(xml);
693 Local Variables:
694 mode: c
695 c-file-style: "bsd"
696 indent-tabs-mode: t
697 tab-width: 8
698 End: