ews: add additional check for new email address
[siplcs.git] / src / core / sipe-ews-autodiscover.c
blobae29bd885ed17bfcea9114ad0ed8be22c6fece55
1 /**
2 * @file sipe-ews-autodiscover.c
4 * pidgin-sipe
6 * Copyright (C) 2013-2014 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
23 * Specification references:
25 * - POX: plain old XML autodiscover
26 * - [MS-OXDSCLI]: http://msdn.microsoft.com/en-us/library/cc463896.aspx
27 * - POX autodiscover: http://msdn.microsoft.com/en-us/library/office/aa581522.aspx
28 * - POX redirect: http://msdn.microsoft.com/en-us/library/office/dn467392.aspx
31 #include <string.h>
33 #include <glib.h>
35 #include "sipe-backend.h"
36 #include "sipe-common.h"
37 #include "sipe-core.h"
38 #include "sipe-core-private.h"
39 #include "sipe-ews-autodiscover.h"
40 #include "sipe-http.h"
41 #include "sipe-utils.h"
42 #include "sipe-xml.h"
44 struct sipe_ews_autodiscover_cb {
45 sipe_ews_autodiscover_callback *cb;
46 gpointer cb_data;
49 struct sipe_ews_autodiscover {
50 struct sipe_ews_autodiscover_data *data;
51 struct sipe_http_request *request;
52 GSList *callbacks;
53 gchar *email;
54 const gchar * const *method;
55 gboolean retry;
56 gboolean completed;
59 static void sipe_ews_autodiscover_complete(struct sipe_core_private *sipe_private,
60 struct sipe_ews_autodiscover_data *ews_data)
62 struct sipe_ews_autodiscover *sea = sipe_private->ews_autodiscover;
63 GSList *entry = sea->callbacks;
65 while (entry) {
66 struct sipe_ews_autodiscover_cb *sea_cb = entry->data;
67 sea_cb->cb(sipe_private, ews_data, sea_cb->cb_data);
68 g_free(sea_cb);
69 entry = entry->next;
71 g_slist_free(sea->callbacks);
72 sea->callbacks = NULL;
73 sea->completed = TRUE;
76 static void sipe_ews_autodiscover_request(struct sipe_core_private *sipe_private,
77 gboolean next_method);
78 static void sipe_ews_autodiscover_parse(struct sipe_core_private *sipe_private,
79 const gchar *body)
81 struct sipe_ews_autodiscover *sea = sipe_private->ews_autodiscover;
82 struct sipe_ews_autodiscover_data *ews_data = sea->data =
83 g_new0(struct sipe_ews_autodiscover_data, 1);
84 sipe_xml *xml = sipe_xml_parse(body, strlen(body));
85 const sipe_xml *account = sipe_xml_child(xml, "Response/Account");
86 gboolean complete = TRUE;
88 /* valid POX autodiscover response? */
89 if (account) {
90 const sipe_xml *node = sipe_xml_child(account, "Protocol");
92 /* valid settings? */
93 if (node) {
95 /* Autodiscover/Response/User/LegacyDN (requires trimming) */
96 gchar *tmp = sipe_xml_data(sipe_xml_child(xml,
97 "Response/User/LegacyDN"));
98 if (tmp)
99 ews_data->legacy_dn = g_strstrip(tmp);
101 /* extract settings */
102 for (; node; node = sipe_xml_twin(node)) {
103 gchar *type = sipe_xml_data(sipe_xml_child(node,
104 "Type"));
106 if (sipe_strequal("EXCH", type)) {
107 g_free(type);
109 #define _URL(name, field) \
111 ews_data->field = sipe_xml_data(sipe_xml_child(node, #name)); \
112 SIPE_DEBUG_INFO("sipe_ews_autodiscover_parse: " #field " = '%s'", \
113 ews_data->field ? ews_data->field : "<NOT FOUND>"); \
116 _URL(ASUrl, as_url);
117 _URL(EwsUrl, ews_url);
118 _URL(OABUrl, oab_url);
119 _URL(OOFUrl, oof_url);
120 #undef _URL
122 break;
125 g_free(type);
128 } else {
130 * POX autodiscover redirect email address?
131 * Make sure email address contains a "@" character.
132 * Make sure email address is different from current one.
134 gchar *tmp = sipe_xml_data(sipe_xml_child(account,
135 "RedirectAddr"));
136 if (tmp && strchr(tmp, '@') &&
137 !sipe_strequal(sea->email, tmp)) {
138 g_free(sea->email);
139 sea->email = tmp;
140 tmp = NULL; /* sea takes ownership */
142 SIPE_DEBUG_INFO("sipe_ews_autodiscover_parse: restarting with email address '%s'",
143 sea->email);
145 /* restart process with new email address */
146 sea->method = NULL;
147 complete = FALSE;
148 sipe_ews_autodiscover_request(sipe_private,
149 TRUE);
151 g_free(tmp);
154 sipe_xml_free(xml);
156 if (complete)
157 sipe_ews_autodiscover_complete(sipe_private, ews_data);
160 static void sipe_ews_autodiscover_response(struct sipe_core_private *sipe_private,
161 guint status,
162 SIPE_UNUSED_PARAMETER GSList *headers,
163 const gchar *body,
164 gpointer data)
166 struct sipe_ews_autodiscover *sea = data;
168 sea->request = NULL;
170 switch (status) {
171 case SIPE_HTTP_STATUS_OK:
172 if (body)
173 sipe_ews_autodiscover_parse(sipe_private, body);
174 else
175 sipe_ews_autodiscover_request(sipe_private, TRUE);
176 break;
178 case SIPE_HTTP_STATUS_CLIENT_FORBIDDEN:
180 * Authentication succeeded but we still weren't allowed to
181 * view the page. At least at our work place this error is
182 * temporary, i.e. the next access with the exact same
183 * authentication succeeds.
185 * Let's try again, but only once...
187 sipe_ews_autodiscover_request(sipe_private, !sea->retry);
188 break;
190 case SIPE_HTTP_STATUS_ABORTED:
191 /* we are not allowed to generate new requests */
192 break;
194 default:
195 sipe_ews_autodiscover_request(sipe_private, TRUE);
196 break;
200 static gboolean sipe_ews_autodiscover_url(struct sipe_core_private *sipe_private,
201 const gchar *url)
203 struct sipe_ews_autodiscover *sea = sipe_private->ews_autodiscover;
204 gchar *body = g_strdup_printf("<Autodiscover xmlns=\"http://schemas.microsoft.com/exchange/autodiscover/outlook/requestschema/2006\">"
205 " <Request>"
206 " <EMailAddress>%s</EMailAddress>"
207 " <AcceptableResponseSchema>http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a</AcceptableResponseSchema>"
208 " </Request>"
209 "</Autodiscover>",
210 sea->email);
212 SIPE_DEBUG_INFO("sipe_ews_autodiscover_url: trying '%s'", url);
214 sea->request = sipe_http_request_post(sipe_private,
215 url,
216 NULL,
217 body,
218 "text/xml",
219 sipe_ews_autodiscover_response,
220 sea);
221 g_free(body);
223 if (sea->request) {
224 sipe_core_email_authentication(sipe_private,
225 sea->request);
226 sipe_http_request_allow_redirect(sea->request);
227 sipe_http_request_ready(sea->request);
228 return(TRUE);
231 return(FALSE);
234 static void sipe_ews_autodiscover_request(struct sipe_core_private *sipe_private,
235 gboolean next_method)
237 struct sipe_ews_autodiscover *sea = sipe_private->ews_autodiscover;
238 static const gchar * const methods[] = {
239 "https://Autodiscover.%s/Autodiscover/Autodiscover.xml",
240 "http://Autodiscover.%s/Autodiscover/Autodiscover.xml",
241 "https://%s/Autodiscover/Autodiscover.xml",
242 NULL
245 sea->retry = next_method;
246 if (sea->method) {
247 if (next_method)
248 sea->method++;
249 } else
250 sea->method = methods;
252 if (*sea->method) {
253 gchar *url = g_strdup_printf(*sea->method,
254 strstr(sea->email, "@") + 1);
256 if (!sipe_ews_autodiscover_url(sipe_private, url))
257 sipe_ews_autodiscover_request(sipe_private, TRUE);
259 g_free(url);
261 } else {
262 SIPE_DEBUG_INFO_NOFORMAT("sipe_ews_autodiscover_request: no more methods to try!");
263 sipe_ews_autodiscover_complete(sipe_private, NULL);
267 void sipe_ews_autodiscover_start(struct sipe_core_private *sipe_private,
268 sipe_ews_autodiscover_callback *callback,
269 gpointer callback_data)
271 struct sipe_ews_autodiscover *sea = sipe_private->ews_autodiscover;
273 if (sea->completed) {
274 (*callback)(sipe_private, sea->data, callback_data);
275 } else {
276 struct sipe_ews_autodiscover_cb *sea_cb = g_new(struct sipe_ews_autodiscover_cb, 1);
277 sea_cb->cb = callback;
278 sea_cb->cb_data = callback_data;
279 sea->callbacks = g_slist_prepend(sea->callbacks, sea_cb);
281 if (!sea->method)
282 sipe_ews_autodiscover_request(sipe_private, TRUE);
286 void sipe_ews_autodiscover_init(struct sipe_core_private *sipe_private)
288 struct sipe_ews_autodiscover *sea = g_new0(struct sipe_ews_autodiscover, 1);
290 sea->email = g_strdup(sipe_private->email);
292 sipe_private->ews_autodiscover = sea;
295 void sipe_ews_autodiscover_free(struct sipe_core_private *sipe_private)
297 struct sipe_ews_autodiscover *sea = sipe_private->ews_autodiscover;
298 struct sipe_ews_autodiscover_data *ews_data = sea->data;
299 sipe_ews_autodiscover_complete(sipe_private, NULL);
300 if (ews_data) {
301 g_free((gchar *)ews_data->as_url);
302 g_free((gchar *)ews_data->ews_url);
303 g_free((gchar *)ews_data->legacy_dn);
304 g_free((gchar *)ews_data->oab_url);
305 g_free((gchar *)ews_data->oof_url);
306 g_free(ews_data);
308 g_free(sea->email);
309 g_free(sea);
313 Local Variables:
314 mode: c
315 c-file-style: "bsd"
316 indent-tabs-mode: t
317 tab-width: 8
318 End: