/** 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; }