Blame src/goabackend/goaewsclient.c

Packit 79f644
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
Packit 79f644
/*
Packit 79f644
 * Copyright © 2012 – 2017 Red Hat, Inc.
Packit 79f644
 *
Packit 79f644
 * This library is free software; you can redistribute it and/or
Packit 79f644
 * modify it under the terms of the GNU Lesser General Public
Packit 79f644
 * License as published by the Free Software Foundation; either
Packit 79f644
 * version 2 of the License, or (at your option) any later version.
Packit 79f644
 *
Packit 79f644
 * This library is distributed in the hope that it will be useful,
Packit 79f644
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 79f644
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 79f644
 * Lesser General Public License for more details.
Packit 79f644
 *
Packit 79f644
 * You should have received a copy of the GNU Lesser General
Packit 79f644
 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
Packit 79f644
 */
Packit 79f644
Packit 79f644
/* Based on code by the Evolution team.
Packit 79f644
 *
Packit 79f644
 * This was originally written as a part of evolution-ews:
Packit 79f644
 * evolution-ews/src/server/e-ews-connection.c
Packit 79f644
 */
Packit 79f644
Packit 79f644
#include "config.h"
Packit 79f644
Packit 79f644
#include <glib/gi18n-lib.h>
Packit 79f644
Packit 79f644
#include <libsoup/soup.h>
Packit 79f644
#include <libxml/xmlIO.h>
Packit 79f644
Packit 79f644
#include "goaewsclient.h"
Packit 79f644
#include "goautils.h"
Packit 79f644
Packit 79f644
struct _GoaEwsClient
Packit 79f644
{
Packit 79f644
  GObject parent_instance;
Packit 79f644
};
Packit 79f644
Packit 79f644
G_DEFINE_TYPE (GoaEwsClient, goa_ews_client, G_TYPE_OBJECT);
Packit 79f644
Packit 79f644
/* ---------------------------------------------------------------------------------------------------- */
Packit 79f644
Packit 79f644
static void
Packit 79f644
goa_ews_client_init (GoaEwsClient *self)
Packit 79f644
{
Packit 79f644
}
Packit 79f644
Packit 79f644
static void
Packit 79f644
goa_ews_client_class_init (GoaEwsClientClass *self)
Packit 79f644
{
Packit 79f644
}
Packit 79f644
Packit 79f644
/* ---------------------------------------------------------------------------------------------------- */
Packit 79f644
Packit 79f644
GoaEwsClient *
Packit 79f644
goa_ews_client_new (void)
Packit 79f644
{
Packit 79f644
  return GOA_EWS_CLIENT (g_object_new (GOA_TYPE_EWS_CLIENT, NULL));
Packit 79f644
}
Packit 79f644
Packit 79f644
/* ---------------------------------------------------------------------------------------------------- */
Packit 79f644
Packit 79f644
typedef struct
Packit 79f644
{
Packit 79f644
  GCancellable *cancellable;
Packit 79f644
  GSimpleAsyncResult *res;
Packit 79f644
  SoupMessage *msgs[2];
Packit 79f644
  SoupSession *session;
Packit 79f644
  gboolean accept_ssl_errors;
Packit 79f644
  guint pending;
Packit 79f644
  gulong cancellable_id;
Packit 79f644
  xmlOutputBuffer *buf;
Packit 79f644
} AutodiscoverData;
Packit 79f644
Packit 79f644
typedef struct
Packit 79f644
{
Packit 79f644
  gchar *password;
Packit 79f644
  gchar *username;
Packit 79f644
} AutodiscoverAuthData;
Packit 79f644
Packit 79f644
static gboolean
Packit 79f644
ews_client_autodiscover_data_free (gpointer user_data)
Packit 79f644
{
Packit 79f644
  AutodiscoverData *data = user_data;
Packit 79f644
Packit 79f644
  g_simple_async_result_complete_in_idle (data->res);
Packit 79f644
Packit 79f644
  if (data->cancellable_id > 0)
Packit 79f644
    {
Packit 79f644
      g_cancellable_disconnect (data->cancellable, data->cancellable_id);
Packit 79f644
      g_object_unref (data->cancellable);
Packit 79f644
    }
Packit 79f644
Packit 79f644
  /* soup_session_queue_message stole the references to data->msgs */
Packit 79f644
  xmlOutputBufferClose (data->buf);
Packit 79f644
  g_object_unref (data->res);
Packit 79f644
  g_object_unref (data->session);
Packit 79f644
  g_slice_free (AutodiscoverData, data);
Packit 79f644
Packit 79f644
  return G_SOURCE_REMOVE;
Packit 79f644
}
Packit 79f644
Packit 79f644
static void
Packit 79f644
ews_client_autodiscover_auth_data_free (gpointer data, GClosure *closure)
Packit 79f644
{
Packit 79f644
  AutodiscoverAuthData *auth = data;
Packit 79f644
Packit 79f644
  g_free (auth->password);
Packit 79f644
  g_free (auth->username);
Packit 79f644
  g_slice_free (AutodiscoverAuthData, auth);
Packit 79f644
}
Packit 79f644
Packit 79f644
static gboolean
Packit 79f644
ews_client_check_node (const xmlNode *node, const gchar *name)
Packit 79f644
{
Packit 79f644
  g_return_val_if_fail (node != NULL, FALSE);
Packit 79f644
  return node->type == XML_ELEMENT_NODE && !g_strcmp0 ((gchar *) node->name, name);
Packit 79f644
}
Packit 79f644
Packit 79f644
static void
Packit 79f644
ews_client_authenticate (SoupSession *session,
Packit 79f644
                         SoupMessage *msg,
Packit 79f644
                         SoupAuth *auth,
Packit 79f644
                         gboolean retrying,
Packit 79f644
                         gpointer user_data)
