diff options
Diffstat (limited to 'calendar/pcs/cal-backend-object-sexp.c')
-rw-r--r-- | calendar/pcs/cal-backend-object-sexp.c | 1007 |
1 files changed, 1007 insertions, 0 deletions
diff --git a/calendar/pcs/cal-backend-object-sexp.c b/calendar/pcs/cal-backend-object-sexp.c new file mode 100644 index 0000000000..4bc6b78ebe --- /dev/null +++ b/calendar/pcs/cal-backend-object-sexp.c @@ -0,0 +1,1007 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * cal-backend-card-sexp.c + * Copyright 1999, 2000, 2001, Ximian, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License, version 2, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <string.h> +#include <libgnome/gnome-i18n.h> +#include <e-util/e-sexp.h> +#include <gal/widgets/e-unicode.h> +#include <cal-util/timeutil.h> + +#include "cal-backend-object-sexp.h" + +static GObjectClass *parent_class; + +typedef struct _SearchContext SearchContext; + +struct _CalBackendObjectSExpPrivate { + ESExp *search_sexp; + char *text; + SearchContext *search_context; +}; + +struct _SearchContext { + CalComponent *comp; + CalBackend *backend; +}; + +static ESExpResult * +func_time_now (ESExp *esexp, int argc, ESExpResult **argv, void *data) +{ + ESExpResult *result; + + if (argc != 0) { + e_sexp_fatal_error (esexp, _("time-now expects 0 arguments")); + return NULL; + } + + result = e_sexp_result_new (esexp, ESEXP_RES_TIME); + result->value.time = time (NULL); + + return result; +} + +/* (make-time ISODATE) + * + * ISODATE - string, ISO 8601 date/time representation + * + * Constructs a time_t value for the specified date. + */ +static ESExpResult * +func_make_time (ESExp *esexp, int argc, ESExpResult **argv, void *data) +{ + const char *str; + time_t t; + ESExpResult *result; + + if (argc != 1) { + e_sexp_fatal_error (esexp, _("make-time expects 1 argument")); + return NULL; + } + + if (argv[0]->type != ESEXP_RES_STRING) { + e_sexp_fatal_error (esexp, _("make-time expects argument 1 " + "to be a string")); + return NULL; + } + str = argv[0]->value.string; + + t = time_from_isodate (str); + if (t == -1) { + e_sexp_fatal_error (esexp, _("make-time argument 1 must be an " + "ISO 8601 date/time string")); + return NULL; + } + + result = e_sexp_result_new (esexp, ESEXP_RES_TIME); + result->value.time = t; + + return result; +} + +/* (time-add-day TIME N) + * + * TIME - time_t, base time + * N - int, number of days to add + * + * Adds the specified number of days to a time value. + * + * FIXME: TIMEZONES - need to use a timezone or daylight saving changes will + * make the result incorrect. + */ +static ESExpResult * +func_time_add_day (ESExp *esexp, int argc, ESExpResult **argv, void *data) +{ + ESExpResult *result; + time_t t; + int n; + + if (argc != 2) { + e_sexp_fatal_error (esexp, _("time-add-day expects 2 arguments")); + return NULL; + } + + if (argv[0]->type != ESEXP_RES_TIME) { + e_sexp_fatal_error (esexp, _("time-add-day expects argument 1 " + "to be a time_t")); + return NULL; + } + t = argv[0]->value.time; + + if (argv[1]->type != ESEXP_RES_INT) { + e_sexp_fatal_error (esexp, _("time-add-day expects argument 2 " + "to be an integer")); + return NULL; + } + n = argv[1]->value.number; + + result = e_sexp_result_new (esexp, ESEXP_RES_TIME); + result->value.time = time_add_day (t, n); + + return result; +} + +/* (time-day-begin TIME) + * + * TIME - time_t, base time + * + * Returns the start of the day, according to the local time. + * + * FIXME: TIMEZONES - this uses the current Unix timezone. + */ +static ESExpResult * +func_time_day_begin (ESExp *esexp, int argc, ESExpResult **argv, void *data) +{ + time_t t; + ESExpResult *result; + + if (argc != 1) { + e_sexp_fatal_error (esexp, _("time-day-begin expects 1 argument")); + return NULL; + } + + if (argv[0]->type != ESEXP_RES_TIME) { + e_sexp_fatal_error (esexp, _("time-day-begin expects argument 1 " + "to be a time_t")); + return NULL; + } + t = argv[0]->value.time; + + result = e_sexp_result_new (esexp, ESEXP_RES_TIME); + result->value.time = time_day_begin (t); + + return result; +} + +/* (time-day-end TIME) + * + * TIME - time_t, base time + * + * Returns the end of the day, according to the local time. + * + * FIXME: TIMEZONES - this uses the current Unix timezone. + */ +static ESExpResult * +func_time_day_end (ESExp *esexp, int argc, ESExpResult **argv, void *data) +{ + time_t t; + ESExpResult *result; + + if (argc != 1) { + e_sexp_fatal_error (esexp, _("time-day-end expects 1 argument")); + return NULL; + } + + if (argv[0]->type != ESEXP_RES_TIME) { + e_sexp_fatal_error (esexp, _("time-day-end expects argument 1 " + "to be a time_t")); + return NULL; + } + t = argv[0]->value.time; + + result = e_sexp_result_new (esexp, ESEXP_RES_TIME); + result->value.time = time_day_end (t); + + return result; +} + +/* (get-vtype) + * + * Returns a string indicating the type of component (VEVENT, VTODO, VJOURNAL, + * VFREEBUSY, VTIMEZONE, UNKNOWN). + */ +static ESExpResult * +func_get_vtype (ESExp *esexp, int argc, ESExpResult **argv, void *data) +{ + SearchContext *ctx = data; + CalComponentVType vtype; + char *str; + ESExpResult *result; + + /* Check argument types */ + + if (argc != 0) { + e_sexp_fatal_error (esexp, _("get-vtype expects 0 arguments")); + return NULL; + } + + /* Get the type */ + + vtype = cal_component_get_vtype (ctx->comp); + + switch (vtype) { + case CAL_COMPONENT_EVENT: + str = g_strdup ("VEVENT"); + break; + + case CAL_COMPONENT_TODO: + str = g_strdup ("VTODO"); + break; + + case CAL_COMPONENT_JOURNAL: + str = g_strdup ("VJOURNAL"); + break; + + case CAL_COMPONENT_FREEBUSY: + str = g_strdup ("VFREEBUSY"); + break; + + case CAL_COMPONENT_TIMEZONE: + str = g_strdup ("VTIMEZONE"); + break; + + default: + str = g_strdup ("UNKNOWN"); + break; + } + + result = e_sexp_result_new (esexp, ESEXP_RES_STRING); + result->value.string = str; + + return result; +} + +/* (occur-in-time-range? START END) + * + * START - time_t, start of the time range + * END - time_t, end of the time range + * + * Returns a boolean indicating whether the component has any occurrences in the + * specified time range. + */ +static ESExpResult * +func_occur_in_time_range (ESExp *esexp, int argc, ESExpResult **argv, void *data) +{ + SearchContext *ctx = data; + time_t start, end, tt; + gboolean occurs; + ESExpResult *result; + CalComponentDateTime dt; + + /* Check argument types */ + + if (argc != 2) { + e_sexp_fatal_error (esexp, _("occur-in-time-range? expects 2 arguments")); + return NULL; + } + + if (argv[0]->type != ESEXP_RES_TIME) { + e_sexp_fatal_error (esexp, _("occur-in-time-range? expects argument 1 " + "to be a time_t")); + return NULL; + } + start = argv[0]->value.time; + + if (argv[1]->type != ESEXP_RES_TIME) { + e_sexp_fatal_error (esexp, _("occur-in-time-range? expects argument 2 " + "to be a time_t")); + return NULL; + } + end = argv[1]->value.time; + + /* See if the object occurs in the specified time range */ + occurs = FALSE; + + cal_component_get_dtstart (ctx->comp, &dt); + if (dt.value) { + icaltimezone *zone; + + if (dt.tzid) + zone = cal_backend_internal_get_timezone (ctx->backend, dt.tzid); + else + zone = cal_backend_internal_get_default_timezone (ctx->backend); + + tt = icaltime_as_timet_with_zone (*dt.value, zone); + if (tt >= start && tt <= end) + occurs = TRUE; + else { + cal_component_get_dtend (ctx->comp, &dt); + if (dt.value) { + if (dt.tzid) + zone = cal_backend_internal_get_timezone (ctx->backend, dt.tzid); + else + zone = cal_backend_internal_get_default_timezone (ctx->backend); + + tt = icaltime_as_timet_with_zone (*dt.value, zone); + if (tt >= start && tt <= end) + occurs = TRUE; + } + } + } + + result = e_sexp_result_new (esexp, ESEXP_RES_BOOL); + result->value.bool = occurs; + + return result; +} + +/* Returns whether a list of CalComponentText items matches the specified string */ +static gboolean +matches_text_list (GSList *text_list, const char *str) +{ + GSList *l; + gboolean matches; + + matches = FALSE; + + for (l = text_list; l; l = l->next) { + CalComponentText *text; + + text = l->data; + g_assert (text->value != NULL); + + if (e_utf8_strstrcasedecomp (text->value, str) != NULL) { + matches = TRUE; + break; + } + } + + return matches; +} + +/* Returns whether the comments in a component matches the specified string */ +static gboolean +matches_comment (CalComponent *comp, const char *str) +{ + GSList *list; + gboolean matches; + + cal_component_get_comment_list (comp, &list); + matches = matches_text_list (list, str); + cal_component_free_text_list (list); + + return matches; +} + +/* Returns whether the description in a component matches the specified string */ +static gboolean +matches_description (CalComponent *comp, const char *str) +{ + GSList *list; + gboolean matches; + + cal_component_get_description_list (comp, &list); + matches = matches_text_list (list, str); + cal_component_free_text_list (list); + + return matches; +} + +/* Returns whether the summary in a component matches the specified string */ +static gboolean +matches_summary (CalComponent *comp, const char *str) +{ + CalComponentText text; + + cal_component_get_summary (comp, &text); + + if (!text.value) + return FALSE; + + return e_utf8_strstrcasedecomp (text.value, str) != NULL; +} + +/* Returns whether any text field in a component matches the specified string */ +static gboolean +matches_any (CalComponent *comp, const char *str) +{ + /* As an optimization, and to make life easier for the individual + * predicate functions, see if we are looking for the empty string right + * away. + */ + if (strlen (str) == 0) + return TRUE; + + return (matches_comment (comp, str) + || matches_description (comp, str) + || matches_summary (comp, str)); +} + +/* (contains? FIELD STR) + * + * FIELD - string, name of field to match (any, comment, description, summary) + * STR - string, match string + * + * Returns a boolean indicating whether the specified field contains the + * specified string. + */ +static ESExpResult * +func_contains (ESExp *esexp, int argc, ESExpResult **argv, void *data) +{ + SearchContext *ctx = data; + const char *field; + const char *str; + gboolean matches; + ESExpResult *result; + + /* Check argument types */ + + if (argc != 2) { + e_sexp_fatal_error (esexp, _("contains? expects 2 arguments")); + return NULL; + } + + if (argv[0]->type != ESEXP_RES_STRING) { + e_sexp_fatal_error (esexp, _("contains? expects argument 1 " + "to be a string")); + return NULL; + } + field = argv[0]->value.string; + + if (argv[1]->type != ESEXP_RES_STRING) { + e_sexp_fatal_error (esexp, _("contains? expects argument 2 " + "to be a string")); + return NULL; + } + str = argv[1]->value.string; + + /* See if it matches */ + + if (strcmp (field, "any") == 0) + matches = matches_any (ctx->comp, str); + else if (strcmp (field, "comment") == 0) + matches = matches_comment (ctx->comp, str); + else if (strcmp (field, "description") == 0) + matches = matches_description (ctx->comp, str); + else if (strcmp (field, "summary") == 0) + matches = matches_summary (ctx->comp, str); + else { + e_sexp_fatal_error (esexp, _("contains? expects argument 1 to " + "be one of \"any\", \"summary\", \"description\"")); + return NULL; + } + + result = e_sexp_result_new (esexp, ESEXP_RES_BOOL); + result->value.bool = matches; + + return result; +} + +/* (has-alarms? #f|#t) + * + * A boolean value for components that have/dont have alarms. + * + * Returns: a boolean indicating whether the component has alarms or not. + */ +static ESExpResult * +func_has_alarms (ESExp *esexp, int argc, ESExpResult **argv, void *data) +{ + SearchContext *ctx = data; + ESExpResult *result; + gboolean has_to_have_alarms; + + /* Check argument types */ + + if (argc != 1) { + e_sexp_fatal_error (esexp, _("has-alarms? expects at least 1 argument")); + return NULL; + } + + if (argv[0]->type != ESEXP_RES_BOOL) { + e_sexp_fatal_error (esexp, _("has-alarms? excepts argument to be a boolean")); + return NULL; + } + + has_to_have_alarms = argv[0]->value.bool; + result = e_sexp_result_new (esexp, ESEXP_RES_BOOL); + + if (has_to_have_alarms && cal_component_has_alarms (ctx->comp)) + result->value.bool = TRUE; + else if (!has_to_have_alarms && !cal_component_has_alarms (ctx->comp)) + result->value.bool = TRUE; + else + result->value.bool = FALSE; + + return result; +} + +/* (has-categories? STR+) + * (has-categories? #f) + * + * STR - At least one string specifying a category + * Or you can specify a single #f (boolean false) value for components + * that have no categories assigned to them ("unfiled"). + * + * Returns a boolean indicating whether the component has all the specified + * categories. + */ +static ESExpResult * +func_has_categories (ESExp *esexp, int argc, ESExpResult **argv, void *data) +{ + SearchContext *ctx = data; + gboolean unfiled; + int i; + GSList *categories; + gboolean matches; + ESExpResult *result; + + /* Check argument types */ + + if (argc < 1) { + e_sexp_fatal_error (esexp, _("has-categories? expects at least 1 argument")); + return NULL; + } + + if (argc == 1 && argv[0]->type == ESEXP_RES_BOOL) + unfiled = TRUE; + else + unfiled = FALSE; + + if (!unfiled) + for (i = 0; i < argc; i++) + if (argv[i]->type != ESEXP_RES_STRING) { + e_sexp_fatal_error (esexp, _("has-categories? expects all arguments " + "to be strings or one and only one " + "argument to be a boolean false (#f)")); + return NULL; + } + + /* Search categories. First, if there are no categories we return + * whether unfiled components are supposed to match. + */ + + cal_component_get_categories_list (ctx->comp, &categories); + if (!categories) { + result = e_sexp_result_new (esexp, ESEXP_RES_BOOL); + result->value.bool = unfiled; + + return result; + } + + /* Otherwise, we *do* have categories but unfiled components were + * requested, so this component does not match. + */ + if (unfiled) { + result = e_sexp_result_new (esexp, ESEXP_RES_BOOL); + result->value.bool = FALSE; + + return result; + } + + matches = TRUE; + + for (i = 0; i < argc; i++) { + const char *sought; + GSList *l; + gboolean has_category; + + sought = argv[i]->value.string; + + has_category = FALSE; + + for (l = categories; l; l = l->next) { + const char *category; + + category = l->data; + + if (strcmp (category, sought) == 0) { + has_category = TRUE; + break; + } + } + + if (!has_category) { + matches = FALSE; + break; + } + } + + cal_component_free_categories_list (categories); + + result = e_sexp_result_new (esexp, ESEXP_RES_BOOL); + result->value.bool = matches; + + return result; +} + +/* (is-completed?) + * + * Returns a boolean indicating whether the component is completed (i.e. has + * a COMPLETED property. This is really only useful for TODO components. + */ +static ESExpResult * +func_is_completed (ESExp *esexp, int argc, ESExpResult **argv, void *data) +{ + SearchContext *ctx = data; + ESExpResult *result; + struct icaltimetype *t; + gboolean complete = FALSE; + + /* Check argument types */ + + if (argc != 0) { + e_sexp_fatal_error (esexp, _("is-completed? expects 0 arguments")); + return NULL; + } + + cal_component_get_completed (ctx->comp, &t); + if (t) { + complete = TRUE; + cal_component_free_icaltimetype (t); + } + + result = e_sexp_result_new (esexp, ESEXP_RES_BOOL); + result->value.bool = complete; + + return result; +} + +/* (completed-before? TIME) + * + * TIME - time_t + * + * Returns a boolean indicating whether the component was completed on or + * before the given time (i.e. it checks the COMPLETED property). + * This is really only useful for TODO components. + */ +static ESExpResult * +func_completed_before (ESExp *esexp, int argc, ESExpResult **argv, void *data) +{ + SearchContext *ctx = data; + ESExpResult *result; + struct icaltimetype *tt; + icaltimezone *zone; + gboolean retval = FALSE; + time_t before_time, completed_time; + + /* Check argument types */ + + if (argc != 1) { + e_sexp_fatal_error (esexp, _("completed-before? expects 1 argument")); + return NULL; + } + + if (argv[0]->type != ESEXP_RES_TIME) { + e_sexp_fatal_error (esexp, _("completed-before? expects argument 1 " + "to be a time_t")); + return NULL; + } + before_time = argv[0]->value.time; + + cal_component_get_completed (ctx->comp, &tt); + if (tt) { + /* COMPLETED must be in UTC. */ + zone = icaltimezone_get_utc_timezone (); + completed_time = icaltime_as_timet_with_zone (*tt, zone); + +#if 0 + g_print ("Query Time : %s", ctime (&before_time)); + g_print ("Completed Time: %s", ctime (&completed_time)); +#endif + + /* We want to return TRUE if before_time is after + completed_time. */ + if (difftime (before_time, completed_time) > 0) { +#if 0 + g_print (" Returning TRUE\n"); +#endif + retval = TRUE; + } + + cal_component_free_icaltimetype (tt); + } + + result = e_sexp_result_new (esexp, ESEXP_RES_BOOL); + result->value.bool = retval; + + return result; +} + +#if 0 +static struct prop_info { + ECardSimpleField field_id; + const char *query_prop; + const char *ecard_prop; +#define PROP_TYPE_NORMAL 0x01 +#define PROP_TYPE_LIST 0x02 +#define PROP_TYPE_LISTITEM 0x03 +#define PROP_TYPE_ID 0x04 + int prop_type; + gboolean (*list_compare)(ECardSimple *ecard, const char *str, + char *(*compare)(const char*, const char*)); + +} prop_info_table[] = { +#define NORMAL_PROP(f,q,e) {f, q, e, PROP_TYPE_NORMAL, NULL} +#define ID_PROP {0, "id", NULL, PROP_TYPE_ID, NULL} +#define LIST_PROP(q,e,c) {0, q, e, PROP_TYPE_LIST, c} + + /* query prop, ecard prop, type, list compare function */ + NORMAL_PROP ( E_CARD_SIMPLE_FIELD_FILE_AS, "file_as", "file_as" ), + LIST_PROP ( "full_name", "full_name", compare_name), /* not really a list, but we need to compare both full and surname */ + NORMAL_PROP ( E_CARD_SIMPLE_FIELD_URL, "url", "url" ), + NORMAL_PROP ( E_CARD_SIMPLE_FIELD_MAILER, "mailer", "mailer"), + NORMAL_PROP ( E_CARD_SIMPLE_FIELD_ORG, "org", "org"), + NORMAL_PROP ( E_CARD_SIMPLE_FIELD_ORG_UNIT, "org_unit", "org_unit"), + NORMAL_PROP ( E_CARD_SIMPLE_FIELD_OFFICE, "office", "office"), + NORMAL_PROP ( E_CARD_SIMPLE_FIELD_TITLE, "title", "title"), + NORMAL_PROP ( E_CARD_SIMPLE_FIELD_ROLE, "role", "role"), + NORMAL_PROP ( E_CARD_SIMPLE_FIELD_MANAGER, "manager", "manager"), + NORMAL_PROP ( E_CARD_SIMPLE_FIELD_ASSISTANT, "assistant", "assistant"), + NORMAL_PROP ( E_CARD_SIMPLE_FIELD_NICKNAME, "nickname", "nickname"), + NORMAL_PROP ( E_CARD_SIMPLE_FIELD_SPOUSE, "spouse", "spouse" ), + NORMAL_PROP ( E_CARD_SIMPLE_FIELD_NOTE, "note", "note"), + ID_PROP, + LIST_PROP ( "email", "email", compare_email ), + LIST_PROP ( "phone", "phone", compare_phone ), + LIST_PROP ( "address", "address", compare_address ), + LIST_PROP ( "category", "category", compare_category ), + LIST_PROP ( "arbitrary", "arbitrary", compare_arbitrary ) +}; +static int num_prop_infos = sizeof(prop_info_table) / sizeof(prop_info_table[0]); + +static ESExpResult * +entry_compare(SearchContext *ctx, struct _ESExp *f, + int argc, struct _ESExpResult **argv, + char *(*compare)(const char*, const char*)) +{ + ESExpResult *r; + int truth = FALSE; + + if (argc == 2 + && argv[0]->type == ESEXP_RES_STRING + && argv[1]->type == ESEXP_RES_STRING) { + char *propname; + struct prop_info *info = NULL; + int i; + gboolean any_field; + + propname = argv[0]->value.string; + + any_field = !strcmp(propname, "x-evolution-any-field"); + for (i = 0; i < num_prop_infos; i ++) { + if (any_field + || !strcmp (prop_info_table[i].query_prop, propname)) { + info = &prop_info_table[i]; + + if (info->prop_type == PROP_TYPE_NORMAL) { + char *prop = NULL; + /* searches where the query's property + maps directly to an ecard property */ + + prop = e_card_simple_get (ctx->card, info->field_id); + + if (prop && compare(prop, argv[1]->value.string)) { + truth = TRUE; + } + if ((!prop) && compare("", argv[1]->value.string)) { + truth = TRUE; + } + g_free (prop); + } else if (info->prop_type == PROP_TYPE_LIST) { + /* the special searches that match any of the list elements */ + truth = info->list_compare (ctx->card, argv[1]->value.string, compare); + } else if (info->prop_type == PROP_TYPE_ID) { + const char *prop = NULL; + /* searches where the query's property + maps directly to an ecard property */ + + prop = e_card_get_id (ctx->card->card); + + if (prop && compare(prop, argv[1]->value.string)) { + truth = TRUE; + } + if ((!prop) && compare("", argv[1]->value.string)) { + truth = TRUE; + } + } + + /* if we're looking at all fields and find a match, + or if we're just looking at this one field, + break. */ + if ((any_field && truth) + || !any_field) + break; + } + } + + } + r = e_sexp_result_new(f, ESEXP_RES_BOOL); + r->value.bool = truth; + + return r; +} +#endif + +/* 'builtin' functions */ +static struct { + char *name; + ESExpFunc *func; + int type; /* set to 1 if a function can perform shortcut evaluation, or + doesn't execute everything, 0 otherwise */ +} symbols[] = { + /* Time-related functions */ + { "time-now", func_time_now, 0 }, + { "make-time", func_make_time, 0 }, + { "time-add-day", func_time_add_day, 0 }, + { "time-day-begin", func_time_day_begin, 0 }, + { "time-day-end", func_time_day_end, 0 }, + + /* Component-related functions */ + { "get-vtype", func_get_vtype, 0 }, + { "occur-in-time-range?", func_occur_in_time_range, 0 }, + { "contains?", func_contains, 0 }, + { "has-alarms?", func_has_alarms, 0 }, + { "has-categories?", func_has_categories, 0 }, + { "is-completed?", func_is_completed, 0 }, + { "completed-before?", func_completed_before, 0 } +}; + +gboolean +cal_backend_object_sexp_match_comp (CalBackendObjectSExp *sexp, CalComponent *comp, CalBackend *backend) +{ + ESExpResult *r; + gboolean retval; + + sexp->priv->search_context->comp = g_object_ref (comp); + sexp->priv->search_context->backend = g_object_ref (backend); + + /* if it's not a valid vcard why is it in our db? :) */ + if (!sexp->priv->search_context->comp) + return FALSE; + + r = e_sexp_eval(sexp->priv->search_sexp); + + retval = (r && r->type == ESEXP_RES_BOOL && r->value.bool); + + g_object_unref (sexp->priv->search_context->comp); + g_object_unref (sexp->priv->search_context->backend); + + e_sexp_result_free(sexp->priv->search_sexp, r); + + return retval; +} + +gboolean +cal_backend_object_sexp_match_object (CalBackendObjectSExp *sexp, const char *object, CalBackend *backend) +{ + CalComponent *comp; + icalcomponent *icalcomp; + gboolean retval; + + icalcomp = icalcomponent_new_from_string ((char *) object); + if (!icalcomp) + return FALSE; + + comp = cal_component_new (); + cal_component_set_icalcomponent (comp, icalcomp); + + retval = cal_backend_object_sexp_match_comp (sexp, comp, backend); + + g_object_unref (comp); + + return retval; +} + + + +/** + * cal_backend_card_sexp_new: + */ +CalBackendObjectSExp * +cal_backend_object_sexp_new (const char *text) +{ + CalBackendObjectSExp *sexp = g_object_new (CAL_TYPE_BACKEND_OBJECT_SEXP, NULL); + int esexp_error; + int i; + + sexp->priv->search_sexp = e_sexp_new(); + sexp->priv->text = g_strdup (text); + + for(i=0;i<sizeof(symbols)/sizeof(symbols[0]);i++) { + if (symbols[i].type == 1) { + e_sexp_add_ifunction(sexp->priv->search_sexp, 0, symbols[i].name, + (ESExpIFunc *)symbols[i].func, sexp->priv->search_context); + } else { + e_sexp_add_function(sexp->priv->search_sexp, 0, symbols[i].name, + symbols[i].func, sexp->priv->search_context); + } + } + + e_sexp_input_text(sexp->priv->search_sexp, text, strlen(text)); + esexp_error = e_sexp_parse(sexp->priv->search_sexp); + + if (esexp_error == -1) { + g_object_unref (sexp); + sexp = NULL; + } + + return sexp; +} + +const char * +cal_backend_object_sexp_text (CalBackendObjectSExp *sexp) +{ + CalBackendObjectSExpPrivate *priv; + + g_return_val_if_fail (sexp != NULL, NULL); + g_return_val_if_fail (CAL_IS_BACKEND_OBJECT_SEXP (sexp), NULL); + + priv = sexp->priv; + + return priv->text; +} + +static void +cal_backend_object_sexp_dispose (GObject *object) +{ + CalBackendObjectSExp *sexp = CAL_BACKEND_OBJECT_SEXP (object); + + if (sexp->priv) { + e_sexp_unref(sexp->priv->search_sexp); + + g_free (sexp->priv->text); + + g_free (sexp->priv->search_context); + g_free (sexp->priv); + sexp->priv = NULL; + } + + if (G_OBJECT_CLASS (parent_class)->dispose) + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +cal_backend_object_sexp_class_init (CalBackendObjectSExpClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + /* Set the virtual methods. */ + + object_class->dispose = cal_backend_object_sexp_dispose; +} + +static void +cal_backend_object_sexp_init (CalBackendObjectSExp *sexp) +{ + CalBackendObjectSExpPrivate *priv; + + priv = g_new0 (CalBackendObjectSExpPrivate, 1); + + sexp->priv = priv; + priv->search_context = g_new (SearchContext, 1); +} + +/** + * cal_backend_object_sexp_get_type: + */ +GType +cal_backend_object_sexp_get_type (void) +{ + static GType type = 0; + + if (! type) { + GTypeInfo info = { + sizeof (CalBackendObjectSExpClass), + NULL, /* base_class_init */ + NULL, /* base_class_finalize */ + (GClassInitFunc) cal_backend_object_sexp_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (CalBackendObjectSExp), + 0, /* n_preallocs */ + (GInstanceInitFunc) cal_backend_object_sexp_init + }; + + type = g_type_register_static (G_TYPE_OBJECT, "CalBackendObjectSExp", &info, 0); + } + + return type; +} |