ucs: implement request queue
[siplcs.git] / src / core / sipe-ucs.c
blobed21b455a8a898cd93db267e31d82ff4bdba982a
1 /**
2 * @file sipe-ucs.c
4 * pidgin-sipe
6 * Copyright (C) 2013 SIPE Project <http://sipe.sourceforge.net/>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * Implementation for Unified Contact Store [MS-OXWSCOS]
25 * <http://msdn.microsoft.com/en-us/library/jj194130.aspx>
28 #include <string.h>
30 #include <glib.h>
32 #include "sipe-backend.h"
33 #include "sipe-common.h"
34 #include "sipe-core.h"
35 #include "sipe-core-private.h"
36 #include "sipe-ews-autodiscover.h"
37 #include "sipe-http.h"
38 #include "sipe-ucs.h"
39 #include "sipe-utils.h"
40 #include "sipe-xml.h"
42 typedef void (ucs_callback)(struct sipe_core_private *sipe_private,
43 const sipe_xml *xml);
45 struct ucs_request {
46 ucs_callback *cb;
47 struct sipe_http_request *request;
50 struct sipe_ucs {
51 gchar *ews_url;
52 GSList *pending_requests;
53 gboolean shutting_down;
56 static void sipe_ucs_request_free(struct sipe_core_private *sipe_private,
57 struct ucs_request *data)
59 if (data->request)
60 sipe_http_request_cancel(data->request);
61 if (data->cb)
62 /* Callback: aborted */
63 (*data->cb)(sipe_private, NULL);
64 g_free(data);
67 static void sipe_ucs_get_im_item_list_response(struct sipe_core_private *sipe_private,
68 const sipe_xml *xml)
70 /* temporary */
71 (void)sipe_private;
72 (void)xml;
75 static void sipe_ucs_http_response(struct sipe_core_private *sipe_private,
76 guint status,
77 SIPE_UNUSED_PARAMETER GSList *headers,
78 const gchar *body,
79 gpointer callback_data)
81 struct ucs_request *data = callback_data;
82 struct sipe_ucs *ucs = sipe_private->ucs;
84 SIPE_DEBUG_INFO("sipe_ucs_http_response: code %d", status);
85 data->request = NULL;
87 if ((status == SIPE_HTTP_STATUS_OK) && body) {
88 sipe_xml *xml = sipe_xml_parse(body, strlen(body));
89 /* Callback: success */
90 (*data->cb)(sipe_private, xml);
91 sipe_xml_free(xml);
92 } else {
93 /* Callback: failed */
94 (*data->cb)(sipe_private, NULL);
97 /* already been called */
98 data->cb = NULL;
100 ucs->pending_requests = g_slist_remove(ucs->pending_requests,
101 data);
102 sipe_ucs_request_free(sipe_private, data);
105 static void sipe_ucs_http_request(struct sipe_core_private *sipe_private,
106 const gchar *body,
107 ucs_callback *callback)
109 struct sipe_ucs *ucs = sipe_private->ucs;
111 if (ucs->shutting_down) {
112 SIPE_DEBUG_ERROR("sipe_ucs_http_request: new UCS request during shutdown: THIS SHOULD NOT HAPPEN! Debugging information:\n"
113 "Body: %s\n",
114 body ? body : "<EMPTY>");
115 } else {
116 struct ucs_request *data = g_new0(struct ucs_request, 1);
117 gchar *soap = g_strdup_printf("<?xml version=\"1.0\"?>\r\n"
118 "<soap:Envelope"
119 " xmlns:m=\"http://schemas.microsoft.com/exchange/services/2006/messages\""
120 " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""
121 " xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\""
122 " >"
123 " <soap:Header>"
124 " <t:RequestServerVersion Version=\"Exchange2013\" />"
125 " </soap:Header>"
126 " <soap:Body>"
127 " %s"
128 " </soap:Body>"
129 "</soap:Envelope>",
130 body);
131 struct sipe_http_request *request = sipe_http_request_post(sipe_private,
132 ucs->ews_url,
133 NULL,
134 soap,
135 "text/xml; charset=UTF-8",
136 sipe_ucs_http_response,
137 data);
138 g_free(soap);
140 if (request) {
141 data->cb = callback;
142 data->request = request;
144 ucs->pending_requests = g_slist_prepend(ucs->pending_requests,
145 data);
147 sipe_core_email_authentication(sipe_private,
148 request);
149 sipe_http_request_allow_redirect(request);
150 sipe_http_request_ready(request);
151 } else {
152 SIPE_DEBUG_ERROR_NOFORMAT("sipe_ucs_http_request: failed to create HTTP connection");
153 g_free(data);
158 static void ucs_ews_autodiscover_cb(struct sipe_core_private *sipe_private,
159 const struct sipe_ews_autodiscover_data *ews_data,
160 SIPE_UNUSED_PARAMETER gpointer callback_data)
162 struct sipe_ucs *ucs = sipe_private->ucs;
163 const gchar *ews_url = ews_data->ews_url;
165 if (!ucs)
166 return;
168 if (is_empty(ews_url)) {
169 SIPE_DEBUG_ERROR_NOFORMAT("ucs_ews_autodiscover_cb: can't detect EWS URL, contact list operations will not work!");
170 return;
173 SIPE_DEBUG_INFO("ucs_ews_autodiscover_cb: EWS URL '%s'", ews_url);
174 ucs->ews_url = g_strdup(ews_url);
176 sipe_ucs_http_request(sipe_private,
177 "<m:GetImItemList/>",
178 sipe_ucs_get_im_item_list_response);
181 void sipe_ucs_init(struct sipe_core_private *sipe_private)
183 if (sipe_private->ucs)
184 return;
186 sipe_private->ucs = g_new0(struct sipe_ucs, 1);
188 sipe_ews_autodiscover_start(sipe_private,
189 ucs_ews_autodiscover_cb,
190 NULL);
193 void sipe_ucs_free(struct sipe_core_private *sipe_private)
195 struct sipe_ucs *ucs = sipe_private->ucs;
197 if (!ucs)
198 return;
200 /* UCS stack is shutting down: reject all new requests */
201 ucs->shutting_down = TRUE;
203 if (ucs->pending_requests) {
204 GSList *entry = ucs->pending_requests;
205 while (entry) {
206 sipe_ucs_request_free(sipe_private, entry->data);
207 entry = entry->next;
209 g_slist_free(ucs->pending_requests);
212 g_free(ucs->ews_url);
213 g_free(ucs);
214 sipe_private->ucs = NULL;
218 Local Variables:
219 mode: c
220 c-file-style: "bsd"
221 indent-tabs-mode: t
222 tab-width: 8
223 End: