diff --git a/SOURCES/evolution-ews-3.28.5-autodiscover-improvements.patch b/SOURCES/evolution-ews-3.28.5-autodiscover-improvements.patch new file mode 100644 index 0000000..6b41ec3 --- /dev/null +++ b/SOURCES/evolution-ews-3.28.5-autodiscover-improvements.patch @@ -0,0 +1,783 @@ +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 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 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 and in autodiscover response")); ++ _("Failed to find 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, diff --git a/SPECS/evolution-ews.spec b/SPECS/evolution-ews.spec index 0855364..a8e8a03 100644 --- a/SPECS/evolution-ews.spec +++ b/SPECS/evolution-ews.spec @@ -2,7 +2,7 @@ Name: evolution-ews Version: 3.28.5 -Release: 11%{?dist} +Release: 13%{?dist} Group: Applications/Productivity Summary: Evolution extension for Exchange Web Services License: LGPLv2 @@ -49,6 +49,9 @@ Patch12: evolution-ews-3.28.5-oauth2-endpoints.patch # RH bug #1972749 Patch13: evolution-ews-3.28.5-cmake-variable-name-comparison.patch +# RH bug #2082245 +Patch14: evolution-ews-3.28.5-autodiscover-improvements.patch + Requires: evolution >= %{eds_evo_version} Requires: evolution-data-server >= %{eds_evo_version} Requires: %{name}-langpacks = %{version}-%{release} @@ -101,6 +104,7 @@ This package contains translations for %{name}. %patch11 -p1 -b .oauth2-simplify %patch12 -p1 -b .oauth2-endpoints %patch13 -p1 -b .cmake-variable-name-comparison +%patch14 -p1 -b .autodiscover-improvements %build @@ -141,6 +145,12 @@ make install DESTDIR=$RPM_BUILD_ROOT %files langpacks -f _build/%{name}.lang %changelog +* Fri May 06 2022 Milan Crha - 3.28.5-13 +- Related: #2082245 (Fix issues in the patch found by Coverity scan) + +* Fri May 06 2022 Milan Crha - 3.28.5-12 +- Resolves: #2082245 (Backport fixes to improve autodiscovery) + * Wed Jun 16 2021 Milan Crha - 3.28.5-11 - Resolves: #1972749 (PrintableOptions.cmake: Correct variable name comparison)