<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -10,6 +10,7 @@ INCLUDES =						\
 	-I$(top_builddir)/calendar/libical/src/libical	\
 	$(EVOLUTION_CALENDAR_CFLAGS)
 
+noinst_PROGRAMS = test-intervaltree test-intervaltree-coverage test-interval-searches
 extension_LTLIBRARIES = libecalbackendfile.la
 
 libecalbackendfile_la_SOURCES =		\
@@ -17,6 +18,8 @@ libecalbackendfile_la_SOURCES =		\
 	e-cal-backend-file-factory.h\
 	e-cal-backend-file-events.c\
 	e-cal-backend-file-events.h\
+	e-cal-backend-file-intervaltree.c\
+	e-cal-backend-file-intervaltree.h\
 	e-cal-backend-file-journal.c\
 	e-cal-backend-file-journal.h\
 	e-cal-backend-file-todos.c\
@@ -30,5 +33,50 @@ libecalbackendfile_la_LIBADD =							\
 	$(top_builddir)/libedataserver/libedataserver-1.2.la			\
 	$(EVOLUTION_CALENDAR_LIBS)
 
+libecalbackendfile_la_CFLAGS =	$(AM_CFLAGS)
+
 libecalbackendfile_la_LDFLAGS =		\
 	-module -avoid-version $(NO_UNDEFINED)
+
+test_intervaltree_SOURCES = test-intervaltree.c e-cal-backend-file-intervaltree.c
+
+test_intervaltree_LDADD = \
+	$(top_builddir)/calendar/libecal/libecal-1.2.la				\
+	$(top_builddir)/calendar/libedata-cal/libedata-cal-1.2.la		\
+	$(top_builddir)/libedataserver/libedataserver-1.2.la			\
+	$(EVOLUTION_CALENDAR_LIBS)
+
+test_intervaltree_CFLAGS = $(AM_CFLAGS)
+
+test_interval_searches_SOURCES = e-cal-backend-file.c
+
+test_interval_searches_LDADD = \
+	$(top_builddir)/calendar/libecal/libecal-1.2.la				\
+	$(top_builddir)/calendar/libedata-cal/libedata-cal-1.2.la		\
+	$(top_builddir)/libedataserver/libedataserver-1.2.la			\
+	$(top_builddir)/calendar/backends/file/libecalbackendfile.la		\
+	$(EVOLUTION_CALENDAR_LIBS)
+
+test_interval_searches_CFLAGS = $(AM_CFLAGS) -DTEST_QUERY_RESULT
+
+test_intervaltree_coverage_SOURCES = test-intervaltree.c e-cal-backend-file-intervaltree.c
+
+test_intervaltree_coverage_LDADD = \
+	$(top_builddir)/calendar/libecal/libecal-1.2.la				\
+	$(top_builddir)/calendar/libedata-cal/libedata-cal-1.2.la		\
+	$(top_builddir)/libedataserver/libedataserver-1.2.la			\
+	$(EVOLUTION_CALENDAR_LIBS)						\
+	-lgcov
+
+test_intervaltree_coverage_CFLAGS = $(AM_CFLAGS) -fprofile-arcs -ftest-coverage 
+
+.PHONY: coverage
+coverage: 
+	mkdir -p ./coverage
+	lcov --directory . --zerocounters
+	./test-intervaltree-coverage
+	lcov --directory . --capture --output-file ./coverage/*.info
+	genhtml -o ./coverage --legend --num-spaces 2 ./coverage/*.info
+
+clean-local:
+	rm -f *.gcda *.gcno</diff>
      <filename>calendar/backends/file/Makefile.am</filename>
    </modified>
    <modified>
      <diff>@@ -35,6 +35,7 @@
 #include &lt;gio/gio.h&gt;
 #include &quot;libedataserver/e-data-server-util.h&quot;
 #include &quot;libedataserver/e-xml-hash-utils.h&quot;
+#include &quot;libedataserver/e-debug-log.h&quot;
 #include &lt;libecal/e-cal-recur.h&gt;
 #include &lt;libecal/e-cal-time-util.h&gt;
 #include &lt;libecal/e-cal-util.h&gt;
@@ -42,6 +43,7 @@
 #include &lt;libedata-cal/e-cal-backend-util.h&gt;
 #include &lt;libedata-cal/e-cal-backend-sexp.h&gt;
 #include &quot;e-cal-backend-file-events.h&quot;
+#include &quot;e-cal-backend-file-intervaltree.h&quot;
 
 #ifndef O_BINARY
 #define O_BINARY 0
@@ -82,6 +84,8 @@ struct _ECalBackendFilePrivate {
 	 */
 	GHashTable *comp_uid_hash;
 
+	EIntervalTree *interval_tree;
+
 	GList *comp;
 
 	/* The calendar's default timezone, used for resolving DATE and
@@ -104,6 +108,12 @@ static ECalBackendSyncClass *parent_class;
 static ECalBackendSyncStatus
 e_cal_backend_file_add_timezone (ECalBackendSync *backend, EDataCal *cal, const char *tzobj);
 
+static icaltimezone *
+e_cal_backend_file_internal_get_timezone (ECalBackend *backend, const char *tzid);
+
+static icaltimezone *
+e_cal_backend_file_internal_get_default_timezone (ECalBackend *backend);
+
 /* g_hash_table_foreach() callback to destroy a ECalBackendFileObject */
 static void
 free_object_data (gpointer data)
@@ -262,6 +272,9 @@ free_calendar_data (ECalBackendFile *cbfile)
 
 	priv = cbfile-&gt;priv;
 
+	e_intervaltree_destroy (priv-&gt;interval_tree);
+	priv-&gt;interval_tree = NULL;
+
 	free_calendar_components (priv-&gt;comp_uid_hash, priv-&gt;icalcomp);
 	priv-&gt;comp_uid_hash = NULL;
 	priv-&gt;icalcomp = NULL;
@@ -416,7 +429,12 @@ resolve_tzid (const char *tzid, gpointer user_data)
         else if (!strcmp (tzid, &quot;UTC&quot;))
                 return icaltimezone_get_utc_timezone ();
 
-	return icalcomponent_get_timezone (vcalendar_comp, tzid);
+	icaltimezone* zone = icalcomponent_get_timezone (vcalendar_comp, tzid);
+
+	if (!zone)
+		zone = icaltimezone_get_builtin_timezone_from_tzid (tzid);
+
+	return zone;
 }
 
 /* Checks if the specified component has a duplicated UID and if so changes it */
@@ -469,6 +487,58 @@ get_rid_icaltime (ECalComponent *comp)
         return tt;
 }
 
