Пример #1
0
/** Get all timezones from the cache.
 *
 * @param cb 3E calendar backend.
 * @param cache Calendar backend cache object.
 *
 * @return List of icaltimezone objects (free them using icaltimezone_free(x, 1);).
 */
static GSList *e_cal_backend_cache_get_timezones(ECalBackend3e *cb, ECalBackendCache *cache)
{
    GSList *keys, *iter;
    GSList *list = NULL;

    g_return_val_if_fail(E_IS_CAL_BACKEND_CACHE(cache), NULL);
    keys = e_file_cache_get_keys(E_FILE_CACHE(cache));

    for (iter = keys; iter; iter = iter->next)
    {
        char *key = iter->data;
        const icaltimezone *zone;

        g_static_rw_lock_reader_lock(&cb->priv->cache_lock);
        zone = e_cal_backend_cache_get_timezone(cache, key);
        g_static_rw_lock_reader_unlock(&cb->priv->cache_lock);

        if (zone)
        {
            icalcomponent *zone_comp = icaltimezone_get_component((icaltimezone *)zone);
            icaltimezone *new_zone = icaltimezone_new();
            /* make sure you have patched eds if you get segfaults here */
            if (zone_comp == NULL)
            {
                g_critical("Patch your evolution-data-server or else...");
            }

            icaltimezone_set_component(new_zone, icalcomponent_new_clone(zone_comp));
            list = g_slist_prepend(list, new_zone);
        }
    }

    /* eds patch required here! */
    g_slist_free(keys);
    return list;
}
static GError *
download_contacts (EBookBackendWebdav *webdav,
                   EFlag *running,
                   EDataBookView *book_view,
                   GCancellable *cancellable)
{
	EBookBackendWebdavPrivate *priv = webdav->priv;
	EBookBackend		  *book_backend;
	SoupMessage               *message;
	guint                      status;
	xmlTextReaderPtr           reader;
	response_element_t        *elements;
	response_element_t        *element;
	response_element_t        *next;
	gint                        count;
	gint                        i;
	gchar                     *new_ctag = NULL;

	g_mutex_lock (&priv->update_lock);

	if (!check_addressbook_changed (webdav, &new_ctag, cancellable)) {
		g_free (new_ctag);
		g_mutex_unlock (&priv->update_lock);
		return EDB_ERROR (SUCCESS);
	}

	book_backend = E_BOOK_BACKEND (webdav);

	if (book_view != NULL) {
		e_data_book_view_notify_progress (book_view, -1,
				_("Loading Addressbook summary..."));
	}

	message = send_propfind (webdav, cancellable);
	status  = message->status_code;

	if (status == 401 || status == 407) {
		g_object_unref (message);
		g_free (new_ctag);
		if (book_view)
			e_data_book_view_notify_progress (book_view, -1, NULL);
		g_mutex_unlock (&priv->update_lock);
		return webdav_handle_auth_request (webdav);
	}
	if (status != 207) {
		GError *error;

		error = e_data_book_create_error_fmt (
			E_DATA_BOOK_STATUS_OTHER_ERROR,
			_("PROPFIND on webdav failed with HTTP status %d (%s)"),
			status,
			message->reason_phrase && *message->reason_phrase ? message->reason_phrase :
			(soup_status_get_phrase (message->status_code) ? soup_status_get_phrase (message->status_code) : _("Unknown error")));

		g_object_unref (message);
		g_free (new_ctag);

		if (book_view)
			e_data_book_view_notify_progress (book_view, -1, NULL);

		g_mutex_unlock (&priv->update_lock);

		return error;
	}
	if (message->response_body == NULL) {
		g_warning ("No response body in webdav PROPFIND result");
		g_object_unref (message);
		g_free (new_ctag);

		if (book_view)
			e_data_book_view_notify_progress (book_view, -1, NULL);

		g_mutex_unlock (&priv->update_lock);

		return e_data_book_create_error_fmt (E_DATA_BOOK_STATUS_OTHER_ERROR, _("No response body in webdav PROPFIND result"));
	}

	/* parse response */
	reader = xmlReaderForMemory (
		message->response_body->data,
		message->response_body->length, NULL, NULL,
		XML_PARSE_NOWARNING);

	elements = parse_propfind_response (reader);

	/* count contacts */
	count = 0;
	for (element = elements; element != NULL; element = element->next) {
		++count;
	}

	/* download contacts */
	i = 0;
	for (element = elements; element != NULL; element = element->next, ++i) {
		const gchar  *uri;
		const gchar *etag;
		EContact    *contact;
		gchar *complete_uri;

		/* stop downloading if search was aborted */
		if (running != NULL && !e_flag_is_set (running))
			break;

		if (book_view != NULL) {
			gfloat percent = 100.0 / count * i;
			gchar buf[100];
			snprintf (buf, sizeof (buf), _("Loading Contacts (%d%%)"), (gint) percent);
			e_data_book_view_notify_progress (book_view, -1, buf);
		}

		/* skip collections */
		uri = (const gchar *) element->href;
		if (uri[strlen (uri) - 1] == '/')
			continue;

		/* uri might be relative, construct complete one */
		if (uri[0] == '/') {
			SoupURI *soup_uri = soup_uri_new (priv->uri);
			soup_uri->path    = g_strdup (uri);

			complete_uri = soup_uri_to_string (soup_uri, 0);
			soup_uri_free (soup_uri);
		} else {
			complete_uri = g_strdup (uri);
		}

		etag = (const gchar *) element->etag;

		g_mutex_lock (&priv->cache_lock);
		contact = e_book_backend_cache_get_contact (priv->cache, complete_uri);
		g_mutex_unlock (&priv->cache_lock);

		/* download contact if it is not cached or its ETag changed */
		if (contact == NULL || etag == NULL ||
		    strcmp (e_contact_get_const (contact, E_CONTACT_REV), etag) != 0) {
			contact = download_contact (webdav, complete_uri, cancellable);
			if (contact != NULL) {
				g_mutex_lock (&priv->cache_lock);
				if (e_book_backend_cache_remove_contact (priv->cache, complete_uri))
					e_book_backend_notify_remove (book_backend, complete_uri);
				e_book_backend_cache_add_contact (priv->cache, contact);
				g_mutex_unlock (&priv->cache_lock);
				e_book_backend_notify_update (book_backend, contact);
			}
		}

		g_free (complete_uri);
	}

	/* free element list */
	for (element = elements; element != NULL; element = next) {
		next = element->next;

		xmlFree (element->href);
		xmlFree (element->etag);
		g_free (element);
	}

	xmlFreeTextReader (reader);
	g_object_unref (message);

	if (new_ctag) {
		g_mutex_lock (&priv->cache_lock);
		if (!e_file_cache_replace_object (E_FILE_CACHE (priv->cache), WEBDAV_CTAG_KEY, new_ctag))
			e_file_cache_add_object (E_FILE_CACHE (priv->cache), WEBDAV_CTAG_KEY, new_ctag);
		g_mutex_unlock (&priv->cache_lock);
	}
	g_free (new_ctag);

	if (book_view)
		e_data_book_view_notify_progress (book_view, -1, NULL);

	g_mutex_unlock (&priv->update_lock);

	return EDB_ERROR (SUCCESS);
}
static gboolean
check_addressbook_changed (EBookBackendWebdav *webdav,
                           gchar **new_ctag,
                           GCancellable *cancellable)
{
	gboolean res = TRUE;
	const gchar *request = "<?xml version=\"1.0\" encoding=\"utf-8\"?><propfind xmlns=\"DAV:\"><prop><getctag/></prop></propfind>";
	EBookBackendWebdavPrivate *priv;
	SoupMessage *message;

	g_return_val_if_fail (webdav != NULL, TRUE);
	g_return_val_if_fail (new_ctag != NULL, TRUE);

	*new_ctag = NULL;
	priv = webdav->priv;

	if (!priv->supports_getctag)
		return TRUE;

	priv->supports_getctag = FALSE;

	message = soup_message_new (SOUP_METHOD_PROPFIND, priv->uri);
	if (!message)
		return TRUE;

	soup_message_headers_append (message->request_headers, "User-Agent", USERAGENT);
	soup_message_headers_append (message->request_headers, "Connection", "close");
	soup_message_headers_append (message->request_headers, "Depth", "0");
	soup_message_set_request (message, "text/xml", SOUP_MEMORY_TEMPORARY, (gchar *) request, strlen (request));
	send_and_handle_ssl (webdav, message, cancellable);

	if (message->status_code == 207 && message->response_body) {
		xmlDocPtr xml;

		xml = xmlReadMemory (message->response_body->data, message->response_body->length, NULL, NULL, XML_PARSE_NOWARNING);
		if (xml) {
			const gchar *GETCTAG_XPATH_STATUS = "string(/D:multistatus/D:response/D:propstat/D:prop/D:getctag/../../D:status)";
			const gchar *GETCTAG_XPATH_VALUE = "string(/D:multistatus/D:response/D:propstat/D:prop/D:getctag)";
			xmlXPathContextPtr xpctx;

			xpctx = xmlXPathNewContext (xml);
			xmlXPathRegisterNs (xpctx, (xmlChar *) "D", (xmlChar *) "DAV:");

			if (xp_object_get_status (xpath_eval (xpctx, GETCTAG_XPATH_STATUS)) == 200) {
				gchar *txt = xp_object_get_string (xpath_eval (xpctx, GETCTAG_XPATH_VALUE));

				if (txt && *txt) {
					gint len = strlen (txt);

					if (*txt == '\"' && len > 2 && txt[len - 1] == '\"') {
						/* dequote */
						*new_ctag = g_strndup (txt + 1, len - 2);
					} else {
						*new_ctag = txt;
						txt = NULL;
					}

					if (*new_ctag) {
						const gchar *my_ctag;

						g_mutex_lock (&priv->cache_lock);
						my_ctag = e_file_cache_get_object (E_FILE_CACHE (priv->cache), WEBDAV_CTAG_KEY);
						res = !my_ctag || !g_str_equal (my_ctag, *new_ctag);
						priv->supports_getctag = TRUE;
						g_mutex_unlock (&priv->cache_lock);
					}
				}

				g_free (txt);
			}

			xmlXPathFreeContext (xpctx);
			xmlFreeDoc (xml);
		}
	}

	g_object_unref (message);

	return res;
}