[evolution-data-server] Bug #572176 - Allow Local iCal Files To Be Selected As Cal Source
- From: Milan Crha <mcrha src gnome org>
- To: svn-commits-list gnome org
- Subject: [evolution-data-server] Bug #572176 - Allow Local iCal Files To Be Selected As Cal Source
- Date: Mon, 27 Jul 2009 11:02:19 +0000 (UTC)
commit f95e0a988a6467922c129431a21370de3080a9d7
Author: Milan Crha <mcrha redhat com>
Date: Mon Jul 27 13:01:19 2009 +0200
Bug #572176 - Allow Local iCal Files To Be Selected As Cal Source
calendar/backends/file/e-cal-backend-file.c | 271 +++++++++++++++++++++++++--
libedataserver/e-source.c | 6 +-
2 files changed, 261 insertions(+), 16 deletions(-)
---
diff --git a/calendar/backends/file/e-cal-backend-file.c b/calendar/backends/file/e-cal-backend-file.c
index 4d8422b..d315977 100644
--- a/calendar/backends/file/e-cal-backend-file.c
+++ b/calendar/backends/file/e-cal-backend-file.c
@@ -86,8 +86,25 @@ struct _ECalBackendFilePrivate {
floating DATE-TIME values. */
icaltimezone *default_zone;
- /* The list of live queries */
- GList *queries;
+ /* a custom filename opened */
+ gchar *custom_file;
+
+ /* guards refresh members */
+ GMutex *refresh_lock;
+ /* set to TRUE to indicate thread should stop */
+ gboolean refresh_thread_stop;
+ /* condition for refreshing, not NULL when thread exists */
+ GCond *refresh_cond;
+ /* cond to know the refresh thread gone */
+ GCond *refresh_gone_cond;
+ /* increased when backend saves the file */
+ guint refresh_skip;
+
+ /* Monitor for a refresh type "1" */
+ GFileMonitor *refresh_monitor;
+
+ /* timeour id for refresh type "2" */
+ guint refresh_timeout_id;
};
@@ -102,6 +119,8 @@ static ECalBackendSyncClass *parent_class;
static ECalBackendSyncStatus
e_cal_backend_file_add_timezone (ECalBackendSync *backend, EDataCal *cal, const gchar *tzobj);
+static void free_refresh_data (ECalBackendFile *cbfile);
+
/* g_hash_table_foreach() callback to destroy a ECalBackendFileObject */
static void
free_object_data (gpointer data)
@@ -133,8 +152,9 @@ save_file_when_idle (gpointer user_data)
g_assert (priv->icalcomp != NULL);
g_static_rec_mutex_lock (&priv->idle_save_rmutex);
- if (!priv->is_dirty) {
+ if (!priv->is_dirty || priv->read_only) {
priv->dirty_idle_id = 0;
+ priv->is_dirty = FALSE;
g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
return FALSE;
}
@@ -161,6 +181,7 @@ save_file_when_idle (gpointer user_data)
goto error_malformed_uri;
}
+ priv->refresh_skip++;
stream = g_file_replace (backup_file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, &e);
if (!stream || e) {
if (stream)
@@ -168,6 +189,7 @@ save_file_when_idle (gpointer user_data)
g_object_unref (file);
g_object_unref (backup_file);
+ priv->refresh_skip--;
goto error;
}
@@ -308,6 +330,12 @@ e_cal_backend_file_finalize (GObject *object)
priv->dirty_idle_id = 0;
}
+ free_refresh_data (cbfile);
+
+ if (priv->refresh_lock)
+ g_mutex_free (priv->refresh_lock);
+ priv->refresh_lock = NULL;
+
g_static_rec_mutex_free (&priv->idle_save_rmutex);
if (priv->path) {
@@ -315,6 +343,9 @@ e_cal_backend_file_finalize (GObject *object)
priv->path = NULL;
}
+ g_free (priv->custom_file);
+ priv->custom_file = NULL;
+
if (priv->default_zone && priv->default_zone != icaltimezone_get_utc_timezone ()) {
icaltimezone_free (priv->default_zone, 1);
}
@@ -643,25 +674,37 @@ uri_to_path (ECalBackend *backend)
{
ECalBackendFile *cbfile;
ECalBackendFilePrivate *priv;
+ ESource *source;
const gchar *master_uri;
gchar *full_uri, *str_uri;
- GFile *file;
+ GFile *file = NULL;
cbfile = E_CAL_BACKEND_FILE (backend);
priv = cbfile->priv;
- master_uri = e_cal_backend_get_uri (backend);
+ source = e_cal_backend_get_source (backend);
+ if (source && e_source_get_property (source, "custom-file")) {
+ /* customr-uri is with a filename already */
+ master_uri = e_source_get_property (source, "custom-file");
+ file = g_file_new_for_path (master_uri);
+ if (!file)
+ return NULL;
+ }
- /* FIXME Check the error conditions a little more elegantly here */
- if (g_strrstr ("tasks.ics", master_uri) || g_strrstr ("calendar.ics", master_uri)) {
- g_warning (G_STRLOC ": Existing file name %s", master_uri);
+ if (!file) {
+ master_uri = e_cal_backend_get_uri (backend);
- return NULL;
- }
+ /* FIXME Check the error conditions a little more elegantly here */
+ if (g_strrstr ("tasks.ics", master_uri) || g_strrstr ("calendar.ics", master_uri)) {
+ g_warning (G_STRLOC ": Existing file name %s", master_uri);
+
+ return NULL;
+ }
- full_uri = g_strdup_printf ("%s/%s", master_uri, priv->file_name);
- file = g_file_new_for_uri (full_uri);
- g_free (full_uri);
+ full_uri = g_strdup_printf ("%s/%s", master_uri, priv->file_name);
+ file = g_file_new_for_uri (full_uri);
+ g_free (full_uri);
+ }
if (!file)
return NULL;
@@ -679,6 +722,180 @@ uri_to_path (ECalBackend *backend)
return str_uri;
}
+static gpointer
+refresh_thread_func (gpointer data)
+{
+ ECalBackendFile *cbfile = data;
+ ECalBackendFilePrivate *priv;
+ GFile *file;
+ GFileInfo *info;
+ guint64 last_modified, modified;
+
+ g_return_val_if_fail (cbfile != NULL, NULL);
+ g_return_val_if_fail (E_IS_CAL_BACKEND_FILE (cbfile), NULL);
+
+ priv = cbfile->priv;
+ g_return_val_if_fail (priv->custom_file != NULL, NULL);
+
+ file = g_file_new_for_path (priv->custom_file);
+ info = g_file_query_info (file, G_FILE_ATTRIBUTE_TIME_MODIFIED, G_FILE_QUERY_INFO_NONE, NULL, NULL);
+ g_return_val_if_fail (info != NULL, NULL);
+
+ last_modified = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
+ g_object_unref (info);
+
+ g_mutex_lock (priv->refresh_lock);
+ while (!priv->refresh_thread_stop) {
+ g_cond_wait (priv->refresh_cond, priv->refresh_lock);
+
+ g_static_rec_mutex_lock (&priv->idle_save_rmutex);
+
+ if (priv->refresh_skip > 0) {
+ priv->refresh_skip--;
+ g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
+ continue;
+ }
+
+ if (priv->is_dirty) {
+ /* save before reload, if dirty */
+ if (priv->dirty_idle_id) {
+ g_source_remove (priv->dirty_idle_id);
+ priv->dirty_idle_id = 0;
+ }
+ save_file_when_idle (cbfile);
+ priv->refresh_skip = 0;
+ }
+
+ g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
+
+ info = g_file_query_info (file, G_FILE_ATTRIBUTE_TIME_MODIFIED, G_FILE_QUERY_INFO_NONE, NULL, NULL);
+ if (!info)
+ break;
+
+ modified = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
+ g_object_unref (info);
+
+ if (modified != last_modified) {
+ last_modified = modified;
+ e_cal_backend_file_reload (cbfile);
+ }
+ }
+
+ g_object_unref (file);
+ g_cond_signal (priv->refresh_gone_cond);
+ g_mutex_unlock (priv->refresh_lock);
+
+ return NULL;
+}
+
+static gboolean
+check_refresh_calendar_timeout (ECalBackendFilePrivate *priv)
+{
+ g_return_val_if_fail (priv != NULL, FALSE);
+
+ /* called in the main thread */
+ if (priv->refresh_cond)
+ g_cond_signal (priv->refresh_cond);
+
+ /* call it next time again */
+ return TRUE;
+}
+
+static void
+custom_file_changed (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type, ECalBackendFilePrivate *priv)
+{
+ if (priv->refresh_cond)
+ g_cond_signal (priv->refresh_cond);
+}
+
+static void
+prepare_refresh_data (ECalBackendFile *cbfile)
+{
+ ECalBackendFilePrivate *priv;
+ ESource *source;
+ const gchar *value;
+
+ g_return_if_fail (cbfile != NULL);
+
+ priv = cbfile->priv;
+
+ g_mutex_lock (priv->refresh_lock);
+
+ priv->refresh_thread_stop = FALSE;
+ priv->refresh_skip = 0;
+
+ source = e_cal_backend_get_source (E_CAL_BACKEND (cbfile));
+ value = e_source_get_property (source, "refresh-type");
+ if (e_source_get_property (source, "custom-file") && value && *value && !value[1]) {
+ GFile *file;
+ GError *error = NULL;
+
+ switch (*value) {
+ case '1': /* on file change */
+ file = g_file_new_for_path (priv->custom_file);
+ priv->refresh_monitor = g_file_monitor_file (file, G_FILE_MONITOR_WATCH_MOUNTS, NULL, &error);
+ if (file)
+ g_object_unref (file);
+ if (priv->refresh_monitor)
+ g_signal_connect (G_OBJECT (priv->refresh_monitor), "changed", G_CALLBACK (custom_file_changed), priv);
+ break;
+ case '2': /* on refresh timeout */
+ value = e_source_get_property (source, "refresh");
+ if (value && atoi (value) > 0) {
+ priv->refresh_timeout_id = g_timeout_add_seconds (60 * atoi (value), (GSourceFunc) check_refresh_calendar_timeout, priv);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (priv->refresh_monitor || priv->refresh_timeout_id) {
+ priv->refresh_cond = g_cond_new ();
+ priv->refresh_gone_cond = g_cond_new ();
+
+ g_thread_create (refresh_thread_func, cbfile, FALSE, NULL);
+ }
+
+ g_mutex_unlock (priv->refresh_lock);
+}
+
+static void
+free_refresh_data (ECalBackendFile *cbfile)
+{
+ ECalBackendFilePrivate *priv;
+
+ g_return_if_fail (cbfile != NULL);
+
+ priv = cbfile->priv;
+ g_return_if_fail (priv != NULL);
+
+ g_mutex_lock (priv->refresh_lock);
+
+ if (priv->refresh_monitor)
+ g_object_unref (priv->refresh_monitor);
+ priv->refresh_monitor = NULL;
+
+ if (priv->refresh_timeout_id)
+ g_source_remove (priv->refresh_timeout_id);
+ priv->refresh_timeout_id = 0;
+
+ if (priv->refresh_cond) {
+ priv->refresh_thread_stop = TRUE;
+ g_cond_signal (priv->refresh_cond);
+ g_cond_wait (priv->refresh_gone_cond, priv->refresh_lock);
+
+ g_cond_free (priv->refresh_cond);
+ priv->refresh_cond = NULL;
+ g_cond_free (priv->refresh_gone_cond);
+ priv->refresh_gone_cond = NULL;
+ }
+
+ priv->refresh_skip = 0;
+
+ g_mutex_unlock (priv->refresh_lock);
+}
+
/* Parses an open iCalendar file and loads it into the backend */
static ECalBackendSyncStatus
open_cal (ECalBackendFile *cbfile, const gchar *uristr)
@@ -688,6 +905,8 @@ open_cal (ECalBackendFile *cbfile, const gchar *uristr)
priv = cbfile->priv;
+ free_refresh_data (cbfile);
+
icalcomp = e_cal_util_parse_ics_file (uristr);
if (!icalcomp)
return GNOME_Evolution_Calendar_OtherError;
@@ -704,10 +923,14 @@ open_cal (ECalBackendFile *cbfile, const gchar *uristr)
priv->icalcomp = icalcomp;
priv->path = uri_to_path (E_CAL_BACKEND (cbfile));
+ g_free (priv->custom_file);
+ priv->custom_file = g_strdup (uristr);
priv->comp_uid_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, free_object_data);
scan_vcalendar (cbfile);
+ prepare_refresh_data (cbfile);
+
return GNOME_Evolution_Calendar_Success;
}
@@ -870,6 +1093,8 @@ create_cal (ECalBackendFile *cbfile, const gchar *uristr)
gchar *dirname;
ECalBackendFilePrivate *priv;
+ free_refresh_data (cbfile);
+
priv = cbfile->priv;
/* Create the directory to contain the file */
@@ -891,6 +1116,10 @@ create_cal (ECalBackendFile *cbfile, const gchar *uristr)
save (cbfile);
+ g_free (priv->custom_file);
+ priv->custom_file = g_strdup (uristr);
+ prepare_refresh_data (cbfile);
+
return GNOME_Evolution_Calendar_Success;
}
@@ -1030,6 +1259,7 @@ e_cal_backend_file_open (ECalBackendSync *backend, EDataCal *cal, gboolean only_
goto done;
}
+ priv->read_only = FALSE;
if (g_access (str_uri, R_OK) == 0) {
status = open_cal (cbfile, str_uri);
if (g_access (str_uri, W_OK) != 0)
@@ -1042,6 +1272,13 @@ e_cal_backend_file_open (ECalBackendSync *backend, EDataCal *cal, gboolean only_
}
if (status == GNOME_Evolution_Calendar_Success) {
+ if (!priv->read_only) {
+ ESource *source = e_cal_backend_get_source (E_CAL_BACKEND (backend));
+
+ if (source && e_source_get_property (source, "custom-file-readonly") && g_str_equal (e_source_get_property (source, "custom-file-readonly"), "1"))
+ priv->read_only = TRUE;
+ }
+
if (priv->default_zone && add_timezone (priv->icalcomp, priv->default_zone)) {
save (cbfile);
}
@@ -2814,6 +3051,8 @@ e_cal_backend_file_init (ECalBackendFile *cbfile)
priv->icalcomp = NULL;
priv->comp_uid_hash = NULL;
priv->comp = NULL;
+ priv->custom_file = NULL;
+ priv->refresh_lock = g_mutex_new ();
/* The timezone defaults to UTC. */
priv->default_zone = icaltimezone_get_utc_timezone ();
@@ -2965,6 +3204,12 @@ e_cal_backend_file_reload (ECalBackendFile *cbfile)
g_free (str_uri);
+ if (status == GNOME_Evolution_Calendar_Success && !priv->read_only) {
+ ESource *source = e_cal_backend_get_source (E_CAL_BACKEND (cbfile));
+
+ if (source && e_source_get_property (source, "custom-file-readonly") && g_str_equal (e_source_get_property (source, "custom-file-readonly"), "1"))
+ priv->read_only = TRUE;
+ }
done:
g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
return status;
diff --git a/libedataserver/e-source.c b/libedataserver/e-source.c
index 9d34038..73b2aa4 100644
--- a/libedataserver/e-source.c
+++ b/libedataserver/e-source.c
@@ -304,9 +304,9 @@ e_source_update_from_xml_node (ESource *source,
if (source->priv->name == NULL
|| strcmp ((gchar *)name, source->priv->name) != 0
- || source->priv->relative_uri == NULL
- || relative_uri == NULL
- || strcmp ((gchar *)relative_uri, source->priv->relative_uri) != 0) {
+ || (source->priv->relative_uri == NULL && relative_uri != NULL)
+ || (source->priv->relative_uri != NULL && relative_uri == NULL)
+ || (relative_uri && source->priv->relative_uri && strcmp ((gchar *)relative_uri, source->priv->relative_uri) != 0)) {
gchar *abs_uri = NULL;
g_free (source->priv->name);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]