+
+/* Adds component to the interval tree
+ */
+static gboolean
+add_component_to_intervaltree (ECalBackendFile *cbfile, ECalComponent *comp)
+{
+	time_t time_start = -1, time_end = -1;
+	ECalBackendFilePrivate *priv;
+
+	g_return_val_if_fail (cbfile != NULL, FALSE);
+	g_return_val_if_fail (comp != NULL, FALSE);
+
+	priv = cbfile-&gt;priv;
+
+	get_component_occur_times (comp, &amp;time_start, &amp;time_end,
+				   resolve_tzid, priv-&gt;icalcomp, priv-&gt;default_zone);
+
+	if (time_end != -1 &amp;&amp; time_start &gt; time_end)
+		g_print (&quot;Bogus component %s\n&quot;, e_cal_component_get_as_string (comp));
+	else
+		e_intervaltree_insert (priv-&gt;interval_tree, time_start, time_end, comp);
+
+	return FALSE;
+}
+
+static gboolean 
+remove_component_from_intervaltree (ECalBackendFile *cbfile, ECalComponent *comp)
+{
+	time_t time_start = -1, time_end = -1;
+	const char *uid = NULL;
+	ECalBackendFilePrivate *priv;
+
+	g_return_val_if_fail (cbfile != NULL, FALSE);
+	g_return_val_if_fail (comp != NULL, FALSE);
+
+	priv = cbfile-&gt;priv;
+
+	get_component_occur_times (comp, &amp;time_start, &amp;time_end,
+				   resolve_tzid, priv-&gt;icalcomp, priv-&gt;default_zone);
+
+	if (time_end != -1 &amp;&amp; time_start &gt; time_end) {
+		g_error (&quot;Bogus component %s\n&quot;, e_cal_component_get_as_string (comp));
+		return FALSE;
+	} else {
+		char *rid = e_cal_component_get_recurid_as_string (comp);
+		e_cal_component_get_uid (comp, &amp;uid);
+		gboolean res = e_intervaltree_remove (priv-&gt;interval_tree, uid, rid, time_start, time_end);
+		g_free (rid);
+		return res;
+	}
+}
+
 /* Tries to add an icalcomponent to the file backend.  We only store the objects
  * of the types we support; all others just remain in the toplevel component so
  * that we don't lose them.
@@ -507,6 +577,7 @@ add_component (ECalBackendFile *cbfile, ECalComponent *comp, gboolean add_to_top
 			g_hash_table_insert (priv-&gt;comp_uid_hash, g_strdup (uid), obj_data);
 		}
 
+		add_component_to_intervaltree (cbfile, comp);
 		g_hash_table_insert (obj_data-&gt;recurrences, rid, comp);
 		obj_data-&gt;recurrences_list = g_list_append (obj_data-&gt;recurrences_list, comp);
 	} else {
@@ -528,6 +599,7 @@ add_component (ECalBackendFile *cbfile, ECalComponent *comp, gboolean add_to_top
 			obj_data-&gt;recurrences = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
 
 			g_hash_table_insert (priv-&gt;comp_uid_hash, g_strdup (uid), obj_data);
+			add_component_to_intervaltree (cbfile, comp);
 		}
 	}
 
@@ -561,6 +633,9 @@ remove_recurrence_cb (gpointer key, gpointer value, gpointer data)
 	icalcomp = e_cal_component_get_icalcomponent (comp);
 	g_assert (icalcomp != NULL);
 
+	if (!remove_component_from_intervaltree (cbfile, comp)) {
+		g_message (G_STRLOC &quot; Could not remove component from interval tree!&quot;);
+		}
 	icalcomponent_remove_component (priv-&gt;icalcomp, icalcomp);
 
 	/* remove it from our mapping */
@@ -594,6 +669,10 @@ remove_component (ECalBackendFile *cbfile, const char *uid, ECalBackendFileObjec
 		l = g_list_find (priv-&gt;comp, obj_data-&gt;full_object);
 		g_assert (l != NULL);
 		priv-&gt;comp = g_list_delete_link (priv-&gt;comp, l);
+
+		if (!remove_component_from_intervaltree (cbfile, obj_data-&gt;full_object)) {
+			g_message (G_STRLOC &quot; Could not remove component from interval tree!&quot;);
+		}
 	}
 
 	/* remove the recurrences also */
@@ -708,6 +787,7 @@ open_cal (ECalBackendFile *cbfile, const char *uristr)
 	priv-&gt;path = uri_to_path (E_CAL_BACKEND (cbfile));
 
 	priv-&gt;comp_uid_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, free_object_data);
+	priv-&gt;interval_tree = e_intervaltree_new ();
 	scan_vcalendar (cbfile);
 
 	return GNOME_Evolution_Calendar_Success;
@@ -853,6 +933,7 @@ reload_cal (ECalBackendFile *cbfile, const char *uristr)
 	priv-&gt;icalcomp = icalcomp;
 
 	priv-&gt;comp_uid_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, free_object_data);
+	priv-&gt;interval_tree = e_intervaltree_new ();
 	scan_vcalendar (cbfile);
 
 	priv-&gt;path = uri_to_path (E_CAL_BACKEND (cbfile));
@@ -889,6 +970,7 @@ create_cal (ECalBackendFile *cbfile, const char *uristr)
 
 	/* Create our internal data */
 	priv-&gt;comp_uid_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, free_object_data);
+	priv-&gt;interval_tree = e_intervaltree_new ();
 
 	priv-&gt;path = uri_to_path (E_CAL_BACKEND (cbfile));
 
@@ -1299,6 +1381,33 @@ typedef struct {
 } MatchObjectData;
 
 static void
+match_object_sexp_to_component (gpointer value, gpointer data)
+{
+	ECalComponent* comp = value;
+	MatchObjectData *match_data = data;
+	const char *uid;
+	e_cal_component_get_uid (comp, &amp;uid);
+	ECalBackendFile *cbfile;
+	ECalBackendFilePrivate *priv;
+
+	g_return_if_fail (comp != NULL);
+
+	cbfile = E_CAL_BACKEND_FILE (match_data-&gt;backend);
+
+	g_return_if_fail (match_data-&gt;backend != NULL);
+
+	priv = cbfile-&gt;priv;
+
+	g_return_if_fail (priv != NULL);
+
+	if ((!match_data-&gt;search_needed) ||
+	    (e_cal_backend_sexp_match_comp (match_data-&gt;obj_sexp, comp, match_data-&gt;backend))) {
+		match_data-&gt;obj_list = g_list_append (match_data-&gt;obj_list,
+						      e_cal_component_get_as_string (comp));
+	}
+}
+
+static void
 match_recurrence_sexp (gpointer key, gpointer value, gpointer data)
 {
 	ECalComponent *comp = value;
@@ -1331,6 +1440,7 @@ match_object_sexp (gpointer key, gpointer value, gpointer data)
 			      match_data);
 }
 