Packit 79f644
{
Packit 79f644
  AutodiscoverAuthData *data = user_data;
Packit 79f644
Packit 79f644
  if (retrying)
Packit 79f644
    return;
Packit 79f644
Packit 79f644
  soup_auth_authenticate (auth, data->username, data->password);
Packit 79f644
}
Packit 79f644
Packit 79f644
static void
Packit 79f644
ews_client_request_started (SoupSession *session, SoupMessage *msg, SoupSocket *socket, gpointer user_data)
Packit 79f644
{
Packit 79f644
  AutodiscoverData *data = user_data;
Packit 79f644
  GError *error;
Packit 79f644
  GTlsCertificateFlags cert_flags;
Packit 79f644
Packit 79f644
  error = NULL;
Packit 79f644
Packit 79f644
  if (!data->accept_ssl_errors
Packit 79f644
      && soup_message_get_https_status (msg, NULL, &cert_flags)
Packit 79f644
      && cert_flags != 0)
Packit 79f644
    {
Packit 79f644
      goa_utils_set_error_ssl (&error, cert_flags);
Packit 79f644
      g_simple_async_result_take_error (data->res, error);
Packit 79f644
      soup_session_abort (data->session);
Packit 79f644
    }
Packit 79f644
}
Packit 79f644
Packit 79f644
static void
Packit 79f644
ews_client_autodiscover_cancelled_cb (GCancellable *cancellable, gpointer user_data)
Packit 79f644
{
Packit 79f644
  AutodiscoverData *data = user_data;
Packit 79f644
  soup_session_abort (data->session);
Packit 79f644
}
Packit 79f644
Packit 79f644
static gboolean
Packit 79f644
ews_client_autodiscover_parse_protocol (xmlNode *node)
Packit 79f644
{
Packit 79f644
  gboolean as_url = FALSE;
Packit 79f644
  gboolean oab_url = FALSE;
Packit 79f644
Packit 79f644
  for (node = node->children; node; node = node->next)
Packit 79f644
    {
Packit 79f644
      if (ews_client_check_node (node, "ASUrl"))
Packit 79f644
        as_url = TRUE;
Packit 79f644
      else if (ews_client_check_node (node, "OABUrl"))
Packit 79f644
        oab_url = TRUE;
Packit 79f644
Packit 79f644
      if (as_url && oab_url)
Packit 79f644
        break;
Packit 79f644
    }
Packit 79f644
Packit 79f644
  return as_url && oab_url;
Packit 79f644
}
Packit 79f644
Packit 79f644
static void
Packit 79f644
ews_client_autodiscover_response_cb (SoupSession *session, SoupMessage *msg, gpointer user_data)
Packit 79f644
{
Packit 79f644
  GError *error = NULL;
Packit 79f644
  AutodiscoverData *data = user_data;
Packit 79f644
  gboolean op_res = FALSE;
Packit 79f644
  guint idx;
Packit 79f644
  guint status;
Packit 79f644
  gsize size;
Packit 79f644
  xmlDoc *doc;
Packit 79f644
  xmlNode *node;
Packit 79f644
Packit 79f644
  size = sizeof (data->msgs) / sizeof (data->msgs[0]);
Packit 79f644
Packit 79f644
  for (idx = 0; idx < size; idx++)
Packit 79f644
    {
Packit 79f644
      if (data->msgs[idx] == msg)
Packit 79f644
        break;
Packit 79f644
    }
Packit 79f644
  if (idx == size || data->pending == 0)
Packit 79f644
    return;
Packit 79f644
Packit 79f644
  data->msgs[idx] = NULL;
Packit 79f644
  status = msg->status_code;
Packit 79f644
Packit 79f644
  /* status == SOUP_STATUS_CANCELLED, if we are being aborted by the
Packit 79f644
   * GCancellable, an SSL error or another message that was
Packit 79f644
   * successful.
Packit 79f644
   */
Packit 79f644
  if (status == SOUP_STATUS_CANCELLED)
Packit 79f644
    {
Packit 79f644
      /* If a previous autodiscover attempt for the same GAsyncResult
Packit 79f644
       * was successful then no additional attempts are required and
Packit 79f644
       * we should use the result from the earlier attempt.
Packit 79f644
       */
Packit 79f644
      op_res = g_simple_async_result_get_op_res_gboolean (data->res);
Packit 79f644
      goto out;
Packit 79f644
    }
Packit 79f644
  else if (status != SOUP_STATUS_OK)
Packit 79f644
    {
Packit 79f644
      g_warning ("goa_ews_client_autodiscover() failed: %u — %s", msg->status_code, msg->reason_phrase);
Packit 79f644
      goa_utils_set_error_soup (&error, msg);
Packit 79f644
      goto out;
Packit 79f644
    }
Packit 79f644
Packit 79f644
  soup_buffer_free (soup_message_body_flatten (SOUP_MESSAGE (msg)->response_body));
Packit 79f644
  g_debug ("The response headers");
Packit 79f644
  g_debug ("===================");
Packit 79f644
  g_debug ("%s", SOUP_MESSAGE (msg)->response_body->data);
Packit 79f644
Packit 79f644
  doc = xmlReadMemory (msg->response_body->data, msg->response_body->length, "autodiscover.xml", NULL, 0);
Packit 79f644
  if (doc == NULL)
Packit 79f644
    {
Packit 79f644
      g_set_error (&error,
Packit 79f644
                   GOA_ERROR,
Packit 79f644
                   GOA_ERROR_FAILED, /* TODO: more specific */
Packit 79f644
                   _("Failed to parse autodiscover response XML"));
Packit 79f644
      goto out;
Packit 79f644
    }
Packit 79f644
Packit 79f644
  node = xmlDocGetRootElement (doc);
Packit 79f644
  if (g_strcmp0 ((gchar *) node->name, "Autodiscover"))
Packit 79f644
    {
Packit 79f644
      g_set_error (&error,
Packit 79f644
                   GOA_ERROR,
Packit 79f644
                   GOA_ERROR_FAILED, /* TODO: more specific */
Packit 79f644
                   /* Translators: the parameter is an XML element name. */
Packit 79f644
                   _("Failed to find “%s” element"), "Autodiscover");
Packit 79f644
      goto out;
Packit 79f644
    }
Packit 79f644
Packit 79f644
  for (node = node->children; node; node = node->next)
Packit 79f644
    {
Packit 79f644
      if (ews_client_check_node (node, "Response"))
Packit 79f644
        break;
Packit 79f644
    }
Packit 79f644
  if (node == NULL)
Packit 79f644
    {
Packit 79f644
      g_set_error (&error,
Packit 79f644
                   GOA_ERROR,
Packit 79f644
                   GOA_ERROR_FAILED, /* TODO: more specific */
Packit 79f644
                   /* Translators: the parameter is an XML element name. */
Packit 79f644
                   _("Failed to find “%s” element"), "Response");
Packit 79f644
      goto out;
Packit 79f644
    }
Packit 79f644
Packit 79f644
  for (node = node->children; node; node = node->next)
Packit 79f644
    {
Packit 79f644
      if (ews_client_check_node (node, "Account"))
Packit 79f644
        break;
Packit 79f644
    }
Packit 79f644
  if (node == NULL)
Packit 79f644
    {
Packit 79f644
      g_set_error (&error,
Packit 79f644
                   GOA_ERROR,
Packit 79f644
                   GOA_ERROR_FAILED, /* TODO: more specific */
Packit 79f644
                   /* Translators: the parameter is an XML element name. */
Packit 79f644
                   _("Failed to find “%s” element"), "Account");
Packit 79f644
      goto out;
Packit 79f644
    }
Packit 79f644
Packit 79f644
  for (node = node->children; node; node = node->next)
Packit 79f644
    {
Packit 79f644
      if (ews_client_check_node (node, "Protocol"))
Packit 79f644
        {
Packit 79f644
          op_res = ews_client_autodiscover_parse_protocol (node);
Packit 79f644
          /* Since the server may send back multiple <Protocol> nodes
Packit 79f644
           * don't break unless we found the one we want.
Packit 79f644
           */
Packit 79f644
          if (op_res)
Packit 79f644
            break;
Packit 79f644
        }
Packit 79f644
    }
Packit 79f644
  if (!op_res)
Packit 79f644
    {
Packit 79f644
      g_set_error (&error,
Packit 79f644
                   GOA_ERROR,
Packit 79f644
                   GOA_ERROR_FAILED, /* TODO: more specific*/
Packit 79f644
                   _("Failed to find ASUrl and OABUrl in autodiscover response"));
Packit 79f644
      goto out;
Packit 79f644
    }
Packit 79f644
Packit 79f644
  /* This autodiscover attempt was successful. Save the result now so
Packit 79f644
   * that it won't get lost when we hear from another autodiscover
Packit 79f644
   * attempt for the same GAsyncResult.
Packit 79f644
   */
Packit 79f644
  g_simple_async_result_set_op_res_gboolean (data->res, op_res);
Packit 79f644
Packit 79f644
  for (idx = 0; idx < size; idx++)
Packit 79f644
    {
Packit 79f644
      if (data->msgs[idx] != NULL)
Packit 79f644
        {
Packit 79f644
          /* The callback (ie. this function) will be invoked after we
Packit 79f644
           * have returned to the main loop.
Packit 79f644
           */
Packit 79f644
          soup_session_cancel_message (data->session, data->msgs[idx], SOUP_STATUS_CANCELLED);
Packit 79f644
        }
Packit 79f644
    }
Packit 79f644
Packit 79f644
 out:
Packit 79f644
  /* error == NULL, if we are being aborted by the GCancellable, an
Packit 79f644
   * SSL error or another message that was successful.
Packit 79f644
   */
Packit 79f644
  if (!op_res)
Packit 79f644
    {
Packit 79f644
      /* There's another request outstanding.
Packit 79f644
       * Hope that it has better luck.
Packit 79f644
       */
Packit 79f644
      if (data->pending > 1)
Packit 79f644
        g_clear_error (&error);
Packit 79f644
Packit 79f644
      if (error != NULL)
Packit 79f644
        g_simple_async_result_take_error (data->res, error);
Packit 79f644
    }
Packit 79f644
Packit 79f644
  data->pending--;
Packit 79f644
  if (data->pending == 0)
Packit 79f644
    {
Packit 79f644
      GMainContext *context;
Packit 79f644
      GSource *source;
Packit 79f644
Packit 79f644
      /* The result of the GAsyncResult should already be set when we
Packit 79f644
       * get here. If it wasn't explicitly set to TRUE then
Packit 79f644
       * autodiscovery has failed and the default value of the
Packit 79f644
       * GAsyncResult (which is FALSE) should be returned to the
Packit 79f644
       * original caller.
Packit 79f644
       */
Packit 79f644
Packit 79f644
      source = g_idle_source_new ();
Packit 79f644
      g_source_set_priority (source, G_PRIORITY_DEFAULT_IDLE);
Packit 79f644
      g_source_set_callback (source, ews_client_autodiscover_data_free, data, NULL);
Packit 79f644
      g_source_set_name (source, "[goa] ews_client_autodiscover_data_free");
Packit 79f644
Packit 79f644
      context = g_main_context_get_thread_default ();
Packit 79f644
      g_source_attach (source, context);
Packit 79f644
      g_source_unref (source);
Packit 79f644
    }
Packit 79f644
}
Packit 79f644
Packit 79f644
static xmlDoc *
Packit 79f644
ews_client_create_autodiscover_xml (const gchar *email)
Packit 79f644
{
Packit 79f644
  xmlDoc *doc;
Packit 79f644
  xmlNode *node;
Packit 79f644
  xmlNs *ns;
Packit 79f644
Packit 79f644
  doc = xmlNewDoc ((xmlChar *) "1.0");
Packit 79f644
Packit 79f644
  node = xmlNewDocNode (doc, NULL, (xmlChar *) "Autodiscover", NULL);
Packit 79f644
  xmlDocSetRootElement (doc, node);
Packit 79f644
  ns = xmlNewNs (node,
Packit 79f644
                 (xmlChar *) "http://schemas.microsoft.com/exchange/autodiscover/outlook/requestschema/2006",
Packit 79f644
                 NULL);
Packit 79f644
Packit 79f644
  node = xmlNewChild (node, ns, (xmlChar *) "Request", NULL);
Packit 79f644
  xmlNewChild (node, ns, (xmlChar *) "EMailAddress", (xmlChar *) email);
Packit 79f644
  xmlNewChild (node,
Packit 79f644
               ns,
Packit 79f644
               (xmlChar *) "AcceptableResponseSchema",
Packit 79f644
               (xmlChar *) "http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a");
Packit 79f644
Packit 79f644
  return doc;
Packit 79f644
}
Packit 79f644
Packit 79f644
static void
Packit 79f644
ews_client_post_restarted_cb (SoupMessage *msg, gpointer data)
Packit 79f644
{
Packit 79f644
  xmlOutputBuffer *buf = data;
Packit 79f644
Packit 79f644
  /* In violation of RFC2616, libsoup will change a POST request to
Packit 79f644
   * a GET on receiving a 302 redirect.
Packit 79f644
   */
Packit 79f644
  g_debug ("Working around libsoup bug with redirect");
Packit 79f644
  g_object_set (msg, SOUP_MESSAGE_METHOD, "POST", NULL);
Packit 79f644
Packit 79f644
  soup_message_set_request(msg,
Packit 79f644
                           "text/xml; charset=utf-8",
Packit 79f644
                           SOUP_MEMORY_COPY,
Packit 79f644
#ifdef LIBXML2_NEW_BUFFER
Packit 79f644
                           (gchar *) xmlOutputBufferGetContent(buf),
Packit 79f644
                           xmlOutputBufferGetSize(buf));
Packit 79f644
#else
Packit 79f644
                           (gchar *) buf->buffer->content,
Packit 79f644
                           buf->buffer->use);
