ews: retry only once after 403
[siplcs.git] / src / core / sipe-ews-autodiscover.c
blobda9f1f02f907670f903f4f62dc55ded6cf7c5bc4
1 /**
2 * @file sipe-ews-autodiscover.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
23 * Specification references:
25 * - [MS-OXDSCLI]: http://msdn.microsoft.com/en-us/library/cc463896.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-xml.h"
40 struct sipe_ews_autodiscover_cb {
41 sipe_ews_autodiscover_callback *cb;
42 gpointer cb_data;
45 struct sipe_ews_autodiscover {
46 struct sipe_ews_autodiscover_data *data;
47 struct sipe_http_request *request;
48 GSList *callbacks;
49 const gchar *domain;
50 const gchar * const *method;
51 gboolean retry;
52 gboolean completed;
55 static void sipe_ews_autodiscover_complete(struct sipe_core_private *sipe_private,
56 struct sipe_ews_autodiscover_data *ews_data)
58 struct sipe_ews_autodiscover *sea = sipe_private->ews_autodiscover;
59 GSList *entry = sea->callbacks;
61 while (entry) {
62 struct sipe_ews_autodiscover_cb *sea_cb = entry->data;
63 sea_cb->cb(sipe_private, ews_data, sea_cb->cb_data);
64 g_free(sea_cb);
65 entry = entry->next;
67 g_slist_free(sea->callbacks);
68 sea->callbacks = NULL;
69 sea->completed = TRUE;
72 static void sipe_ews_autodiscover_parse(struct sipe_core_private *sipe_private,
73 const gchar *body)
75 struct sipe_ews_autodiscover *sea = sipe_private->ews_autodiscover;
76 struct sipe_ews_autodiscover_data *ews_data = sea->data =
77 g_new0(struct sipe_ews_autodiscover_data, 1);
78 sipe_xml *xml = sipe_xml_parse(body, strlen(body));
79 const sipe_xml *node;
80 gchar *tmp;
82 /* Autodiscover/Response/User/LegacyDN (requires trimming) */
83 tmp = sipe_xml_data(sipe_xml_child(xml, "Response/User/LegacyDN"));
84 if (tmp)
85 ews_data->legacy_dn = g_strstrip(tmp);
87 /* Autodiscover/Response/Account/Protocol */
88 for (node = sipe_xml_child(xml, "Response/Account/Protocol");
89 node;
90 node = sipe_xml_twin(node)) {
91 gchar *type = sipe_xml_data(sipe_xml_child(node, "Type"));
93 if (sipe_strequal("EXCH", type)) {
94 g_free(type);
96 #define _URL(name, field) \
97 { \
98 ews_data->field = sipe_xml_data(sipe_xml_child(node, #name)); \
99 SIPE_DEBUG_INFO("sipe_ews_autodiscover_parse: " #field " = '%s'", \
100 ews_data->field ? ews_data->field : "<NOT FOUND>"); \
103 _URL(ASUrl, as_url);
104 _URL(EwsUrl, ews_url);
105 _URL(OABUrl, oab_url);
106 _URL(OOFUrl, oof_url);
107 #undef _URL
109 break;
112 g_free(type);
114 sipe_xml_free(xml);
116 sipe_ews_autodiscover_complete(sipe_private, ews_data);
119 static void sipe_ews_autodiscover_request(struct sipe_core_private *sipe_private,
120 gboolean next_method);
121 static void sipe_ews_autodiscover_response(struct sipe_core_private *sipe_private,
122 guint status,
123 SIPE_UNUSED_PARAMETER GSList *headers,
124 const gchar *body,
125 gpointer data)
127 struct sipe_ews_autodiscover *sea = data;
129 sea->request = NULL;
131 switch (status) {
132 case SIPE_HTTP_STATUS_OK:
133 if (body)
134 sipe_ews_autodiscover_parse(sipe_private, body);
135 else
136 sipe_ews_autodiscover_request(sipe_private, TRUE);
137 break;
139 case SIPE_HTTP_STATUS_CLIENT_FORBIDDEN:
141 * Authentication succeeded but we still weren't allowed to
142 * view the page. At least at our work place this error is
143 * temporary, i.e. the next access with the exact same
144 * authentication succeeds.
146 * Let's try again, but only once...
148 sipe_ews_autodiscover_request(sipe_private, !sea->retry);
149 break;
151 case SIPE_HTTP_STATUS_ABORTED:
152 /* we are not allowed to generate new requests */
153 break;
155 default:
156 sipe_ews_autodiscover_request(sipe_private, TRUE);
157 break;
161 static void sipe_ews_autodiscover_request(struct sipe_core_private *sipe_private,
162 gboolean next_method)
164 struct sipe_ews_autodiscover *sea = sipe_private->ews_autodiscover;
165 static const gchar * const methods[] = {
166 "https://Autodiscover.%s/Autodiscover/Autodiscover.xml",
167 "http://Autodiscover.%s/Autodiscover/Autodiscover.xml",
168 "https://%s/Autodiscover/Autodiscover.xml",
169 NULL
172 sea->retry = next_method;
173 if (sea->method) {
174 if (next_method)
175 sea->method++;
176 } else
177 sea->method = methods;
179 if (*sea->method) {
180 gchar *url = g_strdup_printf(*sea->method, sea->domain);
181 gchar *body = g_strdup_printf("<Autodiscover xmlns=\"http://schemas.microsoft.com/exchange/autodiscover/outlook/requestschema/2006\">"
182 " <Request>"
183 " <EMailAddress>%s</EMailAddress>"
184 " <AcceptableResponseSchema>http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a</AcceptableResponseSchema>"
185 " </Request>"
186 "</Autodiscover>",
187 sipe_private->email);
189 SIPE_DEBUG_INFO("sipe_ews_autodiscover_request: trying '%s'", url);
191 sea->request = sipe_http_request_post(sipe_private,
192 url,
193 NULL,
194 body,
195 "text/xml",
196 sipe_ews_autodiscover_response,
197 sea);
198 g_free(body);
199 g_free(url);
201 if (sea->request) {
202 /* @TODO: sipe_cal_http_authentication(cal); */
203 sipe_http_request_allow_redirect(sea->request);
204 sipe_http_request_ready(sea->request);
205 } else
206 sipe_ews_autodiscover_request(sipe_private, TRUE);
208 } else {
209 SIPE_DEBUG_INFO_NOFORMAT("sipe_ews_autodiscover_request: no more methods to try!");
210 sipe_ews_autodiscover_complete(sipe_private, NULL);
214 void sipe_ews_autodiscover_start(struct sipe_core_private *sipe_private,
215 sipe_ews_autodiscover_callback *callback,
216 gpointer callback_data)
218 struct sipe_ews_autodiscover *sea = sipe_private->ews_autodiscover;
220 if (sea->completed) {
221 (*callback)(sipe_private, sea->data, callback_data);
222 } else {
223 struct sipe_ews_autodiscover_cb *sea_cb = g_new(struct sipe_ews_autodiscover_cb, 1);
224 sea_cb->cb = callback;
225 sea_cb->cb_data = callback_data;
226 sea->callbacks = g_slist_prepend(sea->callbacks, sea_cb);
228 if (!sea->method)
229 sipe_ews_autodiscover_request(sipe_private, TRUE);
233 void sipe_ews_autodiscover_init(struct sipe_core_private *sipe_private)
235 struct sipe_ews_autodiscover *sea = g_new0(struct sipe_ews_autodiscover, 1);
237 sea->domain = strstr(sipe_private->email, "@") + 1;
238 sipe_private->ews_autodiscover = sea;
241 void sipe_ews_autodiscover_free(struct sipe_core_private *sipe_private)
243 struct sipe_ews_autodiscover *sea = sipe_private->ews_autodiscover;
244 struct sipe_ews_autodiscover_data *ews_data = sea->data;
245 sipe_ews_autodiscover_complete(sipe_private, NULL);
246 if (ews_data) {
247 g_free((gchar *)ews_data->as_url);
248 g_free((gchar *)ews_data->ews_url);
249 g_free((gchar *)ews_data->legacy_dn);
250 g_free((gchar *)ews_data->oab_url);
251 g_free((gchar *)ews_data->oof_url);
252 g_free(ews_data);
254 g_free(sea);
258 Local Variables:
259 mode: c
260 c-file-style: "bsd"
261 indent-tabs-mode: t
262 tab-width: 8
263 End: