2 * @file sipe-ews-autodiscover.c
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
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"
40 struct sipe_ews_autodiscover_cb
{
41 sipe_ews_autodiscover_callback
*cb
;
45 struct sipe_ews_autodiscover
{
46 struct sipe_ews_autodiscover_data
*data
;
47 struct sipe_http_request
*request
;
50 const gchar
* const *method
;
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
;
62 struct sipe_ews_autodiscover_cb
*sea_cb
= entry
->data
;
63 sea_cb
->cb(sipe_private
, ews_data
, sea_cb
->cb_data
);
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
,
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
));
82 /* Autodiscover/Response/User/LegacyDN (requires trimming) */
83 tmp
= sipe_xml_data(sipe_xml_child(xml
, "Response/User/LegacyDN"));
85 ews_data
->legacy_dn
= g_strstrip(tmp
);
87 /* Autodiscover/Response/Account/Protocol */
88 for (node
= sipe_xml_child(xml
, "Response/Account/Protocol");
90 node
= sipe_xml_twin(node
)) {
91 gchar
*type
= sipe_xml_data(sipe_xml_child(node
, "Type"));
93 if (sipe_strequal("EXCH", type
)) {
96 #define _URL(name, field) \
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>"); \
104 _URL(EwsUrl
, ews_url
);
105 _URL(OABUrl
, oab_url
);
106 _URL(OOFUrl
, oof_url
);
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
,
123 SIPE_UNUSED_PARAMETER GSList
*headers
,
127 struct sipe_ews_autodiscover
*sea
= data
;
132 case SIPE_HTTP_STATUS_OK
:
134 sipe_ews_autodiscover_parse(sipe_private
, body
);
136 sipe_ews_autodiscover_request(sipe_private
, TRUE
);
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
);
151 case SIPE_HTTP_STATUS_ABORTED
:
152 /* we are not allowed to generate new requests */
156 sipe_ews_autodiscover_request(sipe_private
, TRUE
);
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",
172 sea
->retry
= next_method
;
177 sea
->method
= methods
;
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\">"
183 " <EMailAddress>%s</EMailAddress>"
184 " <AcceptableResponseSchema>http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a</AcceptableResponseSchema>"
187 sipe_private
->email
);
189 SIPE_DEBUG_INFO("sipe_ews_autodiscover_request: trying '%s'", url
);
191 sea
->request
= sipe_http_request_post(sipe_private
,
196 sipe_ews_autodiscover_response
,
202 sipe_core_email_authentication(sipe_private
,
204 sipe_http_request_allow_redirect(sea
->request
);
205 sipe_http_request_ready(sea
->request
);
207 sipe_ews_autodiscover_request(sipe_private
, TRUE
);
210 SIPE_DEBUG_INFO_NOFORMAT("sipe_ews_autodiscover_request: no more methods to try!");
211 sipe_ews_autodiscover_complete(sipe_private
, NULL
);
215 void sipe_ews_autodiscover_start(struct sipe_core_private
*sipe_private
,
216 sipe_ews_autodiscover_callback
*callback
,
217 gpointer callback_data
)
219 struct sipe_ews_autodiscover
*sea
= sipe_private
->ews_autodiscover
;
221 if (sea
->completed
) {
222 (*callback
)(sipe_private
, sea
->data
, callback_data
);
224 struct sipe_ews_autodiscover_cb
*sea_cb
= g_new(struct sipe_ews_autodiscover_cb
, 1);
225 sea_cb
->cb
= callback
;
226 sea_cb
->cb_data
= callback_data
;
227 sea
->callbacks
= g_slist_prepend(sea
->callbacks
, sea_cb
);
230 sipe_ews_autodiscover_request(sipe_private
, TRUE
);
234 void sipe_ews_autodiscover_init(struct sipe_core_private
*sipe_private
)
236 struct sipe_ews_autodiscover
*sea
= g_new0(struct sipe_ews_autodiscover
, 1);
238 sea
->domain
= strstr(sipe_private
->email
, "@") + 1;
239 sipe_private
->ews_autodiscover
= sea
;
242 void sipe_ews_autodiscover_free(struct sipe_core_private
*sipe_private
)
244 struct sipe_ews_autodiscover
*sea
= sipe_private
->ews_autodiscover
;
245 struct sipe_ews_autodiscover_data
*ews_data
= sea
->data
;
246 sipe_ews_autodiscover_complete(sipe_private
, NULL
);
248 g_free((gchar
*)ews_data
->as_url
);
249 g_free((gchar
*)ews_data
->ews_url
);
250 g_free((gchar
*)ews_data
->legacy_dn
);
251 g_free((gchar
*)ews_data
->oab_url
);
252 g_free((gchar
*)ews_data
->oof_url
);