+
 /* Get_objects_in_range handler for the file backend */
 static ECalBackendSyncStatus
 e_cal_backend_file_get_object_list (ECalBackendSync *backend, EDataCal *cal, const char *sexp, GList **objects)
@@ -1358,11 +1468,35 @@ e_cal_backend_file_get_object_list (ECalBackendSync *backend, EDataCal *cal, con
 		return GNOME_Evolution_Calendar_InvalidQuery;
 
 	g_static_rec_mutex_lock (&amp;priv-&gt;idle_save_rmutex);
-	g_hash_table_foreach (priv-&gt;comp_uid_hash, (GHFunc) match_object_sexp, &amp;match_data);
+
+	time_t occur_start = -1, occur_end = -1;
+
+	gboolean prunning_by_time = e_cal_backend_sexp_evaluate_occur_times(match_data.obj_sexp,
+									    &amp;occur_start,
+									    &amp;occur_end);
+
+	GList* objs_occuring_in_tw =  NULL;
+
+	if (!prunning_by_time) {
+		g_hash_table_foreach (priv-&gt;comp_uid_hash, (GHFunc) match_object_sexp,
+				      &amp;match_data); 
+	} else {
+		objs_occuring_in_tw = e_intervaltree_search(priv-&gt;interval_tree,
+							    occur_start, occur_end);
+
+		g_list_foreach(objs_occuring_in_tw, (GFunc) match_object_sexp_to_component,
+			       &amp;match_data); 
+	}
+
 	g_static_rec_mutex_unlock (&amp;priv-&gt;idle_save_rmutex);
 
 	*objects = match_data.obj_list;
 
+	if (objs_occuring_in_tw) {
+		g_list_foreach(objs_occuring_in_tw, (GFunc)g_object_unref, NULL);
+		g_list_free (objs_occuring_in_tw);
+	}
+
 	g_object_unref (match_data.obj_sexp);
 
 	return GNOME_Evolution_Calendar_Success;
@@ -1396,28 +1530,64 @@ e_cal_backend_file_start_query (ECalBackend *backend, EDataCalView *query)
 	match_data.obj_list = NULL;
 	match_data.backend = backend;
 	match_data.default_zone = priv-&gt;default_zone;
+	match_data.obj_sexp = e_data_cal_view_get_object_sexp (query);
 
 	if (!strcmp (match_data.query, &quot;#t&quot;))
 		match_data.search_needed = FALSE;
 
-	match_data.obj_sexp = e_data_cal_view_get_object_sexp (query);
 	if (!match_data.obj_sexp) {
 		e_data_cal_view_notify_done (query, GNOME_Evolution_Calendar_InvalidQuery);
 		return;
 	}
 
+	time_t occur_start = -1, occur_end = -1;
+	gboolean prunning_by_time = e_cal_backend_sexp_evaluate_occur_times(match_data.obj_sexp,
+									    &amp;occur_start,
+									    &amp;occur_end);
+
+	GList* objs_occuring_in_tw = NULL;
+
 	g_static_rec_mutex_lock (&amp;priv-&gt;idle_save_rmutex);
-	g_hash_table_foreach (priv-&gt;comp_uid_hash, (GHFunc) match_object_sexp, &amp;match_data);
+
+	if (!prunning_by_time) {
+		/* full scan */
+		g_hash_table_foreach (priv-&gt;comp_uid_hash, (GHFunc) match_object_sexp,
+				      &amp;match_data); 
+
+		e_debug_log(FALSE, E_DEBUG_LOG_DOMAIN_CAL_QUERIES,  &quot;---;%p;QUERY-ITEMS;%s;%s;%d&quot;, query,
+			    e_data_cal_view_get_text (query), G_OBJECT_TYPE_NAME (backend),
+			    g_hash_table_size(priv-&gt;comp_uid_hash));
+	} else {
+		/* matches objects in new &quot;interval tree&quot; way */
+		/* events occuring in time window */
+		objs_occuring_in_tw = e_intervaltree_search(priv-&gt;interval_tree, occur_start, occur_end);
+
+		g_list_foreach(objs_occuring_in_tw, (GFunc) match_object_sexp_to_component,
+			       &amp;match_data); 
+
+		e_debug_log(FALSE, E_DEBUG_LOG_DOMAIN_CAL_QUERIES,  &quot;---;%p;QUERY-ITEMS;%s;%s;%d&quot;, query,
+			    e_data_cal_view_get_text (query), G_OBJECT_TYPE_NAME (backend),
+			    g_list_length (objs_occuring_in_tw));
+	}
+
 	g_static_rec_mutex_unlock (&amp;priv-&gt;idle_save_rmutex);
 
 	/* notify listeners of all objects */
 	if (match_data.obj_list) {
-		e_data_cal_view_notify_objects_added (query, (const GList *) match_data.obj_list);
+		e_data_cal_view_notify_objects_added
+			(query, (const GList *) match_data.obj_list);
 
 		/* free memory */
 		g_list_foreach (match_data.obj_list, (GFunc) g_free, NULL);
 		g_list_free (match_data.obj_list);
 	}
+
+
+	if (objs_occuring_in_tw) {
+		g_list_foreach(objs_occuring_in_tw, (GFunc)g_object_unref, NULL);
+		g_list_free (objs_occuring_in_tw);
+	}
+
 	g_object_unref (match_data.obj_sexp);
 
 	e_data_cal_view_notify_done (query, GNOME_Evolution_Calendar_Success);
@@ -2726,6 +2896,7 @@ e_cal_backend_file_init (ECalBackendFile *cbfile)
 	priv-&gt;icalcomp = NULL;
 	priv-&gt;comp_uid_hash = NULL;
 	priv-&gt;comp = NULL;
+	priv-&gt;interval_tree = NULL;
 
 	/* The timezone defaults to UTC. */
 	priv-&gt;default_zone = icaltimezone_get_utc_timezone ();
@@ -2882,3 +3053,250 @@ e_cal_backend_file_reload (ECalBackendFile *cbfile)
         g_static_rec_mutex_unlock (&amp;priv-&gt;idle_save_rmutex);
 	return status;
 }
+
+#ifdef TEST_QUERY_RESULT
+#include &lt;glib.h&gt;
+
+static void
+test_query_by_scanning_all_objects (ECalBackendFile* cbfile, const char *sexp, GList **objects)
+{
+	MatchObjectData match_data;
+	ECalBackendFilePrivate *priv;
+
+	priv = cbfile-&gt;priv;
+
+	match_data.search_needed = TRUE;
+	match_data.query = sexp;
+	match_data.obj_list = NULL;
+	match_data.default_zone = priv-&gt;default_zone;
+	match_data.backend = E_CAL_BACKEND (cbfile);
+
+	if (!strcmp (sexp, &quot;#t&quot;))
+		match_data.search_needed = FALSE;
+
+	match_data.obj_sexp = e_cal_backend_sexp_new (sexp);
+	if (!match_data.obj_sexp)
+		return;
+
+	g_static_rec_mutex_lock (&amp;priv-&gt;idle_save_rmutex);
+
+	if (!match_data.obj_sexp)
+	{
+		g_message (G_STRLOC &quot;: Getting object list (%s)&quot;, sexp);
+		exit (-1);
+	}
+
+	g_hash_table_foreach (priv-&gt;comp_uid_hash, (GHFunc) match_object_sexp,
+			&amp;match_data); 
+
+	g_static_rec_mutex_unlock (&amp;priv-&gt;idle_save_rmutex);
+
+	*objects = match_data.obj_list;
+
+	g_object_unref (match_data.obj_sexp);
+}
+
+static void
+write_list (GList* list)
+{
+	GList *l;
+
+	for (l = list; l; l = l-&gt;next)
+	{
+		const char *str = l-&gt;data;
+		ECalComponent *comp = e_cal_component_new_from_string (str);
+		const char *uid;
+		e_cal_component_get_uid (comp, &amp;uid);
+		g_print (&quot;%s\n&quot;, uid);
+	}
+}
+
+static void
+get_difference_of_lists (ECalBackendFile* cbfile, GList* smaller, GList* bigger)
+{
+	GList *l, *lsmaller;
+
+	for (l = bigger ; l; l = l-&gt;next) {
+		char *str = l-&gt;data;
+
+		ECalComponent *comp = e_cal_component_new_from_string (str);
+		const char *uid;
+		e_cal_component_get_uid (comp, &amp;uid);
+		gboolean found = FALSE;
+
+		for (lsmaller = smaller; lsmaller &amp;&amp; !found; lsmaller = lsmaller-&gt;next)
+		{
+			char *strsmaller = lsmaller-&gt;data;
+			ECalComponent *compsmaller = e_cal_component_new_from_string (strsmaller);
+			const char *uidsmaller;
+			e_cal_component_get_uid (compsmaller, &amp;uidsmaller);
+
+			found = strcmp (uid, uidsmaller) == 0;
+
+			g_object_unref (compsmaller);
+		}
+
+		if (!found)
+		{
+			printf (&quot;%s IS MISSING\n&quot;, uid);
+			time_t time_start, time_end;
+
+			get_component_occur_times (comp, &amp;time_start, &amp;time_end,
+						   resolve_tzid, cbfile-&gt;priv-&gt;icalcomp,
+						   cbfile-&gt;priv-&gt;default_zone);
+
+			d (printf (&quot;start %s\n&quot;, asctime(gmtime(&amp;time_start))));
+			d (printf (&quot;end %s\n&quot;, asctime(gmtime(&amp;time_end))));
+		}
+
+		g_object_unref (comp);
+	}
+}
+
+static void
+test_query (ECalBackendFile* cbfile, const char* query)
+{
+	GList *objects = NULL, *all_objects = NULL;
+
+	g_return_if_fail (query != NULL);
+
+	d (g_print (&quot;Query %s\n&quot;, query));
+
+	test_query_by_scanning_all_objects (cbfile, query, &amp;all_objects);
+
+	if (e_cal_backend_file_get_object_list (E_CAL_BACKEND_SYNC (cbfile), NULL, query, &amp;objects)
+	    != GNOME_Evolution_Calendar_Success)
+	{
+		g_message (G_STRLOC &quot; failed to get objects\n&quot;);
+		exit(0);
+	}
+
+	if (g_list_length (objects) &lt; g_list_length (all_objects) )
+	{
+		g_print (&quot;ERROR\n&quot;);
+		get_difference_of_lists (cbfile, objects, all_objects);
+		exit (-1);
+	}
+	else if (g_list_length (objects) &gt; g_list_length (all_objects) )
+	{
+		g_print (&quot;ERROR\n&quot;);
+		write_list (all_objects);
+		get_difference_of_lists (cbfile, all_objects, objects);
+		exit (-1);
+	}
+
+
+	g_list_foreach(objects, (GFunc) g_free, NULL);
+	g_list_free (objects);
+	g_list_foreach(all_objects, (GFunc) g_free, NULL);
+	g_list_free (all_objects);
+}
+
+static void
+execute_query (ECalBackendFile* cbfile, const char* query)
+{
+	GList *objects = NULL;
+
+	g_return_if_fail (query != NULL);
+
+	d (g_print (&quot;Query %s\n&quot;, query));
+
+	if (e_cal_backend_file_get_object_list (E_CAL_BACKEND_SYNC (cbfile), NULL, query, &amp;objects)
+	    != GNOME_Evolution_Calendar_Success)
+	{
+		g_message (G_STRLOC &quot; failed to get objects\n&quot;);
+		exit(0);
+	}
+
+	g_list_foreach(objects, (GFunc) g_free, NULL);
+	g_list_free (objects);
+}
+
+static gchar *fname = NULL;
+static gboolean only_execute = FALSE;
+static gchar *calendar_fname = NULL;
+
+static GOptionEntry entries[] = 
+{
+  { &quot;test-file&quot;, 't', 0, G_OPTION_ARG_STRING, &amp;fname, &quot;File with prepared queries&quot;, NULL },
+  { &quot;only-execute&quot;, 'e', 0, G_OPTION_ARG_NONE, &amp;only_execute, &quot;Only execute, do not test query&quot;, NULL },
+  { &quot;calendar-file&quot;, 'c', 0, G_OPTION_ARG_STRING, &amp;calendar_fname, &quot;Path to the calendar.ics file&quot;, NULL },
+  { NULL }
+};
+
+int
+main(int argc, char **argv)
+{
+	char * line = NULL;
+	size_t len = 0;
+	ssize_t read;
+	ECalBackendFile* cbfile;
+	int num = 0;
+	GError *error = NULL;
+	GOptionContext *context;
+	FILE* fin = NULL;
+
+	g_type_init ();
+	g_thread_init (NULL);
+
+	context = g_option_context_new (&quot;- test utility for e-d-s file backend&quot;);
+	g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
+	if (!g_option_context_parse (context, &amp;argc, &amp;argv, &amp;error))
+	{
+		g_print (&quot;option parsing failed: %s\n&quot;, error-&gt;message);
+		exit (1);
+	}
+
+	calendar_fname = &quot;calendar.ics&quot;;
+
+	if (!calendar_fname)
+	{
+		g_message (G_STRLOC &quot; Please, use -c parameter&quot;);
+		exit (-1);
+	}
+
+	cbfile = g_object_new (E_TYPE_CAL_BACKEND_FILE, NULL);
+	if (open_cal (cbfile, calendar_fname) != GNOME_Evolution_Calendar_Success)
+	{
+		g_message (G_STRLOC &quot; Could not open calendar %s&quot;, calendar_fname);
+		exit (-1);
+	}
+
+	if (fname)
+	{
+		fin = fopen (fname, &quot;r&quot;);
+
+		if (!fin)
+		{
+			g_message (G_STRLOC &quot; Could not open file %s&quot;, fname);
+			goto err0;
+		}
+	}
+	else
+	{
+		g_message (G_STRLOC &quot; Reading from stdin&quot;);
+		fin = stdin;
+	}
+
+	while ((read = getline(&amp;line, &amp;len, fin)) != -1) {
+		g_print (&quot;Query %d: %s&quot;, num++, line);
+
+		if (only_execute)
+			execute_query(cbfile, line);
+		else
+			test_query(cbfile, line);
+	}
+
+	if (line)
+		free(line);
+
+	if (fname)
+		fclose (fin);
+
+err0:
+	g_object_unref (cbfile);
+
+	return 0;
+}
+#endif
+</diff>
      <filename>calendar/backends/file/e-cal-backend-file.c</filename>
    </modified>
    <modified>
      <diff>@@ -917,6 +917,66 @@ array_to_list (short *array, int max_elements)
 	return g_list_reverse (l);
 }
 
+/** 
+ * e_cal_recur_get_enddate
+ * 
+ * @ir: RRULE or EXRULE recurrence 
+ * @prop: An RRULE or EXRULE #icalproperty. 
+ * @zone: The DTSTART timezone, used for converting the UNTIL property if it
+ * is given as a DATE value.
+ * @convert_end_date: TRUE if the saved end date needs to be converted to the
+ * given @zone timezone. This is needed if the DTSTART is a DATE or floating
+ * time.
+ * 
+ * @return End timepoint of giben event
+ *
+ * Finds out end time of (reccurent) event.
+ */
+time_t
+e_cal_recur_obtain_enddate (struct icalrecurrencetype *ir, icalproperty *prop,
+          icaltimezone *zone, gboolean convert_end_date)
+{
+  time_t enddate = -1;
+
+  g_return_val_if_fail (prop != NULL, 0);
+  g_return_val_if_fail (ir != NULL, 0);
+
+  if (ir-&gt;count != 0) {
+    /* If COUNT is set, we use the pre-calculated enddate.
+       Note that this can be 0 if the RULE doesn't actually
+       generate COUNT instances. */
+    enddate = e_cal_recur_get_rule_end_date (prop, convert_end_date ? zone : NULL);
+  } else {
+    if (icaltime_is_null_time (ir-&gt;until)) {
+      /* If neither COUNT or UNTIL is set, the event
+         recurs forever. */
+    } else if (ir-&gt;until.is_date) {
+      /* If UNTIL is a DATE, we stop at the end of
+         the day, in local time (with the DTSTART timezone).
+         Note that UNTIL is inclusive so we stop before
+         midnight. */
+      ir-&gt;until.hour = 23;
+      ir-&gt;until.minute = 59;
+      ir-&gt;until.second = 59;
+      ir-&gt;until.is_date = FALSE;
+
+      enddate = icaltime_as_timet_with_zone (ir-&gt;until, zone);
+#if 0
+      g_print (&quot;  until: %li - %s&quot;, r-&gt;enddate, ctime (&amp;r-&gt;enddate));
+#endif
+
+    } else {
+      /* If UNTIL is a DATE-TIME, it must be in UTC. */
+      icaltimezone *utc_zone;
+      utc_zone = icaltimezone_get_utc_timezone ();
+      enddate = icaltime_as_timet_with_zone (ir-&gt;until,
+                                             utc_zone);
+    }
+  }
+
+  return enddate;
+}
+
 /**
  * e_cal_recur_from_icalproperty:
  * @prop: An RRULE or EXRULE #icalproperty.
@@ -953,40 +1013,7 @@ e_cal_recur_from_icalproperty (icalproperty *prop, gboolean exception,
 	r-&gt;freq = ir.freq;
 	r-&gt;interval = ir.interval;
 
-	if (ir.count != 0) {
-		/* If COUNT is set, we use the pre-calculated enddate.
-		   Note that this can be 0 if the RULE doesn't actually
-		   generate COUNT instances. */
-		r-&gt;enddate = e_cal_recur_get_rule_end_date (prop, convert_end_date ? zone : NULL);
-	} else {
-		if (icaltime_is_null_time (ir.until)) {
-			/* If neither COUNT or UNTIL is set, the event
-			   recurs forever. */
-			r-&gt;enddate = 0;
-		} else if (ir.until.is_date) {
-			/* If UNTIL is a DATE, we stop at the end of
-			   the day, in local time (with the DTSTART timezone).
-			   Note that UNTIL is inclusive so we stop before
-			   midnight. */
-			ir.until.hour = 23;
-			ir.until.minute = 59;
-			ir.until.second = 59;
-			ir.until.is_date = FALSE;
-
-			r-&gt;enddate = icaltime_as_timet_with_zone (ir.until,
-								  zone);
-#if 0
-			g_print (&quot;  until: %li - %s&quot;, r-&gt;enddate, ctime (&amp;r-&gt;enddate));
-#endif
-
-		} else {
-			/* If UNTIL is a DATE-TIME, it must be in UTC. */
-			icaltimezone *utc_zone;
-			utc_zone = icaltimezone_get_utc_timezone ();
-			r-&gt;enddate = icaltime_as_timet_with_zone (ir.until,
-								  utc_zone);
-		}
-	}
+  r-&gt;enddate = e_cal_recur_obtain_enddate (&amp;ir, prop, zone, convert_end_date);
 
 	r-&gt;week_start_day = e_cal_recur_ical_weekday_to_weekday (ir.week_start);
 </diff>
      <filename>calendar/libecal/e-cal-recur.c</filename>
    </modified>
    <modified>
      <diff>@@ -45,6 +45,12 @@ void	e_cal_recur_generate_instances	(ECalComponent		*comp,
 					 gpointer		   tz_cb_data,
 					 icaltimezone		*default_timezone);
 
+time_t
+e_cal_recur_obtain_enddate (struct icalrecurrencetype *ir,
+                            icalproperty *prop,
+                            icaltimezone *zone,
+                            gboolean convert_end_date);
+
 /* Localized nth-day-of-month strings. (Use with _() ) */
 #ifdef G_OS_WIN32
 extern const char **e_cal_get_recur_nth (void);</diff>
      <filename>calendar/libecal/e-cal-recur.h</filename>
    </modified>
    <modified>
      <diff>@@ -32,6 +32,7 @@ $(CORBA_GENERATED_C): $(CORBA_GENERATED_H)
 
 # The libraray
 lib_LTLIBRARIES = libedata-cal-1.2.la
+noinst_PROGRAMS = test-e-sexp
 
 libedata_cal_1_2_la_SOURCES =		\
 	$(CORBA_GENERATED_C)		\
@@ -72,6 +73,10 @@ libedata_calinclude_HEADERS = 		\
 %-$(API_VERSION).pc: %.pc
 	 cp $&lt; $@
 
+test_e_sexp_SOURCES = e-cal-backend-sexp.c
+test_e_sexp_CFLAGS = $(AM_CFLAGS) -DTESTER
+test_e_sexp_LDADD = libedata-cal-1.2.la $(E_DATA_SERVER_LIBS)
+
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = libedata-cal-$(API_VERSION).pc
 </diff>
      <filename>calendar/libedata-cal/Makefile.am</filename>
    </modified>
    <modified>
      <diff>@@ -1272,6 +1272,25 @@ static struct {
 };
 
 /**
+ * e_cal_backend_sexp_evaluate_occur_times:
+ * @sexp: An #ESExp object.
+ * @start: Start of the time window will be stored here.
+ * @end: End of the time window will be stored here.
+ *
+ * Determines biggest time window given by expressions &quot;occur-in-range&quot; in sexp.
+ *
+ */
+gboolean
+e_cal_backend_sexp_evaluate_occur_times(ECalBackendSExp *sexp, time_t *start, time_t *end)
+{
+	g_return_val_if_fail (sexp != NULL, FALSE);
+	g_return_val_if_fail (start != NULL, FALSE);
+	g_return_val_if_fail (end != NULL, FALSE);
+
+	return e_sexp_evaluate_occur_times(sexp-&gt;priv-&gt;search_sexp, start, end);
+}
+
+/**
  * e_cal_backend_sexp_match_comp:
  * @sexp: An #ESExp object.
  * @comp: Component to match against the expression.
@@ -1476,3 +1495,51 @@ e_cal_backend_sexp_get_type (void)
 
 	return type;
 }
+
+#ifdef TESTER
+static void
+test_query (const char* query)
+{
+	ECalBackendSExp *sexp = e_cal_backend_sexp_new (query);
+	time_t start, end;
+
+	gboolean generator = e_cal_backend_sexp_evaluate_occur_times(sexp, &amp;start, &amp;end);
+
+	if (generator) {
+		printf (&quot;%s: %ld - %ld\n&quot;, query, start, end);
+	} else {
+		printf (&quot;%s: no time prunning possible\n&quot;, query);
+	}
+}
+
+int main(int argc, char **argv)
+{
+	g_type_init();
+
+	/* e_sexp_add_variable(f, 0, &quot;test&quot;, NULL); */
+
+	if (argc &lt; 2 || !argv[1])
+	{
+		test_query (&quot;(occur-in-time-range? (make-time \&quot;20080727T220000Z\&quot;) (make-time \&quot;20080907T220000Z\&quot;))&quot;);
+		test_query (&quot;(due-in-time-range? (make-time \&quot;20080727T220000Z\&quot;) (make-time \&quot;20080907T220000Z\&quot;))&quot;);
+		test_query (&quot;(has-alarms-in-range? (make-time \&quot;20080727T220000Z\&quot;) (make-time \&quot;20080907T220000Z\&quot;))&quot;);
+		test_query (&quot;(completed-before? (make-time \&quot;20080727T220000Z\&quot;) )&quot;);
+
+		test_query (&quot;(and (occur-in-time-range? (make-time \&quot;20080727T220000Z\&quot;) (make-time \&quot;20080907T220000Z\&quot;)) #t)&quot;);
+		test_query (&quot;(or (occur-in-time-range? (make-time \&quot;20080727T220000Z\&quot;)(make-time \&quot;20080907T220000Z\&quot;)) #t)&quot;);
+
+		test_query (&quot;(and (contains? \&quot;substring\&quot;) (has-categories? \&quot;blah\&quot;))&quot;);
+		test_query (&quot;(or (occur-in-time-range? (make-time \&quot;20080727T220000Z\&quot;) (make-time \&quot;20080907T220000Z\&quot;)) (contains? \&quot;substring\&quot;))&quot;);
+
+		test_query (&quot;(and (and (occur-in-time-range? (make-time \&quot;20080727T220000Z\&quot;) (make-time \&quot;20080907T220000Z\&quot;))&quot;
+			    &quot; (or (contains? \&quot;substring\&quot;) (has-categories? \&quot;blah\&quot;))) (has-alarms?))&quot;);
+
+		test_query (&quot;(or (and (occur-in-time-range? (make-time \&quot;20080727T220000Z\&quot;) (make-time \&quot;20080907T220000Z\&quot;))&quot;
+			    &quot; (or (contains? \&quot;substring\&quot;) (has-categories? \&quot;blah\&quot;))) (has-alarms?))&quot;);
+	}
+	else
+		test_query(argv[1]);
+
+	return 0;
+}
+#endif</diff>
      <filename>calendar/libedata-cal/e-cal-backend-sexp.c</filename>
    </modified>
    <modified>
      <diff>@@ -72,6 +72,9 @@ ESExpResult *e_cal_backend_sexp_func_time_add_day   (ESExp *esexp, int argc, ESE
 ESExpResult *e_cal_backend_sexp_func_time_day_begin (ESExp *esexp, int argc, ESExpResult **argv, void *data);
 ESExpResult *e_cal_backend_sexp_func_time_day_end   (ESExp *esexp, int argc, ESExpResult **argv, void *data);
 
+gboolean	e_cal_backend_sexp_evaluate_occur_times	(ECalBackendSExp *sexp, time_t *start, time_t *end);
+gboolean 	e_cal_backend_sexp_is_a_time_function(const char *function_name);
+gboolean        e_cal_backend_sexp_is_a_generator_function(const char *function_name);
 
 G_END_DECLS
 </diff>
      <filename>calendar/libedata-cal/e-cal-backend-sexp.h</filename>
    </modified>
    <modified>
      <diff>@@ -109,6 +109,12 @@ static void parse_dump_term(struct _ESExpTerm *t, int depth);
 static GObjectClass *parent_class;
 #endif
 
+typedef gboolean (ESGeneratorFunc)(int argc, struct _ESExpResult **argv, struct _ESExpResult *r);
+typedef gboolean (ESOperatorFunc)(int argc, struct _ESExpResult **argv, struct _ESExpResult *r);
+/* FIXME: constant _TIME_MAX used in different files, move it somewhere */
+#define _TIME_MAX	((time_t) INT_MAX)	/* Max valid time_t	*/
+
+
 static const GScannerConfig scanner_config =
 {
 	( &quot; \t\r\n&quot;)		/* cset_skip_characters */,
@@ -173,6 +179,9 @@ e_sexp_result_new(struct _ESExp *f, int type)
 {
 	struct _ESExpResult *r = e_memchunk_alloc0(f-&gt;result_chunks);
 	r-&gt;type = type;
+	r-&gt;occuring_start = 0;
+	r-&gt;occuring_end = _TIME_MAX;
+	r-&gt;time_generator = FALSE;
 	return r;
 }
 
@@ -699,7 +708,7 @@ e_sexp_term_eval(struct _ESExp *f, struct _ESExpTerm *t)
 		r-&gt;value.bool = t-&gt;value.bool;
 		break;
 	case ESEXP_TERM_TIME:
-		r(printf(&quot; (time_t %d)\n&quot;, t-&gt;value.time));
+		r(printf(&quot; (time_t %ld)\n&quot;, t-&gt;value.time));
 		r = e_sexp_result_new (f, ESEXP_RES_TIME);
 		r-&gt;value.time = t-&gt;value.time;
 		break;
@@ -814,6 +823,236 @@ parse_dump_term(struct _ESExpTerm *t, int depth)
 	printf(&quot;\n&quot;);
 }
 
+const char *time_functions[] = {
+	&quot;time-now&quot;,
+	&quot;make-time&quot;,
+	&quot;time-add-day&quot;,
+	&quot;time-day-begin&quot;,
+	&quot;time-day-end&quot;
+};
+
+static gboolean
+binary_generator (int argc, struct _ESExpResult **argv, struct _ESExpResult *r)
+{
+	g_return_val_if_fail (r != NULL, FALSE);
+	g_return_val_if_fail (argc == 2, FALSE);
+
+	if ((argv[0]-&gt;type != ESEXP_RES_TIME) || (argv[1]-&gt;type != ESEXP_RES_TIME))
+		return FALSE;
+
+	r-&gt;occuring_start = argv[0]-&gt;value.time;
+	r-&gt;occuring_end = argv[1]-&gt;value.time;
+
+	return TRUE;
+}
+
+static gboolean
+unary_generator(int argc, struct _ESExpResult **argv, struct _ESExpResult *r)
+{
+	/* unary generator with end time */
+	g_return_val_if_fail (r != NULL, FALSE);
+	g_return_val_if_fail (argc == 1, FALSE);
+
+	if (argv[0]-&gt;type != ESEXP_RES_TIME)
+		return FALSE;
+
+        r-&gt;occuring_start = 0;
+	r-&gt;occuring_end = argv[0]-&gt;value.time;
+
+	return TRUE;
+}
+
+static const struct {
+	char *name;
+	ESGeneratorFunc *func;
+} generators[] = {
+	{&quot;occur-in-time-range?&quot;, binary_generator},
+	{&quot;due-in-time-range?&quot;, binary_generator},
+	{&quot;has-alarms-in-range?&quot;, binary_generator},
+	{&quot;completed-before?&quot;, unary_generator},
+};
+
+const int generators_count = sizeof(generators) / sizeof(generators[0]);
+
+static gboolean
+or_operator(int argc, struct _ESExpResult **argv, struct _ESExpResult *r)
+{
+	/*
+	   A          B           A or B
+	   ----       ----        ------
+	   norm(0)    norm(0)     norm(0)
+	   gen(1)     norm(0)     norm(0)
+	   norm(0)    gen(1)      norm(0)
+	   gen(1)     gen(1)      gen*(1)
+	   */
+
+	g_return_val_if_fail (r != NULL, FALSE);
+	g_return_val_if_fail (argc == 2, FALSE);
+
+	if ((r-&gt;time_generator = argv[0]-&gt;time_generator &amp; argv[1]-&gt;time_generator)) {
+		r-&gt;occuring_start = MIN(argv[0]-&gt;occuring_start, argv[1]-&gt;occuring_start);
+		r-&gt;occuring_end = MAX(argv[0]-&gt;occuring_end, argv[1]-&gt;occuring_end);
+	}
+
+	return TRUE;
+}
+
+static gboolean
+and_operator(int argc, struct _ESExpResult **argv, struct _ESExpResult *r)
+{
+	/*
+	   A           B          A and B
+	   ----        ----       ------- -
+	   norm(0)     norm(0)    norm(0)    
+	   gen(1)      norm(0)    gen(1)    
+	   norm(0)     gen(1)     gen(1)     
+	   gen(1)      gen(1)     gen(1)     
+	   */
+
+	g_return_val_if_fail (r != NULL, FALSE);
+	g_return_val_if_fail (argc == 2, FALSE);
+
+	if ((r-&gt;time_generator = argv[0]-&gt;time_generator | argv[1]-&gt;time_generator)) {
+		/* constraint interval */
+		r-&gt;occuring_start = MAX(argv[0]-&gt;occuring_start, argv[1]-&gt;occuring_start);
+		r-&gt;occuring_end = MIN(argv[0]-&gt;occuring_end, argv[1]-&gt;occuring_end);
+	}
+
+	return TRUE;
+}
+
+static const struct {
+	char *name;
+	ESOperatorFunc *func;
+} operators[] = {
+	{&quot;or&quot;, or_operator},
+	{&quot;and&quot;, and_operator}
+};
+
+const int operators_count = sizeof(operators) / sizeof(operators[0]);
+
+
+static ESOperatorFunc*
+get_operator_function(const char *fname)
+{
+	int i;
+
+	g_return_val_if_fail (fname != NULL, NULL);
+
+	for (i = 0; i &lt; sizeof(operators) / sizeof(operators[0]); i++)
+		if (strcmp(operators[i].name, fname) == 0)
+			return operators[i].func;
+
+	return NULL;
+}
+
+static inline gboolean
+is_time_function(const char *fname)
+{
+	int i;
+
+	g_return_val_if_fail (fname != NULL, FALSE);
+
+	for (i = 0; i &lt; sizeof(time_functions) / sizeof(time_functions[0]); i++)
+		if (strcmp(time_functions[i], fname) == 0)
+			return TRUE;
+
+	return FALSE;
+}
+
+static ESGeneratorFunc*
+get_generator_function(const char *fname)
+{
+	int i;
+
+	g_return_val_if_fail (fname != NULL, NULL);
+
+	for (i = 0; i &lt; sizeof(generators) / sizeof(generators[0]); i++)
+		if (strcmp(generators[i].name, fname) == 0)
+			return generators[i].func;
+
+	return NULL;
+}
+
+/* this must only be called from inside term evaluation callbacks! */
+static struct _ESExpResult *
+e_sexp_term_evaluate_occur_times(struct _ESExp *f, struct _ESExpTerm *t, time_t *start, time_t *end)
+{
+	struct _ESExpResult *r = NULL;
+	int i;
+	struct _ESExpResult **argv;
+	gboolean ok = TRUE;
+
+	g_return_val_if_fail(t != NULL, NULL);
+	g_return_val_if_fail(start != NULL, NULL);
+	g_return_val_if_fail(end != NULL, NULL);
+
+	/*
+	printf(&quot;eval term :\n&quot;);
+	parse_dump_term(t, 0);
+	*/
+
+	switch (t-&gt;type) {
+	case ESEXP_TERM_STRING:
+		r(printf(&quot; (string \&quot;%s\&quot;)\n&quot;, t-&gt;value.string));
+		r = e_sexp_result_new(f, ESEXP_RES_STRING);
+		r-&gt;value.string = g_strdup(t-&gt;value.string);
+		break;
+	case ESEXP_TERM_IFUNC:
+	case ESEXP_TERM_FUNC:
+		r(printf(&quot; (function \&quot;%s\&quot;\n&quot;, t-&gt;value.func.sym-&gt;name));
+
+		r = e_sexp_result_new(f, ESEXP_RES_UNDEFINED);
+		int argc = t-&gt;value.func.termcount;
+		argv = alloca(sizeof(argv[0]) * argc);
+
+		for (i=0;i&lt;t-&gt;value.func.termcount;i++) {
+			argv[i] = e_sexp_term_evaluate_occur_times (f, t-&gt;value.func.terms[i],
+								    start, end);
+		}
+
+		ESGeneratorFunc *generator = NULL;
+		ESOperatorFunc *operator = NULL;
+
+		if (is_time_function(t-&gt;value.func.sym-&gt;name)) {
+			/* evaluate time */
+			if (t-&gt;value.func.sym-&gt;f.func)
+				r = t-&gt;value.func.sym-&gt;f.func(f, t-&gt;value.func.termcount,
+					      argv, t-&gt;value.func.sym-&gt;data);
+		} else if ((generator = get_generator_function(t-&gt;value.func.sym-&gt;name)) != NULL) {
+			/* evaluate generator function */
+			r-&gt;time_generator = TRUE;
+			ok = generator(argc, argv, r);
+		} else if ((operator = get_operator_function(t-&gt;value.func.sym-&gt;name)) != NULL)
+			/* evaluate operator function */
+			ok = operator(argc, argv, r);
+		else {
+			/* normal function: we need to scan all objects */
+			r-&gt;time_generator = FALSE;
+		}
+
+		e_sexp_resultv_free(f, t-&gt;value.func.termcount, argv);
+		break;
+
+	case ESEXP_TERM_INT:
+	case ESEXP_TERM_BOOL:
+	case ESEXP_TERM_TIME:
+		break;
+	default:
+		ok = FALSE;
+		break;
+	}
+
+	if (!ok)
+		e_sexp_fatal_error(f, &quot;Error in parse tree&quot;);
+
+	if (r==NULL)
+		r = e_sexp_result_new(f, ESEXP_RES_UNDEFINED);
+
+	return r;
+}
+
+
 /*
   PARSER
 */
@@ -1321,6 +1560,43 @@ e_sexp_eval(ESExp *f)
 }
 
 /**
+ * e_cal_backend_sexp_evaluate_occur_times:
+ * @f: An #ESExp object.
+ * @start: Start of the time window will be stored here.
+ * @end: End of the time window will be stored here.
+ *
+ * Determines biggest time window given by expressions &quot;occur-in-range&quot; in sexp.
+ *
+ */
+gboolean
+e_sexp_evaluate_occur_times(ESExp *f, time_t *start, time_t *end)
+{
+	g_return_val_if_fail (IS_E_SEXP (f), FALSE);
+	g_return_val_if_fail (f-&gt;tree != NULL, FALSE);
+	g_return_val_if_fail (start != NULL, FALSE);
+	g_return_val_if_fail (end != NULL, FALSE);
+
+	*start = *end = -1;
+
+	if (setjmp(f-&gt;failenv)) {
+		g_warning(&quot;Error in execution: %s&quot;, f-&gt;error);
+		return FALSE;
+	}
+
+	struct _ESExpResult *r = e_sexp_term_evaluate_occur_times(f, f-&gt;tree, start, end);
+	gboolean generator = r-&gt;time_generator;
+
+	if (generator) {
+		*start = r-&gt;occuring_start;
+		*end = r-&gt;occuring_end;
+	}
+
+	e_sexp_result_free(f, r);
+
+	return generator;
+}
+
+/**
  * e_sexp_encode_bool:
  * @s:
  * @state:
@@ -1378,7 +1654,10 @@ int main(int argc, char **argv)
 
 	e_sexp_add_variable(f, 0, &quot;test&quot;, NULL);
 
-	e_sexp_input_text(f, t, strlen(t));
+	if (argc &lt; 2 || !argv[1])
+		return;
+
+	e_sexp_input_text(f, t, t);
 	e_sexp_parse(f);
 
 	if (f-&gt;tree) {</diff>
      <filename>libedataserver/e-sexp.c</filename>
    </modified>
    <modified>
      <diff>@@ -57,6 +57,9 @@ struct _ESExpResult {
 		int bool;
 		time_t time;
 	} value;
+	gboolean time_generator;
+	time_t occuring_start;
+	time_t occuring_end;
 };
 
 typedef struct _ESExpResult *(ESExpFunc)(struct _ESExp *sexp, int argc,
@@ -176,6 +179,7 @@ const char     *e_sexp_error		(struct _ESExp *f);
 
 ESExpTerm * e_sexp_parse_value(ESExp *f);
 
+gboolean	e_sexp_evaluate_occur_times	(ESExp *f, time_t *start, time_t *end);
 G_END_DECLS
 
 #endif /* _E_SEXP_H */</diff>
      <filename>libedataserver/e-sexp.h</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>11deffa20b97ca2aa4d8a1d20a091e67b4ee02a6</id>
    </parent>
  </parents>
  <author>
    <name>Stanislav Slusny</name>
    <email>stanislav.slusny@zonio.net</email>
  </author>
  <url>http://github.com/slusnys/evolution-data-server/commit/de2890881d06cd77c9e9207a175a3dbd9287731e</url>
  <id>de2890881d06cd77c9e9207a175a3dbd9287731e</id>
  <committed-date>2008-08-18T14:20:04-07:00</committed-date>
  <authored-date>2008-08-18T11:10:01-07:00</authored-date>
  <message>Adding interval trees to speed up queries in file backend

Using interval trees to solve queries in calendar file backend.
Adding tests for interval trees.</message>
  <tree>e4562ee09a3ad1a37b1b3ae53ceff647897b3838</tree>
  <committer>
    <name>Stanislav Slusny</name>
    <email>stanislav.slusny@zonio.net</email>
  </committer>
</commit>