Packit 79f644
#endif
Packit 79f644
}
Packit 79f644
Packit 79f644
static SoupMessage *
Packit 79f644
ews_client_create_msg_for_url (const gchar *url, xmlOutputBuffer *buf)
Packit 79f644
{
Packit 79f644
  SoupMessage *msg;
Packit 79f644
Packit 79f644
  msg = soup_message_new (buf != NULL ? "POST" : "GET", url);
Packit 79f644
  soup_message_headers_append (msg->request_headers, "User-Agent", "libews/0.1");
Packit 79f644
Packit 79f644
  if (buf != NULL)
Packit 79f644
    {
Packit 79f644
      soup_message_set_request (msg,
Packit 79f644
                                "text/xml; charset=utf-8",
Packit 79f644
                                SOUP_MEMORY_COPY,
Packit 79f644
#ifdef LIBXML2_NEW_BUFFER
Packit 79f644
                                (gchar *) xmlOutputBufferGetContent(buf),
Packit 79f644
                                xmlOutputBufferGetSize(buf));
Packit 79f644
#else
Packit 79f644
                                (gchar *) buf->buffer->content,
Packit 79f644
                                buf->buffer->use);
Packit 79f644
#endif
Packit 79f644
      g_signal_connect (msg, "restarted", G_CALLBACK (ews_client_post_restarted_cb), buf);
Packit 79f644
    }
