From f6ee20d9097f3ba7bce189f3015e65721d328122 Mon Sep 17 00:00:00 2001 From: Federico Mena Quintero Date: Wed, 29 Aug 2001 03:15:54 +0000 Subject: Fixes bug #7879, a query may receive an update notification from the 2001-08-28 Federico Mena Quintero Fixes bug #7879, a query may receive an update notification from the backend before the query itself gets populated. * pcs/query.c (ensure_sexp): New function; ensures that the esexp is created and notifies of parse errors. It is the bulk of start_query_cb() but put in a separate function so that we can share it elsewhere. (start_query_cb): Use ensure_sexp(). (process_component_cb): Oops, notify of a successfully finished query. (match_component): Call ensure_sexp(). This function can be called by the backend notification callbacks before the query is populated, so we need to make sure the esexp exists here. svn path=/trunk/; revision=12509 --- calendar/pcs/query.c | 126 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 98 insertions(+), 28 deletions(-) (limited to 'calendar/pcs/query.c') diff --git a/calendar/pcs/query.c b/calendar/pcs/query.c index ae76ec9795..1b991a85ea 100644 --- a/calendar/pcs/query.c +++ b/calendar/pcs/query.c @@ -36,6 +36,14 @@ +/* States of a query */ +typedef enum { + QUERY_START_PENDING, /* the query is not populated yet */ + QUERY_IN_PROGRESS, /* the query is populated; components are still being processed */ + QUERY_DONE, /* the query is done, but still accepts object changes */ + QUERY_PARSE_ERROR /* a parse error occurred when initially creating the ESexp */ +} QueryState; + /* Private part of the Query structure */ struct _QueryPrivate { /* The backend we are monitoring */ @@ -48,8 +56,9 @@ struct _QueryPrivate { char *sexp; ESExp *esexp; - /* Idle handler ID for asynchronous queries */ + /* Idle handler ID for asynchronous queries and the current state */ guint idle_id; + QueryState state; /* List of UIDs that we still have to process */ GList *pending_uids; @@ -110,6 +119,9 @@ query_init (Query *query) priv->ql = CORBA_OBJECT_NIL; priv->sexp = NULL; + priv->idle_id = 0; + priv->state = QUERY_START_PENDING; + priv->pending_uids = NULL; priv->uids = g_hash_table_new (g_str_hash, g_str_equal); @@ -954,6 +966,66 @@ create_sexp (Query *query) return esexp; } +/* Ensures that the sexp has been parsed and the ESexp has been created. If a + * parse error occurs, it sets the query state to QUERY_PARSE_ERROR and returns + * FALSE. + */ +static gboolean +ensure_sexp (Query *query) +{ + QueryPrivate *priv; + + priv = query->priv; + + if (priv->state == QUERY_PARSE_ERROR) + g_assert_not_reached (); /* we should already have terminated everything */ + + if (priv->esexp) + return TRUE; + + /* Compile the query string */ + + priv->esexp = create_sexp (query); + + g_assert (priv->sexp != NULL); + e_sexp_input_text (priv->esexp, priv->sexp, strlen (priv->sexp)); + + if (e_sexp_parse (priv->esexp) == -1) { + const char *error_str; + CORBA_Environment ev; + + /* Change the state and disconnect from any notifications */ + + priv->state = QUERY_PARSE_ERROR; + gtk_signal_disconnect_by_data (GTK_OBJECT (priv->backend), query); + + /* Report the error to the listener */ + + error_str = e_sexp_error (priv->esexp); + g_assert (error_str != NULL); + + CORBA_exception_init (&ev); + GNOME_Evolution_Calendar_QueryListener_notifyQueryDone ( + priv->ql, + GNOME_Evolution_Calendar_QueryListener_PARSE_ERROR, + error_str, + &ev); + + if (ev._major != CORBA_NO_EXCEPTION) + g_message ("ensure_sexp(): Could not notify the listener of " + "a parse error"); + + CORBA_exception_free (&ev); + + e_sexp_unref (priv->esexp); + priv->esexp = NULL; + + return FALSE; + } + + return TRUE; +} + /* Evaluates the query sexp on the specified component and notifies the listener * as appropriate. */ @@ -967,6 +1039,11 @@ match_component (Query *query, const char *uid, priv = query->priv; + g_assert (priv->state != QUERY_PARSE_ERROR); + + if (!ensure_sexp (query)) + return; + comp = cal_backend_get_object_component (priv->backend, uid); g_assert (comp != NULL); gtk_object_ref (GTK_OBJECT (comp)); @@ -1041,9 +1118,26 @@ process_component_cb (gpointer data) /* No more components? */ if (!priv->pending_uids) { + CORBA_Environment ev; + g_assert (priv->n_pending == 0); priv->idle_id = 0; + priv->state = QUERY_DONE; + + CORBA_exception_init (&ev); + GNOME_Evolution_Calendar_QueryListener_notifyQueryDone ( + priv->ql, + GNOME_Evolution_Calendar_QueryListener_SUCCESS, + "", + &ev); + + if (ev._major != CORBA_NO_EXCEPTION) + g_message ("process_component_cb(): Could not notify the listener of " + "a finished query"); + + CORBA_exception_free (&ev); + return FALSE; } @@ -1087,12 +1181,14 @@ populate_query (Query *query) priv = query->priv; g_assert (priv->idle_id == 0); + g_assert (priv->state == QUERY_START_PENDING); priv->pending_uids = cal_backend_get_uids (priv->backend, CALOBJ_TYPE_ANY); priv->pending_total = g_list_length (priv->pending_uids); priv->n_pending = priv->pending_total; priv->idle_id = g_idle_add (process_component_cb, query); + priv->state = QUERY_IN_PROGRESS; } /* Idle handler for starting a query */ @@ -1101,40 +1197,14 @@ start_query_cb (gpointer data) { Query *query; QueryPrivate *priv; - CORBA_Environment ev; query = QUERY (data); priv = query->priv; priv->idle_id = 0; - priv->esexp = create_sexp (query); - - /* Compile the query string */ - - g_assert (priv->sexp != NULL); - e_sexp_input_text (priv->esexp, priv->sexp, strlen (priv->sexp)); - - if (e_sexp_parse (priv->esexp) == -1) { - const char *error_str; - - error_str = e_sexp_error (priv->esexp); - g_assert (error_str != NULL); - - CORBA_exception_init (&ev); - GNOME_Evolution_Calendar_QueryListener_notifyQueryDone ( - priv->ql, - GNOME_Evolution_Calendar_QueryListener_PARSE_ERROR, - error_str, - &ev); - - if (ev._major != CORBA_NO_EXCEPTION) - g_message ("start_query_cb(): Could not notify the listener of " - "a parse error"); - - CORBA_exception_free (&ev); + if (!ensure_sexp (query)) return FALSE; - } /* Populate the query with UIDs so that we can process them asynchronously */ -- cgit v1.2.3