You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
784 lines
26 KiB
784 lines
26 KiB
diff -up evolution-ews-3.28.5/src/configuration/e-mail-config-ews-backend.c.autodiscover-improvements evolution-ews-3.28.5/src/configuration/e-mail-config-ews-backend.c
|
|
--- evolution-ews-3.28.5/src/configuration/e-mail-config-ews-backend.c.autodiscover-improvements 2022-05-06 09:52:48.565933224 +0200
|
|
+++ evolution-ews-3.28.5/src/configuration/e-mail-config-ews-backend.c 2022-05-06 09:52:48.570933226 +0200
|
|
@@ -661,8 +661,10 @@ mail_config_ews_backend_setup_defaults (
|
|
camel_ews_settings_set_hosturl (ews_settings, hosturl);
|
|
camel_ews_settings_set_email (ews_settings, email_address);
|
|
|
|
+ /* Prefill email address as the user name, it's needed for office365.com
|
|
+ server, but also on-premise servers support it. */
|
|
network_settings = CAMEL_NETWORK_SETTINGS (settings);
|
|
- camel_network_settings_set_user (network_settings, parts[0]);
|
|
+ camel_network_settings_set_user (network_settings, email_address);
|
|
|
|
g_free (hosturl);
|
|
}
|
|
diff -up evolution-ews-3.28.5/src/server/e-ews-connection.c.autodiscover-improvements evolution-ews-3.28.5/src/server/e-ews-connection.c
|
|
--- evolution-ews-3.28.5/src/server/e-ews-connection.c.autodiscover-improvements 2022-05-06 09:52:48.567933225 +0200
|
|
+++ evolution-ews-3.28.5/src/server/e-ews-connection.c 2022-05-06 12:23:47.370716242 +0200
|
|
@@ -468,6 +468,38 @@ autodiscover_parse_protocol (xmlNode *no
|
|
return FALSE;
|
|
}
|
|
|
|
+static xmlChar *
|
|
+autodiscover_get_protocol_type (xmlNode *node)
|
|
+{
|
|
+ for (node = node->children; node; node = node->next) {
|
|
+ if (node->type == XML_ELEMENT_NODE &&
|
|
+ !strcmp ((gchar *) node->name, "Type")) {
|
|
+ return xmlNodeGetContent (node);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static gchar *
|
|
+autodiscover_dup_element_value (xmlNode *node,
|
|
+ const gchar *element_name)
|
|
+{
|
|
+ for (node = node->children; node; node = node->next) {
|
|
+ if (node->type == XML_ELEMENT_NODE &&
|
|
+ !g_strcmp0 ((gchar *) node->name, element_name)) {
|
|
+ xmlChar *str = xmlNodeGetContent (node);
|
|
+ gchar *res;
|
|
+
|
|
+ res = g_strdup ((const gchar *) str);
|
|
+ xmlFree (str);
|
|
+ return res;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
static gint
|
|
comp_func (gconstpointer a,
|
|
gconstpointer b)
|
|
@@ -2916,11 +2948,16 @@ e_ews_autodiscover_ws_xml (const gchar *
|
|
struct _autodiscover_data {
|
|
EEwsConnection *cnc;
|
|
xmlOutputBuffer *buf;
|
|
- SoupMessage *msgs[5];
|
|
+ SoupMessage *msgs[6];
|
|
|
|
GCancellable *cancellable;
|
|
gulong cancel_id;
|
|
|
|
+ GError *error;
|
|
+ gchar *redirect_addr;
|
|
+ gchar *redirect_url;
|
|
+ gint n_redirects;
|
|
+
|
|
/* Results */
|
|
gchar *as_url;
|
|
gchar *oab_url;
|
|
@@ -2944,6 +2981,10 @@ autodiscover_data_free (struct _autodisc
|
|
its worker thread. */
|
|
g_object_unref (ad->cnc);
|
|
|
|
+ g_clear_error (&ad->error);
|
|
+
|
|
+ g_free (ad->redirect_addr);
|
|
+ g_free (ad->redirect_url);
|
|
g_free (ad->as_url);
|
|
g_free (ad->oab_url);
|
|
|
|
@@ -2957,6 +2998,28 @@ autodiscover_cancelled_cb (GCancellable
|
|
ews_connection_schedule_abort (cnc);
|
|
}
|
|
|
|
+/* Frees only the content, not the 'urls' structure itself */
|
|
+static void
|
|
+ews_urls_free_content (EwsUrls *urls)
|
|
+{
|
|
+ if (!urls)
|
|
+ return;
|
|
+
|
|
+ if (urls->as_url)
|
|
+ xmlFree (urls->as_url);
|
|
+ urls->as_url = NULL;
|
|
+
|
|
+ if (urls->oab_url)
|
|
+ xmlFree (urls->oab_url);
|
|
+ urls->oab_url = NULL;
|
|
+}
|
|
+
|
|
+static gboolean
|
|
+e_ews_discover_prepare_messages_and_send (GSimpleAsyncResult *simple,
|
|
+ const gchar *email_address,
|
|
+ const gchar *override_url,
|
|
+ GError **error);
|
|
+
|
|
/* Called when each soup message completes */
|
|
static void
|
|
autodiscover_response_cb (SoupSession *session,
|
|
@@ -2966,21 +3029,24 @@ autodiscover_response_cb (SoupSession *s
|
|
{
|
|
GSimpleAsyncResult *simple = data;
|
|
struct _autodiscover_data *ad;
|
|
- EwsUrls *urls = NULL;
|
|
+ EwsUrls exch_urls, expr_urls;
|
|
guint status = msg->status_code;
|
|
xmlDoc *doc;
|
|
xmlNode *node;
|
|
+ gchar *str;
|
|
gint idx;
|
|
- gboolean success = FALSE;
|
|
GError *error = NULL;
|
|
|
|
+ memset (&exch_urls, 0, sizeof (EwsUrls));
|
|
+ memset (&expr_urls, 0, sizeof (EwsUrls));
|
|
+
|
|
ad = g_simple_async_result_get_op_res_gpointer (simple);
|
|
|
|
- for (idx = 0; idx < 5; idx++) {
|
|
+ for (idx = 0; idx < 6; idx++) {
|
|
if (ad->msgs[idx] == msg)
|
|
break;
|
|
}
|
|
- if (idx == 5) {
|
|
+ if (idx == 6 || (idx == 5 && !ad->msgs[5])) {
|
|
/* We already got removed (cancelled). Do nothing */
|
|
goto unref;
|
|
}
|
|
@@ -3048,33 +3114,54 @@ autodiscover_response_cb (SoupSession *s
|
|
goto failed;
|
|
}
|
|
|
|
- urls = g_new0 (EwsUrls, 1);
|
|
+ str = autodiscover_dup_element_value (node, "RedirectAddr");
|
|
+ if (str) {
|
|
+ g_free (ad->redirect_addr);
|
|
+ ad->redirect_addr = str;
|
|
+ }
|
|
+
|
|
+ str = autodiscover_dup_element_value (node, "RedirectUrl");
|
|
+ if (str) {
|
|
+ g_free (ad->redirect_url);
|
|
+ ad->redirect_url = str;
|
|
+ }
|
|
+
|
|
for (node = node->children; node; node = node->next) {
|
|
if (node->type == XML_ELEMENT_NODE &&
|
|
!strcmp ((gchar *) node->name, "Protocol")) {
|
|
- success = autodiscover_parse_protocol (node, urls);
|
|
- /* Since the server may send back multiple <Protocol> nodes
|
|
- * don't break unless we found the both URLs.
|
|
- */
|
|
- if (success)
|
|
- break;
|
|
+ xmlChar *protocol_type = autodiscover_get_protocol_type (node);
|
|
+
|
|
+ if (g_strcmp0 ((const gchar *) protocol_type, "EXCH") == 0) {
|
|
+ ews_urls_free_content (&exch_urls);
|
|
+ autodiscover_parse_protocol (node, &exch_urls);
|
|
+ } else if (g_strcmp0 ((const gchar *) protocol_type, "EXPR") == 0) {
|
|
+ ews_urls_free_content (&expr_urls);
|
|
+ autodiscover_parse_protocol (node, &expr_urls);
|
|
+
|
|
+ /* EXPR has precedence, thus stop once found both there */
|
|
+ if (expr_urls.as_url && expr_urls.oab_url) {
|
|
+ xmlFree (protocol_type);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (protocol_type)
|
|
+ xmlFree (protocol_type);
|
|
}
|
|
}
|
|
|
|
- if (!success) {
|
|
- if (urls->as_url != NULL)
|
|
- xmlFree (urls->as_url);
|
|
- if (urls->oab_url != NULL)
|
|
- xmlFree (urls->oab_url);
|
|
- g_free (urls);
|
|
+ /* Make the <OABUrl> optional */
|
|
+ if (!exch_urls.as_url && !expr_urls.as_url) {
|
|
+ ews_urls_free_content (&exch_urls);
|
|
+ ews_urls_free_content (&expr_urls);
|
|
g_set_error (
|
|
&error, EWS_CONNECTION_ERROR, -1,
|
|
- _("Failed to find <ASUrl> and <OABUrl> in autodiscover response"));
|
|
+ _("Failed to find <ASUrl> in autodiscover response"));
|
|
goto failed;
|
|
}
|
|
|
|
/* We have a good response; cancel all the others */
|
|
- for (idx = 0; idx < 5; idx++) {
|
|
+ for (idx = 0; idx < 6; idx++) {
|
|
if (ad->msgs[idx]) {
|
|
SoupMessage *m = ad->msgs[idx];
|
|
ad->msgs[idx] = NULL;
|
|
@@ -3082,35 +3169,130 @@ autodiscover_response_cb (SoupSession *s
|
|
}
|
|
}
|
|
|
|
- if (urls->as_url != NULL) {
|
|
- ad->as_url = g_strdup ((gchar *) urls->as_url);
|
|
- xmlFree (urls->as_url);
|
|
- }
|
|
-
|
|
- if (urls->oab_url != NULL) {
|
|
- ad->oab_url = g_strdup ((gchar *) urls->oab_url);
|
|
- xmlFree (urls->oab_url);
|
|
+ if (expr_urls.as_url) {
|
|
+ if (ad->as_url)
|
|
+ g_free (ad->as_url);
|
|
+ ad->as_url = g_strdup ((gchar *) expr_urls.as_url);
|
|
+ } else if (exch_urls.as_url) {
|
|
+ if (ad->as_url)
|
|
+ g_free (ad->as_url);
|
|
+ ad->as_url = g_strdup ((gchar *) exch_urls.as_url);
|
|
+ }
|
|
+
|
|
+ if (expr_urls.as_url && expr_urls.oab_url) {
|
|
+ if (ad->oab_url)
|
|
+ g_free (ad->oab_url);
|
|
+ ad->oab_url = g_strdup ((gchar *) expr_urls.oab_url);
|
|
+ } else if (!expr_urls.as_url && exch_urls.oab_url) {
|
|
+ if (ad->oab_url)
|
|
+ g_free (ad->oab_url);
|
|
+ ad->oab_url = g_strdup ((gchar *) exch_urls.oab_url);
|
|
}
|
|
|
|
- g_free (urls);
|
|
+ ews_urls_free_content (&exch_urls);
|
|
+ ews_urls_free_content (&expr_urls);
|
|
|
|
goto exit;
|
|
|
|
failed:
|
|
- for (idx = 0; idx < 5; idx++) {
|
|
+ for (idx = 0; idx < 6; idx++) {
|
|
if (ad->msgs[idx]) {
|
|
+ /* Preserve any Unauthorized/SSL failed errors */
|
|
+ if (!g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_NONE) &&
|
|
+ !g_error_matches (ad->error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED) &&
|
|
+ !g_error_matches (ad->error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED) &&
|
|
+ (!ad->error ||
|
|
+ g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED) ||
|
|
+ g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED) ||
|
|
+ g_error_matches (ad->error, SOUP_HTTP_ERROR, SOUP_STATUS_NONE) ||
|
|
+ g_error_matches (ad->error, SOUP_HTTP_ERROR, SOUP_STATUS_CANT_RESOLVE) ||
|
|
+ g_error_matches (ad->error, SOUP_HTTP_ERROR, SOUP_STATUS_CANT_RESOLVE_PROXY) ||
|
|
+ g_error_matches (ad->error, SOUP_HTTP_ERROR, SOUP_STATUS_CANT_CONNECT) ||
|
|
+ g_error_matches (ad->error, SOUP_HTTP_ERROR, SOUP_STATUS_CANT_CONNECT_PROXY))) {
|
|
+ g_clear_error (&ad->error);
|
|
+ ad->error = error;
|
|
+ error = NULL;
|
|
+ } else {
|
|
+ g_clear_error (&error);
|
|
+ }
|
|
+
|
|
/* There's another request outstanding.
|
|
* Hope that it has better luck. */
|
|
- g_clear_error (&error);
|
|
goto unref;
|
|
}
|
|
}
|
|
|
|
+ /* Preserve any Unauthorized/SSL failed errors */
|
|
+ if (!g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_NONE) &&
|
|
+ !g_error_matches (ad->error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED) &&
|
|
+ !g_error_matches (ad->error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED) &&
|
|
+ (!ad->error ||
|
|
+ g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED) ||
|
|
+ g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED) ||
|
|
+ g_error_matches (ad->error, SOUP_HTTP_ERROR, SOUP_STATUS_NONE) ||
|
|
+ g_error_matches (ad->error, SOUP_HTTP_ERROR, SOUP_STATUS_CANT_RESOLVE) ||
|
|
+ g_error_matches (ad->error, SOUP_HTTP_ERROR, SOUP_STATUS_CANT_RESOLVE_PROXY) ||
|
|
+ g_error_matches (ad->error, SOUP_HTTP_ERROR, SOUP_STATUS_CANT_CONNECT) ||
|
|
+ g_error_matches (ad->error, SOUP_HTTP_ERROR, SOUP_STATUS_CANT_CONNECT_PROXY))) {
|
|
+ g_clear_error (&ad->error);
|
|
+ ad->error = error;
|
|
+ error = NULL;
|
|
+ }
|
|
+
|
|
+ g_clear_error (&error);
|
|
+
|
|
+ if (!g_cancellable_is_cancelled (ad->cancellable) &&
|
|
+ (!ad->as_url || !ad->oab_url) && ad->n_redirects < 11 &&
|
|
+ (ad->redirect_url || ad->redirect_addr) &&
|
|
+ !g_error_matches (ad->error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED) &&
|
|
+ !g_error_matches (ad->error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED)) {
|
|
+ CamelEwsSettings *settings = NULL;
|
|
+ gboolean re_scheduled;
|
|
+ const gchar *host_url;
|
|
+ gchar *redirect_addr, *redirect_url;
|
|
+ GError *local_error;
|
|
+
|
|
+ redirect_addr = ad->redirect_addr;
|
|
+ redirect_url = ad->redirect_url;
|
|
+ local_error = ad->error;
|
|
+
|
|
+ /* To avoid infinite recursion */
|
|
+ ad->redirect_addr = NULL;
|
|
+ ad->redirect_url = NULL;
|
|
+ ad->n_redirects++;
|
|
+ ad->error = NULL;
|
|
+
|
|
+ host_url = redirect_url;
|
|
+ settings = e_ews_connection_ref_settings (ad->cnc);
|
|
+
|
|
+ if (!host_url)
|
|
+ host_url = camel_ews_settings_get_hosturl (settings);
|
|
+
|
|
+ if (redirect_addr && *redirect_addr)
|
|
+ camel_network_settings_set_user (CAMEL_NETWORK_SETTINGS (settings), redirect_addr);
|
|
+
|
|
+ re_scheduled = e_ews_discover_prepare_messages_and_send (simple, redirect_addr, host_url, NULL);
|
|
+
|
|
+ g_clear_object (&settings);
|
|
+
|
|
+ g_free (redirect_addr);
|
|
+ g_free (redirect_url);
|
|
+
|
|
+ if (re_scheduled) {
|
|
+ g_clear_error (&local_error);
|
|
+ goto unref;
|
|
+ }
|
|
+
|
|
+ ad->error = local_error;
|
|
+ }
|
|
+
|
|
/* FIXME: We're actually returning the *last* error here,
|
|
* and in some cases (stupid firewalls causing timeouts)
|
|
* that's going to be the least interesting one. We probably
|
|
* want the *first* error */
|
|
- g_simple_async_result_take_error (simple, error);
|
|
+ g_simple_async_result_take_error (simple, ad->error);
|
|
+
|
|
+ ad->error = NULL;
|
|
|
|
exit:
|
|
g_simple_async_result_complete_in_idle (simple);
|
|
@@ -3125,7 +3307,10 @@ autodiscover_response_cb (SoupSession *s
|
|
e_ews_connection_utils_unref_in_thread (simple);
|
|
}
|
|
|
|
-static void post_restarted (SoupMessage *msg, gpointer data)
|
|
+
|
|
+static void
|
|
+post_restarted (SoupMessage *msg,
|
|
+ gpointer data)
|
|
{
|
|
xmlOutputBuffer *buf = data;
|
|
|
|
@@ -3151,12 +3336,12 @@ static void post_restarted (SoupMessage
|
|
|
|
static SoupMessage *
|
|
e_ews_get_msg_for_url (EEwsConnection *cnc,
|
|
- CamelEwsSettings *settings,
|
|
const gchar *url,
|
|
xmlOutputBuffer *buf,
|
|
GError **error)
|
|
{
|
|
SoupMessage *msg;
|
|
+ CamelEwsSettings *settings;
|
|
|
|
if (url == NULL) {
|
|
g_set_error_literal (
|
|
@@ -3178,7 +3363,9 @@ e_ews_get_msg_for_url (EEwsConnection *c
|
|
|
|
e_ews_message_attach_chunk_allocator (msg);
|
|
|
|
+ settings = e_ews_connection_ref_settings (cnc);
|
|
e_ews_message_set_user_agent_header (msg, settings);
|
|
+ g_clear_object (&settings);
|
|
|
|
if (buf != NULL) {
|
|
soup_message_set_request (
|
|
@@ -3189,7 +3376,7 @@ e_ews_get_msg_for_url (EEwsConnection *c
|
|
#else
|
|
buf->buffer->content, buf->buffer->use
|
|
#endif
|
|
- );
|
|
+ );
|
|
g_signal_connect (
|
|
msg, "restarted",
|
|
G_CALLBACK (post_restarted), buf);
|
|
@@ -3200,6 +3387,69 @@ e_ews_get_msg_for_url (EEwsConnection *c
|
|
return msg;
|
|
}
|
|
|
|
+static void
|
|
+autodiscover_srv_record_resolved_cb (GObject *source,
|
|
+ GAsyncResult *result,
|
|
+ gpointer user_data)
|
|
+{
|
|
+ GList *targets, *link;
|
|
+ GSimpleAsyncResult *simple = user_data;
|
|
+ struct _autodiscover_data *ad;
|
|
+ gchar *new_uri = NULL;
|
|
+ gboolean success;
|
|
+
|
|
+ ad = g_simple_async_result_get_op_res_gpointer (simple);
|
|
+
|
|
+ g_return_if_fail (ad != NULL);
|
|
+
|
|
+ targets = g_resolver_lookup_service_finish (G_RESOLVER (source), result, NULL);
|
|
+
|
|
+ success = ad->msgs[5] && targets;
|
|
+
|
|
+ for (link = targets; link && success; link = g_list_next (link)) {
|
|
+ GSrvTarget *target = link->data;
|
|
+ const gchar *hostname;
|
|
+
|
|
+ hostname = g_srv_target_get_hostname (target);
|
|
+
|
|
+ switch (g_srv_target_get_port (target)) {
|
|
+ case 80:
|
|
+ link = NULL;
|
|
+ new_uri = g_strdup_printf ("http://%s/autodiscover/autodiscover.xml", hostname);
|
|
+ break;
|
|
+ case 443:
|
|
+ link = NULL;
|
|
+ new_uri = g_strdup_printf ("https://%s/autodiscover/autodiscover.xml", hostname);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ g_list_free_full (targets, (GDestroyNotify) g_srv_target_free);
|
|
+
|
|
+ if (new_uri && success) {
|
|
+ SoupURI *suri;
|
|
+
|
|
+ suri = soup_uri_new (new_uri);
|
|
+ if (suri) {
|
|
+ soup_message_set_uri (ad->msgs[5], suri);
|
|
+ /* The autodiscover_response_cb will free the 'simple' */
|
|
+ ews_connection_schedule_queue_message (ad->cnc, ad->msgs[5], autodiscover_response_cb, simple);
|
|
+ soup_uri_free (suri);
|
|
+ } else {
|
|
+ success = FALSE;
|
|
+ }
|
|
+ } else {
|
|
+ success = FALSE;
|
|
+ }
|
|
+
|
|
+ g_free (new_uri);
|
|
+
|
|
+ if (!success) {
|
|
+ /* The callback also frees the 'simple' */
|
|
+ autodiscover_response_cb (NULL, ad->msgs[5], simple);
|
|
+ }
|
|
+}
|
|
+
|
|
gboolean
|
|
e_ews_autodiscover_ws_url_sync (ESource *source,
|
|
CamelEwsSettings *settings,
|
|
@@ -3232,50 +3482,43 @@ e_ews_autodiscover_ws_url_sync (ESource
|
|
return success;
|
|
}
|
|
|
|
-void
|
|
-e_ews_autodiscover_ws_url (ESource *source,
|
|
- CamelEwsSettings *settings,
|
|
- const gchar *email_address,
|
|
- const gchar *password,
|
|
- GCancellable *cancellable,
|
|
- GAsyncReadyCallback callback,
|
|
- gpointer user_data)
|
|
+static gboolean
|
|
+e_ews_discover_prepare_messages_and_send (GSimpleAsyncResult *simple,
|
|
+ const gchar *email_address,
|
|
+ const gchar *override_url,
|
|
+ GError **error)
|
|
{
|
|
- GSimpleAsyncResult *simple;
|
|
- struct _autodiscover_data *ad;
|
|
- xmlOutputBuffer *buf;
|
|
- gchar *url1, *url2, *url3, *url4, *url5;
|
|
- gchar *domain;
|
|
- xmlDoc *doc;
|
|
- EEwsConnection *cnc;
|
|
SoupURI *soup_uri = NULL;
|
|
gboolean use_secure = TRUE;
|
|
- const gchar *host_url;
|
|
- GError *error = NULL;
|
|
+ gboolean is_outlook = FALSE;
|
|
+ gchar *url1, *url2, *url3, *url4;
|
|
+ const gchar *url5, *domain = NULL;
|
|
+ struct _autodiscover_data *ad;
|
|
+ GError *local_error = NULL;
|
|
|
|
- g_return_if_fail (CAMEL_IS_EWS_SETTINGS (settings));
|
|
- g_return_if_fail (email_address != NULL);
|
|
- g_return_if_fail (password != NULL);
|
|
+ ad = g_simple_async_result_get_op_res_gpointer (simple);
|
|
+ g_return_val_if_fail (ad != NULL, FALSE);
|
|
|
|
- simple = g_simple_async_result_new (
|
|
- G_OBJECT (settings), callback,
|
|
- user_data, e_ews_autodiscover_ws_url);
|
|
+ if (email_address) {
|
|
+ xmlDoc *doc;
|
|
|
|
- domain = strchr (email_address, '@');
|
|
- if (domain == NULL || *domain == '\0') {
|
|
- g_simple_async_result_set_error (
|
|
- simple, EWS_CONNECTION_ERROR, -1,
|
|
- "%s", _("Email address is missing a domain part"));
|
|
- g_simple_async_result_complete_in_idle (simple);
|
|
- g_object_unref (simple);
|
|
- return;
|
|
+ if (ad->buf)
|
|
+ xmlOutputBufferClose (ad->buf);
|
|
+
|
|
+ doc = e_ews_autodiscover_ws_xml (email_address);
|
|
+ ad->buf = xmlAllocOutputBuffer (NULL);
|
|
+ xmlNodeDumpOutput (ad->buf, doc, xmlDocGetRootElement (doc), 0, 1, NULL);
|
|
+ xmlOutputBufferFlush (ad->buf);
|
|
+
|
|
+ xmlFreeDoc (doc);
|
|
+
|
|
+ domain = strchr (email_address, '@');
|
|
+ if (domain)
|
|
+ domain++;
|
|
}
|
|
- domain++;
|
|
|
|
- doc = e_ews_autodiscover_ws_xml (email_address);
|
|
- buf = xmlAllocOutputBuffer (NULL);
|
|
- xmlNodeDumpOutput (buf, doc, xmlDocGetRootElement (doc), 0, 1, NULL);
|
|
- xmlOutputBufferFlush (buf);
|
|
+ g_return_val_if_fail (ad->buf != NULL, FALSE);
|
|
+ g_return_val_if_fail ((domain && *domain) || (override_url && *override_url), FALSE);
|
|
|
|
url1 = NULL;
|
|
url2 = NULL;
|
|
@@ -3283,11 +3526,10 @@ e_ews_autodiscover_ws_url (ESource *sour
|
|
url4 = NULL;
|
|
url5 = NULL;
|
|
|
|
- host_url = camel_ews_settings_get_hosturl (settings);
|
|
- if (host_url != NULL)
|
|
- soup_uri = soup_uri_new (host_url);
|
|
+ if (override_url)
|
|
+ soup_uri = soup_uri_new (override_url);
|
|
|
|
- if (soup_uri != NULL) {
|
|
+ if (soup_uri) {
|
|
const gchar *host = soup_uri_get_host (soup_uri);
|
|
const gchar *scheme = soup_uri_get_scheme (soup_uri);
|
|
|
|
@@ -3296,20 +3538,126 @@ e_ews_autodiscover_ws_url (ESource *sour
|
|
url1 = g_strdup_printf ("http%s://%s/autodiscover/autodiscover.xml", use_secure ? "s" : "", host);
|
|
url2 = g_strdup_printf ("http%s://autodiscover.%s/autodiscover/autodiscover.xml", use_secure ? "s" : "", host);
|
|
|
|
+ is_outlook = host && g_ascii_strcasecmp (host, "outlook.office365.com") == 0;
|
|
+
|
|
/* outlook.office365.com has its autodiscovery at outlook.com */
|
|
- if (host && g_ascii_strcasecmp (host, "outlook.office365.com") == 0 &&
|
|
- domain && g_ascii_strcasecmp (host, "outlook.com") != 0) {
|
|
- url5 = g_strdup_printf ("https://outlook.com/autodiscover/autodiscover.xml");
|
|
+ if (is_outlook && domain && g_ascii_strcasecmp (domain, "outlook.com") != 0) {
|
|
+ url5 = "https://outlook.com/autodiscover/autodiscover.xml";
|
|
+ } else if (!is_outlook && domain) {
|
|
+ #define ON_MICROSOFT_COM_TEXT "onmicrosoft.com"
|
|
+ gint len = strlen (domain);
|
|
+ gint onmslen = strlen (ON_MICROSOFT_COM_TEXT);
|
|
+
|
|
+ if (len >= onmslen) {
|
|
+ const gchar *test_domain;
|
|
+
|
|
+ test_domain = domain + len - onmslen;
|
|
+
|
|
+ /* onmicrosoft.com addresses might be handled on the outlook.com/office365.com as well */
|
|
+ if (g_ascii_strcasecmp (test_domain, ON_MICROSOFT_COM_TEXT) == 0 &&
|
|
+ (len == onmslen || (len > onmslen && domain[len - onmslen - 1] == '.')))
|
|
+ url5 = "https://outlook.com/autodiscover/autodiscover.xml";
|
|
+ }
|
|
+ #undef ON_MICROSOFT_COM_TEXT
|
|
}
|
|
|
|
soup_uri_free (soup_uri);
|
|
}
|
|
|
|
- url3 = g_strdup_printf ("http%s://%s/autodiscover/autodiscover.xml", use_secure ? "s" : "", domain);
|
|
- url4 = g_strdup_printf ("http%s://autodiscover.%s/autodiscover/autodiscover.xml", use_secure ? "s" : "", domain);
|
|
+ is_outlook = is_outlook || (domain && g_ascii_strcasecmp (domain, "outlook.com") == 0);
|
|
+
|
|
+ if (domain) {
|
|
+ url3 = g_strdup_printf ("http%s://%s/autodiscover/autodiscover.xml", use_secure ? "s" : "", domain);
|
|
+ url4 = g_strdup_printf ("http%s://autodiscover.%s/autodiscover/autodiscover.xml", use_secure ? "s" : "", domain);
|
|
+ }
|
|
+
|
|
+ /* Passing a NULL URL string returns NULL. */
|
|
+ ad->msgs[0] = e_ews_get_msg_for_url (ad->cnc, url1, ad->buf, &local_error);
|
|
+ ad->msgs[1] = e_ews_get_msg_for_url (ad->cnc, url2, ad->buf, local_error ? NULL : &local_error);
|
|
+ ad->msgs[2] = e_ews_get_msg_for_url (ad->cnc, url3, ad->buf, local_error ? NULL : &local_error);
|
|
+ ad->msgs[3] = e_ews_get_msg_for_url (ad->cnc, url4, ad->buf, local_error ? NULL : &local_error);
|
|
+ ad->msgs[4] = e_ews_get_msg_for_url (ad->cnc, url5, ad->buf, local_error ? NULL : &local_error);
|
|
+
|
|
+ if (!is_outlook && domain && *domain && (ad->msgs[0] || ad->msgs[1] || ad->msgs[2] || ad->msgs[3] || ad->msgs[4])) {
|
|
+ gchar *tmp;
|
|
+
|
|
+ tmp = g_strdup_printf ("http%s://%s/", use_secure ? "s" : "", domain);
|
|
+
|
|
+ /* Fake SoupMessage, for the autodiscovery with SRV record help */
|
|
+ ad->msgs[5] = e_ews_get_msg_for_url (ad->cnc, tmp, ad->buf, local_error ? NULL : &local_error);
|
|
+
|
|
+ if (ad->msgs[5]) {
|
|
+ g_resolver_lookup_service_async (g_resolver_get_default (), "autodiscover", "tcp", domain, ad->cancellable,
|
|
+ autodiscover_srv_record_resolved_cb, g_object_ref (simple));
|
|
+ }
|
|
+
|
|
+ g_free (tmp);
|
|
+ } else {
|
|
+ ad->msgs[5] = NULL;
|
|
+ }
|
|
+
|
|
+ if (local_error && (ad->msgs[0] || ad->msgs[1] || ad->msgs[2] || ad->msgs[3] || ad->msgs[4]))
|
|
+ g_clear_error (&local_error);
|
|
+
|
|
+ /* These have to be submitted only after they're both set in ad->msgs[]
|
|
+ * or there will be races with fast completion */
|
|
+ if (ad->msgs[0] != NULL)
|
|
+ ews_connection_schedule_queue_message (ad->cnc, ad->msgs[0], autodiscover_response_cb, g_object_ref (simple));
|
|
+ if (ad->msgs[1] != NULL)
|
|
+ ews_connection_schedule_queue_message (ad->cnc, ad->msgs[1], autodiscover_response_cb, g_object_ref (simple));
|
|
+ if (ad->msgs[2] != NULL)
|
|
+ ews_connection_schedule_queue_message (ad->cnc, ad->msgs[2], autodiscover_response_cb, g_object_ref (simple));
|
|
+ if (ad->msgs[3] != NULL)
|
|
+ ews_connection_schedule_queue_message (ad->cnc, ad->msgs[3], autodiscover_response_cb, g_object_ref (simple));
|
|
+ if (ad->msgs[4] != NULL)
|
|
+ ews_connection_schedule_queue_message (ad->cnc, ad->msgs[4], autodiscover_response_cb, g_object_ref (simple));
|
|
+
|
|
+ g_free (url1);
|
|
+ g_free (url2);
|
|
+ g_free (url3);
|
|
+ g_free (url4);
|
|
+
|
|
+ if (local_error) {
|
|
+ g_propagate_error (error, local_error);
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+void
|
|
+e_ews_autodiscover_ws_url (ESource *source,
|
|
+ CamelEwsSettings *settings,
|
|
+ const gchar *email_address,
|
|
+ const gchar *password,
|
|
+ GCancellable *cancellable,
|
|
+ GAsyncReadyCallback callback,
|
|
+ gpointer user_data)
|
|
+{
|
|
+ GSimpleAsyncResult *simple;
|
|
+ struct _autodiscover_data *ad;
|
|
+ const gchar *domain;
|
|
+ const gchar *host_url;
|
|
+ GError *error = NULL;
|
|
+
|
|
+ g_return_if_fail (CAMEL_IS_EWS_SETTINGS (settings));
|
|
+ g_return_if_fail (email_address != NULL);
|
|
+ g_return_if_fail (password != NULL);
|
|
+
|
|
+ simple = g_simple_async_result_new (
|
|
+ G_OBJECT (settings), callback,
|
|
+ user_data, e_ews_autodiscover_ws_url);
|
|
|
|
- cnc = e_ews_connection_new (source, url3, settings);
|
|
- e_ews_connection_set_password (cnc, password);
|
|
+ domain = strchr (email_address, '@');
|
|
+ /* if it's non-NULL, then domain[0] == '@' */
|
|
+ if (!domain || !domain[1]) {
|
|
+ g_simple_async_result_set_error (
|
|
+ simple, EWS_CONNECTION_ERROR, -1,
|
|
+ "%s", _("Email address is missing a domain part"));
|
|
+ g_simple_async_result_complete_in_idle (simple);
|
|
+ g_object_unref (simple);
|
|
+ return;
|
|
+ }
|
|
|
|
/*
|
|
* http://msdn.microsoft.com/en-us/library/ee332364.aspx says we are
|
|
@@ -3320,48 +3668,25 @@ e_ews_autodiscover_ws_url (ESource *sour
|
|
* (successful) one win.
|
|
*/
|
|
ad = g_slice_new0 (struct _autodiscover_data);
|
|
- ad->cnc = cnc; /* takes ownership */
|
|
- ad->buf = buf; /* takes ownership */
|
|
+ ad->cnc = e_ews_connection_new (source, domain + 1, settings); /* Fake URI, it's not used here */
|
|
+ g_object_set (ad->cnc->priv->soup_session, SOUP_SESSION_TIMEOUT, 20, NULL);
|
|
+ e_ews_connection_set_password (ad->cnc, password);
|
|
|
|
if (G_IS_CANCELLABLE (cancellable)) {
|
|
ad->cancellable = g_object_ref (cancellable);
|
|
ad->cancel_id = g_cancellable_connect (
|
|
ad->cancellable,
|
|
G_CALLBACK (autodiscover_cancelled_cb),
|
|
- g_object_ref (cnc),
|
|
+ g_object_ref (ad->cnc),
|
|
g_object_unref);
|
|
}
|
|
|
|
g_simple_async_result_set_op_res_gpointer (
|
|
simple, ad, (GDestroyNotify) autodiscover_data_free);
|
|
|
|
- /* Passing a NULL URL string returns NULL. */
|
|
- ad->msgs[0] = e_ews_get_msg_for_url (cnc, settings, url1, buf, &error);
|
|
- ad->msgs[1] = e_ews_get_msg_for_url (cnc, settings, url2, buf, NULL);
|
|
- ad->msgs[2] = e_ews_get_msg_for_url (cnc, settings, url3, buf, NULL);
|
|
- ad->msgs[3] = e_ews_get_msg_for_url (cnc, settings, url4, buf, NULL);
|
|
- ad->msgs[4] = e_ews_get_msg_for_url (cnc, settings, url5, buf, NULL);
|
|
-
|
|
- /* These have to be submitted only after they're both set in ad->msgs[]
|
|
- * or there will be races with fast completion */
|
|
- if (ad->msgs[0] != NULL)
|
|
- ews_connection_schedule_queue_message (cnc, ad->msgs[0], autodiscover_response_cb, g_object_ref (simple));
|
|
- if (ad->msgs[1] != NULL)
|
|
- ews_connection_schedule_queue_message (cnc, ad->msgs[1], autodiscover_response_cb, g_object_ref (simple));
|
|
- if (ad->msgs[2] != NULL)
|
|
- ews_connection_schedule_queue_message (cnc, ad->msgs[2], autodiscover_response_cb, g_object_ref (simple));
|
|
- if (ad->msgs[3] != NULL)
|
|
- ews_connection_schedule_queue_message (cnc, ad->msgs[3], autodiscover_response_cb, g_object_ref (simple));
|
|
- if (ad->msgs[4] != NULL)
|
|
- ews_connection_schedule_queue_message (cnc, ad->msgs[4], autodiscover_response_cb, g_object_ref (simple));
|
|
-
|
|
- xmlFreeDoc (doc);
|
|
- g_free (url1);
|
|
- g_free (url2);
|
|
- g_free (url3);
|
|
- g_free (url4);
|
|
+ host_url = camel_ews_settings_get_hosturl (settings);
|
|
|
|
- if (error && !ad->msgs[0] && !ad->msgs[1] && !ad->msgs[2] && !ad->msgs[3] && !ad->msgs[4]) {
|
|
+ if (!e_ews_discover_prepare_messages_and_send (simple, email_address, host_url, &error)) {
|
|
g_simple_async_result_take_error (simple, error);
|
|
g_simple_async_result_complete_in_idle (simple);
|
|
} else {
|
|
@@ -3735,7 +4060,7 @@ e_ews_connection_get_oal_list (EEwsConne
|
|
|
|
g_return_if_fail (E_IS_EWS_CONNECTION (cnc));
|
|
|
|
- soup_message = e_ews_get_msg_for_url (cnc, cnc->priv->settings, cnc->priv->uri, NULL, &error);
|
|
+ soup_message = e_ews_get_msg_for_url (cnc, cnc->priv->uri, NULL, &error);
|
|
|
|
simple = g_simple_async_result_new (
|
|
G_OBJECT (cnc), callback, user_data,
|
|
@@ -3856,7 +4181,7 @@ e_ews_connection_get_oal_detail (EEwsCon
|
|
|
|
g_return_if_fail (E_IS_EWS_CONNECTION (cnc));
|
|
|
|
- soup_message = e_ews_get_msg_for_url (cnc, cnc->priv->settings, cnc->priv->uri, NULL, &error);
|
|
+ soup_message = e_ews_get_msg_for_url (cnc, cnc->priv->uri, NULL, &error);
|
|
|
|
simple = g_simple_async_result_new (
|
|
G_OBJECT (cnc), callback, user_data,
|
|
@@ -4073,7 +4398,7 @@ e_ews_connection_download_oal_file (EEws
|
|
|
|
g_return_if_fail (E_IS_EWS_CONNECTION (cnc));
|
|
|
|
- soup_message = e_ews_get_msg_for_url (cnc, cnc->priv->settings, cnc->priv->uri, NULL, &error);
|
|
+ soup_message = e_ews_get_msg_for_url (cnc, cnc->priv->uri, NULL, &error);
|
|
|
|
simple = g_simple_async_result_new (
|
|
G_OBJECT (cnc), callback, user_data,
|