Packit 79f644
Packit 79f644
  soup_buffer_free (soup_message_body_flatten (SOUP_MESSAGE (msg)->request_body));
Packit 79f644
  g_debug ("The request headers");
Packit 79f644
  g_debug ("===================");
Packit 79f644
  g_debug ("%s", SOUP_MESSAGE (msg)->request_body->data);
Packit 79f644
Packit 79f644
  return msg;
Packit 79f644
}
Packit 79f644
Packit 79f644
void
Packit 79f644
goa_ews_client_autodiscover (GoaEwsClient        *self,
Packit 79f644
                             const gchar         *email,
Packit 79f644
                             const gchar         *password,
Packit 79f644
                             const gchar         *username,
Packit 79f644
                             const gchar         *server,
Packit 79f644
                             gboolean             accept_ssl_errors,
Packit 79f644
                             GCancellable        *cancellable,
Packit 79f644
                             GAsyncReadyCallback  callback,
Packit 79f644
                             gpointer             user_data)
Packit 79f644
{
Packit 79f644
  AutodiscoverData *data;
Packit 79f644
  AutodiscoverAuthData *auth;
Packit 79f644
  gchar *url1;
Packit 79f644
  gchar *url2;
Packit 79f644
  xmlDoc *doc;
Packit 79f644
  xmlOutputBuffer *buf;
Packit 79f644
Packit 79f644
  g_return_if_fail (GOA_IS_EWS_CLIENT (self));
Packit 79f644
  g_return_if_fail (email != NULL && email[0] != '\0');
Packit 79f644
  g_return_if_fail (password != NULL && password[0] != '\0');
Packit 79f644
  g_return_if_fail (username != NULL && username[0] != '\0');
Packit 79f644
  g_return_if_fail (server != NULL && server[0] != '\0');
Packit 79f644
  g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
Packit 79f644
Packit 79f644
  doc = ews_client_create_autodiscover_xml (email);
Packit 79f644
  buf = xmlAllocOutputBuffer (NULL);
Packit 79f644
  xmlNodeDumpOutput (buf, doc, xmlDocGetRootElement (doc), 0, 1, NULL);
Packit 79f644
  xmlOutputBufferFlush (buf);
Packit 79f644
Packit 79f644
  url1 = g_strdup_printf ("https://%s/autodiscover/autodiscover.xml", server);
Packit 79f644
  url2 = g_strdup_printf ("https://autodiscover.%s/autodiscover/autodiscover.xml", server);
Packit 79f644
Packit 79f644
  /* http://msdn.microsoft.com/en-us/library/ee332364.aspx says we are
Packit 79f644
   * supposed to try $domain and then autodiscover.$domain. But some
Packit 79f644
   * people have broken firewalls on the former which drop packets
Packit 79f644
   * instead of rejecting connections, and make the request take ages
Packit 79f644
   * to time out. So run both queries in parallel and let the fastest
Packit 79f644
   * (successful) one win.
Packit 79f644
   */
Packit 79f644
  data = g_slice_new0 (AutodiscoverData);
Packit 79f644
  data->buf = buf;
Packit 79f644
  data->res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, goa_ews_client_autodiscover);
