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>
32 #include "sipe-backend.h"
33 #include "sipe-common.h"
34 #include "sipe-core.h"
35 #include "sipe-core-private.h"
36 #include "sipe-digest.h"
37 #include "sipe-ews-autodiscover.h"
38 #include "sipe-http.h"
40 #include "sipe-utils.h"
43 typedef void (ucs_callback
)(struct sipe_core_private
*sipe_private
,
45 gpointer callback_data
);
56 struct sipe_http_request
*request
;
61 GSList
*deferred_requests
;
62 GSList
*pending_requests
;
64 gboolean shutting_down
;
67 static void sipe_ucs_deferred_free(struct sipe_core_private
*sipe_private
,
68 struct ucs_deferred
*data
)
71 /* Callback: aborted */
72 (*data
->cb
)(sipe_private
, NULL
, data
->cb_data
);
77 static void sipe_ucs_request_free(struct sipe_core_private
*sipe_private
,
78 struct ucs_request
*data
)
81 sipe_http_request_cancel(data
->request
);
83 /* Callback: aborted */
84 (*data
->cb
)(sipe_private
, NULL
, data
->cb_data
);
88 static void sipe_ucs_http_response(struct sipe_core_private
*sipe_private
,
90 SIPE_UNUSED_PARAMETER GSList
*headers
,
92 gpointer callback_data
)
94 struct ucs_request
*data
= callback_data
;
95 struct sipe_ucs
*ucs
= sipe_private
->ucs
;
97 SIPE_DEBUG_INFO("sipe_ucs_http_response: code %d", status
);
100 if ((status
== SIPE_HTTP_STATUS_OK
) && body
) {
101 sipe_xml
*xml
= sipe_xml_parse(body
, strlen(body
));
102 /* Callback: success */
103 (*data
->cb
)(sipe_private
, xml
, data
->cb_data
);
106 /* Callback: failed */
107 (*data
->cb
)(sipe_private
, NULL
, data
->cb_data
);
110 /* already been called */
113 ucs
->pending_requests
= g_slist_remove(ucs
->pending_requests
,
115 sipe_ucs_request_free(sipe_private
, data
);
118 static gboolean
sipe_ucs_http_request(struct sipe_core_private
*sipe_private
,
120 ucs_callback
*callback
,
121 gpointer callback_data
)
123 struct sipe_ucs
*ucs
= sipe_private
->ucs
;
124 gboolean success
= FALSE
;
126 if (ucs
->shutting_down
) {
127 SIPE_DEBUG_ERROR("sipe_ucs_http_request: new UCS request during shutdown: THIS SHOULD NOT HAPPEN! Debugging information:\n"
129 body
? body
: "<EMPTY>");
131 } else if (ucs
->ews_url
) {
132 struct ucs_request
*data
= g_new0(struct ucs_request
, 1);
133 gchar
*soap
= g_strdup_printf("<?xml version=\"1.0\"?>\r\n"
135 " xmlns:m=\"http://schemas.microsoft.com/exchange/services/2006/messages\""
136 " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""
137 " xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\""
140 " <t:RequestServerVersion Version=\"Exchange2013\" />"
147 struct sipe_http_request
*request
= sipe_http_request_post(sipe_private
,
151 "text/xml; charset=UTF-8",
152 sipe_ucs_http_response
,
158 data
->cb_data
= callback_data
;
159 data
->request
= request
;
161 ucs
->pending_requests
= g_slist_prepend(ucs
->pending_requests
,
164 sipe_core_email_authentication(sipe_private
,
166 sipe_http_request_allow_redirect(request
);
167 sipe_http_request_ready(request
);
171 SIPE_DEBUG_ERROR_NOFORMAT("sipe_ucs_http_request: failed to create HTTP connection");
176 struct ucs_deferred
*data
= g_new0(struct ucs_deferred
, 1);
178 data
->cb_data
= callback_data
;
179 data
->body
= g_strdup(body
);
181 ucs
->deferred_requests
= g_slist_prepend(ucs
->deferred_requests
,
189 static void sipe_ucs_get_user_photo_response(struct sipe_core_private
*sipe_private
,
191 gpointer callback_data
)
193 gchar
*uri
= callback_data
;
194 const sipe_xml
*node
= sipe_xml_child(xml
,
195 "Body/GetUserPhotoResponse/PictureData");
201 guchar digest
[SIPE_DIGEST_SHA1_LENGTH
];
202 gchar
*digest_string
;
204 /* decode photo data */
205 base64
= sipe_xml_data(node
);
206 photo
= g_base64_decode(base64
, &photo_size
);
209 /* EWS doesn't provide a hash -> calculate SHA-1 digest */
210 sipe_digest_sha1(photo
, photo_size
, digest
);
211 digest_string
= buff_to_hex_str(digest
,
212 SIPE_DIGEST_SHA1_LENGTH
);
214 /* backend frees "photo" */
215 sipe_backend_buddy_set_photo(SIPE_CORE_PUBLIC
,
220 g_free(digest_string
);
226 void sipe_ucs_get_photo(struct sipe_core_private
*sipe_private
,
229 gchar
*payload
= g_strdup(uri
);
230 gchar
*body
= g_strdup_printf("<m:GetUserPhoto>"
231 " <m:Email>%s</m:Email>"
232 " <m:SizeRequested>HR48x48</m:SizeRequested>"
234 sipe_get_no_sip_uri(uri
));
236 if (!sipe_ucs_http_request(sipe_private
,
238 sipe_ucs_get_user_photo_response
,
245 static void sipe_ucs_get_im_item_list_response(struct sipe_core_private
*sipe_private
,
247 gpointer callback_data
)
255 static void ucs_ews_autodiscover_cb(struct sipe_core_private
*sipe_private
,
256 const struct sipe_ews_autodiscover_data
*ews_data
,
257 SIPE_UNUSED_PARAMETER gpointer callback_data
)
259 struct sipe_ucs
*ucs
= sipe_private
->ucs
;
260 const gchar
*ews_url
= ews_data
->ews_url
;
265 if (is_empty(ews_url
)) {
266 SIPE_DEBUG_ERROR_NOFORMAT("ucs_ews_autodiscover_cb: can't detect EWS URL, contact list operations will not work!");
270 SIPE_DEBUG_INFO("ucs_ews_autodiscover_cb: EWS URL '%s'", ews_url
);
271 ucs
->ews_url
= g_strdup(ews_url
);
273 /* Request migrated contact list */
275 sipe_ucs_http_request(sipe_private
,
276 "<m:GetImItemList/>",
277 sipe_ucs_get_im_item_list_response
,
280 /* EWS URL is valid, send all deferred requests now */
281 if (ucs
->deferred_requests
) {
282 GSList
*entry
= ucs
->deferred_requests
;
284 struct ucs_deferred
*data
= entry
->data
;
286 sipe_ucs_http_request(sipe_private
,
291 /* callback & data has been forwarded */
293 sipe_ucs_deferred_free(sipe_private
, data
);
297 g_slist_free(ucs
->deferred_requests
);
298 ucs
->deferred_requests
= NULL
;
302 void sipe_ucs_init(struct sipe_core_private
*sipe_private
,
305 struct sipe_ucs
*ucs
;
307 if (sipe_private
->ucs
)
310 sipe_private
->ucs
= ucs
= g_new0(struct sipe_ucs
, 1);
311 ucs
->migrated
= migrated
;
313 sipe_ews_autodiscover_start(sipe_private
,
314 ucs_ews_autodiscover_cb
,
318 void sipe_ucs_free(struct sipe_core_private
*sipe_private
)
320 struct sipe_ucs
*ucs
= sipe_private
->ucs
;
325 /* UCS stack is shutting down: reject all new requests */
326 ucs
->shutting_down
= TRUE
;
328 if (ucs
->deferred_requests
) {
329 GSList
*entry
= ucs
->deferred_requests
;
331 sipe_ucs_deferred_free(sipe_private
, entry
->data
);
334 g_slist_free(ucs
->deferred_requests
);
337 if (ucs
->pending_requests
) {
338 GSList
*entry
= ucs
->pending_requests
;
340 sipe_ucs_request_free(sipe_private
, entry
->data
);
343 g_slist_free(ucs
->pending_requests
);
346 g_free(ucs
->ews_url
);
348 sipe_private
->ucs
= NULL
;