Packit 79f644
  data->msgs[0] = ews_client_create_msg_for_url (url1, buf);
Packit 79f644
  data->msgs[1] = ews_client_create_msg_for_url (url2, buf);
Packit 79f644
  data->pending = sizeof (data->msgs) / sizeof (data->msgs[0]);
Packit 79f644
  data->session = soup_session_new_with_options (SOUP_SESSION_SSL_STRICT, FALSE,
Packit 79f644
                                                 NULL);
Packit 79f644
  soup_session_add_feature_by_type (data->session, SOUP_TYPE_AUTH_NTLM);
Packit 79f644
  data->accept_ssl_errors = accept_ssl_errors;
Packit 79f644
Packit 79f644
  if (cancellable != NULL)
Packit 79f644
    {
Packit 79f644
      data->cancellable = g_object_ref (cancellable);
Packit 79f644
      data->cancellable_id = g_cancellable_connect (data->cancellable,
Packit 79f644
                                                    G_CALLBACK (ews_client_autodiscover_cancelled_cb),
Packit 79f644
                                                    data,
Packit 79f644
                                                    NULL);
Packit 79f644
      g_simple_async_result_set_check_cancellable (data->res, data->cancellable);
Packit 79f644
    }
Packit 79f644
Packit 79f644
  auth = g_slice_new0 (AutodiscoverAuthData);
Packit 79f644
  auth->username = g_strdup (username);
Packit 79f644
  auth->password = g_strdup (password);
Packit 79f644
  g_signal_connect_data (data->session,
Packit 79f644
                         "authenticate",
Packit 79f644
                         G_CALLBACK (ews_client_authenticate),
Packit 79f644
                         auth,
Packit 79f644
                         ews_client_autodiscover_auth_data_free,
Packit 79f644
                         0);
Packit 79f644
Packit 79f644
  g_signal_connect (data->session, "request-started", G_CALLBACK (ews_client_request_started), data);
Packit 79f644
Packit 79f644
  soup_session_queue_message (data->session, data->msgs[0], ews_client_autodiscover_response_cb, data);
Packit 79f644
  soup_session_queue_message (data->session, data->msgs[1], ews_client_autodiscover_response_cb, data);
Packit 79f644
Packit 79f644
  g_free (url2);
Packit 79f644
  g_free (url1);
Packit 79f644
  xmlFreeDoc (doc);
Packit 79f644
}
Packit 79f644
Packit 79f644
gboolean
Packit 79f644
goa_ews_client_autodiscover_finish (GoaEwsClient *self, GAsyncResult *res, GError **error)
Packit 79f644
{
Packit 79f644
  GSimpleAsyncResult *simple;
Packit 79f644
Packit 79f644
  g_return_val_if_fail (g_simple_async_result_is_valid (res, G_OBJECT (self), goa_ews_client_autodiscover),
Packit 79f644
                        FALSE);
Packit 79f644
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
Packit 79f644
Packit 79f644
  simple = G_SIMPLE_ASYNC_RESULT (res);
Packit 79f644
Packit 79f644
  if (g_simple_async_result_propagate_error (simple, error))
Packit 79f644
    return FALSE;
Packit 79f644
Packit 79f644
  return g_simple_async_result_get_op_res_gboolean (simple);
Packit 79f644
}
Packit 79f644
Packit 79f644
/* ---------------------------------------------------------------------------------------------------- */
Packit 79f644
Packit 79f644
typedef struct
Packit 79f644
{
Packit 79f644
  GError **error;
Packit 79f644
  GMainLoop *loop;
Packit 79f644
  gboolean op_res;
Packit 79f644
} AutodiscoverSyncData;
Packit 79f644
Packit 79f644
static void
Packit 79f644
ews_client_autodiscover_sync_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
Packit 79f644
{
Packit 79f644
  AutodiscoverSyncData *data = user_data;
Packit 79f644
Packit 79f644
  data->op_res = goa_ews_client_autodiscover_finish (GOA_EWS_CLIENT (source_object), res, data->error);
Packit 79f644
  g_main_loop_quit (data->loop);
Packit 79f644
}
Packit 79f644
Packit 79f644
gboolean
Packit 79f644
goa_ews_client_autodiscover_sync (GoaEwsClient        *self,
Packit 79f644
                                  const gchar         *email,
Packit 79f644
                                  const gchar         *password,
Packit 79f644
                                  const gchar         *username,
Packit 79f644
                                  const gchar         *server,
Packit 79f644
                                  gboolean             accept_ssl_errors,
Packit 79f644
                                  GCancellable        *cancellable,
Packit 79f644
                                  GError             **error)
Packit 79f644
{
Packit 79f644
  AutodiscoverSyncData data;
Packit 79f644
  GMainContext *context = NULL;
Packit 79f644
Packit 79f644
  data.error = error;
Packit 79f644
Packit 79f644
  context = g_main_context_new ();
Packit 79f644
  g_main_context_push_thread_default (context);
Packit 79f644
  data.loop = g_main_loop_new (context, FALSE);
Packit 79f644
Packit 79f644
  goa_ews_client_autodiscover (self,
Packit 79f644
                               email,
Packit 79f644
                               password,
Packit 79f644
                               username,
Packit 79f644
                               server,
Packit 79f644
                               accept_ssl_errors,
Packit 79f644
                               cancellable,
Packit 79f644
                               ews_client_autodiscover_sync_cb,
Packit 79f644
                               &data);
Packit 79f644
  g_main_loop_run (data.loop);
Packit 79f644
  g_main_loop_unref (data.loop);
Packit 79f644
Packit 79f644
  g_main_context_pop_thread_default (context);
Packit 79f644
  g_main_context_unref (context);
Packit 79f644
Packit 79f644
  return data.op_res;
Packit 79f644
}