Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:pchenthill
evolution-data-server
fix-ense-opt.diff
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File fix-ense-opt.diff of Package evolution-data-server
Index: addressbook/libebook/e-vcard.c =================================================================== --- e-vcard.c (revision 333) +++ addressbook/libebook/e-vcard.c (working copy) @@ -1475,6 +1475,27 @@ return evcard->priv->attributes; } +EVCardAttribute * +e_vcard_get_attribute (EVCard *vcard, + const char *name) +{ + GList *attrs, *l; + + g_return_val_if_fail (E_IS_VCARD (vcard), NULL); + g_return_val_if_fail (name != NULL, NULL); + + attrs = e_vcard_get_attributes (vcard); + for (l = attrs; l; l = l->next) { + EVCardAttribute *attr; + const char *n; + + attr = (EVCardAttribute *) l->data; + if (strcmp (attr->name, name) == 0) + return attr; + } + + return NULL; +} /** * e_vcard_attribute_get_group: * @attr: an #EVCardAttribute Index: addressbook/libebook/e-vcard.h =================================================================== --- e-vcard.h (revision 314) +++ addressbook/libebook/e-vcard.h (working copy) @@ -168,6 +168,7 @@ /* EVCard* accessors. nothing returned from these functions should be freed by the caller. */ +EVCardAttribute *e_vcard_get_attribute (EVCard *vcard, const char *name); GList* e_vcard_get_attributes (EVCard *evcard); const char* e_vcard_attribute_get_group (EVCardAttribute *attr); const char* e_vcard_attribute_get_name (EVCardAttribute *attr); Index: libedataserverui/e-name-selector-entry.c =================================================================== RCS file: /cvs/gnome/evolution-data-server/libedataserverui/e-name-selector-entry.c,v retrieving revision 1.30 diff -u -p -r1.30 e-name-selector-entry.c --- libedataserverui/e-name-selector-entry.c 5 Mar 2006 10:17:07 -0000 1.30 +++ libedataserverui/e-name-selector-entry.c 1 Jun 2006 06:28:11 -0000 @@ -46,6 +46,14 @@ G_DEFINE_TYPE (ENameSelectorEntry, e_name_selector_entry, GTK_TYPE_ENTRY); +typedef struct _ENameSelectorEntryPrivate ENameSelectorEntryPrivate; +struct _ENameSelectorEntryPrivate +{ + gboolean is_completing; +}; + +#define E_NAME_SELECTOR_ENTRY_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), E_TYPE_NAME_SELECTOR_ENTRY, ENameSelectorEntryPrivate)) + static void e_name_selector_entry_class_init (ENameSelectorEntryClass *name_selector_entry_class); static void e_name_selector_entry_init (ENameSelectorEntry *name_selector_entry); static void e_name_selector_entry_dispose (GObject *object); @@ -117,6 +125,7 @@ e_name_selector_entry_class_init (ENameS /* Install signals */ + g_type_class_add_private (object_class, sizeof(ENameSelectorEntryPrivate)); } /* Remove unquoted commas from string */ @@ -729,6 +738,9 @@ type_ahead_complete (ENameSelectorEntry const gchar *text; gchar *cue_str; gchar *temp_str; + ENameSelectorEntryPrivate *priv; + + priv = E_NAME_SELECTOR_ENTRY_GET_PRIVATE (name_selector_entry); cursor_pos = gtk_editable_get_position (GTK_EDITABLE (name_selector_entry)); if (cursor_pos < 0) @@ -767,6 +779,7 @@ type_ahead_complete (ENameSelectorEntry gtk_editable_insert_text (GTK_EDITABLE (name_selector_entry), textrep, -1, &pos); gtk_editable_select_region (GTK_EDITABLE (name_selector_entry), range_end, range_start + textrep_len); + priv->is_completing = TRUE; } if (contact && destination) { @@ -790,10 +803,15 @@ type_ahead_complete (ENameSelectorEntry static void clear_completion_model (ENameSelectorEntry *name_selector_entry) { + ENameSelectorEntryPrivate *priv; + + priv = E_NAME_SELECTOR_ENTRY_GET_PRIVATE (name_selector_entry); + if (!name_selector_entry->contact_store) return; e_contact_store_set_query (name_selector_entry->contact_store, NULL); + priv->is_completing = FALSE; } static void @@ -1277,6 +1295,9 @@ entry_activate (ENameSelectorEntry *name gint cursor_pos; gint range_start, range_end; const gchar *text; + ENameSelectorEntryPrivate *priv; + + priv = E_NAME_SELECTOR_ENTRY_GET_PRIVATE (name_selector_entry); /* Show us what's really there */ @@ -1288,13 +1309,30 @@ entry_activate (ENameSelectorEntry *name text = gtk_entry_get_text (GTK_ENTRY (name_selector_entry)); get_range_at_position (text, cursor_pos, &range_start, &range_end); gtk_editable_set_position (GTK_EDITABLE (name_selector_entry), range_end); + + priv->is_completing = FALSE; +} + +static gboolean +user_focus_in (ENameSelectorEntry *name_selector_entry, GdkEventFocus *event_focus) +{ + /* + * To preserve selected text, do not propagate the event any more. + */ + + return TRUE; } static gboolean user_focus_out (ENameSelectorEntry *name_selector_entry, GdkEventFocus *event_focus) { - if (!event_focus->in) + ENameSelectorEntryPrivate *priv; + + priv = E_NAME_SELECTOR_ENTRY_GET_PRIVATE (name_selector_entry); + + if (!event_focus->in && priv->is_completing) { entry_activate (name_selector_entry); + } clear_completion_model (name_selector_entry); @@ -2026,6 +2064,9 @@ static void e_name_selector_entry_init (ENameSelectorEntry *name_selector_entry) { GtkCellRenderer *renderer; + ENameSelectorEntryPrivate *priv; + + priv = E_NAME_SELECTOR_ENTRY_GET_PRIVATE (name_selector_entry); /* Source list */ @@ -2039,6 +2080,7 @@ e_name_selector_entry_init (ENameSelecto g_signal_connect (name_selector_entry, "insert-text", G_CALLBACK (user_insert_text), name_selector_entry); g_signal_connect (name_selector_entry, "delete-text", G_CALLBACK (user_delete_text), name_selector_entry); g_signal_connect (name_selector_entry, "focus-out-event", G_CALLBACK (user_focus_out), name_selector_entry); + g_signal_connect_after (name_selector_entry, "focus-in-event", G_CALLBACK (user_focus_in), name_selector_entry); /* Exposition */ @@ -2079,6 +2121,7 @@ e_name_selector_entry_init (ENameSelecto name_selector_entry->destination_store = e_destination_store_new (); setup_destination_store (name_selector_entry); + priv->is_completing = FALSE; } /** Index: libedataserverui/Makefile.am =================================================================== RCS file: /cvs/gnome/evolution-data-server/libedataserverui/Makefile.am,v retrieving revision 1.17 diff -u -p -r1.17 Makefile.am --- libedataserverui/Makefile.am 23 Aug 2006 09:25:14 -0000 1.17 +++ libedataserverui/Makefile.am 11 Dec 2006 06:42:02 -0000 @@ -22,6 +22,7 @@ libedataserverui_1_2_la_SOURCES = \ e-categories-dialog.c \ e-destination-store.c \ e-book-auth-util.c \ + e-book-sexp.c \ e-contact-store.c \ e-name-selector.c \ e-name-selector-dialog.c \ @@ -54,6 +55,7 @@ libedataserveruiinclude_HEADERS = \ e-categories-dialog.h \ e-destination-store.h \ e-book-auth-util.h \ + e-book-sexp.h \ e-contact-store.h \ e-name-selector.h \ e-name-selector-dialog.h \ Index: libedataserverui/e-contact-store.c =================================================================== RCS file: /cvs/gnome/evolution-data-server/libedataserverui/e-contact-store.c,v retrieving revision 1.13 diff -u -p -r1.13 e-contact-store.c --- e-contact-store.c 7 Aug 2006 10:57:45 -0000 1.13 +++ libedataserverui/e-contact-store.c 11 Dec 2006 06:42:03 -0000 @@ -30,6 +30,7 @@ #include <gtk/gtktreednd.h> #include <glib/gi18n-lib.h> #include "e-contact-store.h" +#include "e-book-sexp.h" #define ITER_IS_VALID(contact_store, iter) ((iter)->stamp == (contact_store)->stamp) #define ITER_GET(iter) GPOINTER_TO_INT (iter->user_data) @@ -85,6 +86,13 @@ typedef struct } ContactSource; +typedef struct +{ + EBookSExp *sexp; + +} EContactStorePrivate; +#define E_CONTACT_STORE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), E_TYPE_CONTACT_STORE, EContactStorePrivate)) + static void free_contact_ptrarray (GPtrArray *contacts); static void clear_contact_source (EContactStore *contact_store, ContactSource *source); static void stop_view (EContactStore *contact_store, EBookView *view); @@ -140,6 +148,7 @@ e_contact_store_class_init (EContactStor object_class = (GObjectClass *) class; object_class->finalize = e_contact_store_finalize; + g_type_class_add_private (object_class, sizeof(EContactStorePrivate)); } static void @@ -162,9 +171,13 @@ e_contact_store_tree_model_init (GtkTree static void e_contact_store_init (EContactStore *contact_store) { + EContactStorePrivate *priv; + + priv = E_CONTACT_STORE_GET_PRIVATE (contact_store); contact_store->stamp = g_random_int (); contact_store->query = NULL; contact_store->contact_sources = g_array_new (FALSE, FALSE, sizeof (ContactSource)); + priv->sexp = NULL; } static void @@ -586,7 +599,12 @@ view_sequence_complete (EContactStore *c ContactSource *source; gint offset; gint i; - + EContactStorePrivate *priv; + EBookSExp *sexp; + + priv = E_CONTACT_STORE_GET_PRIVATE (contact_store); + sexp = priv->sexp; + if (!find_contact_source_details_by_view (contact_store, book_view, &source, &offset)) { g_warning ("EContactStore got 'sequence_complete' signal from unknown EBookView!"); return; @@ -600,6 +618,9 @@ view_sequence_complete (EContactStore *c g_assert (book_view == source->book_view_pending); + if (sexp) + g_object_ref (sexp); + /* However, if it was a pending view, calculate and emit the differences between that * and the current view, and move the pending view up to current. * @@ -630,8 +651,13 @@ view_sequence_complete (EContactStore *c result = find_contact_by_view_and_uid (contact_store, source->book_view, new_uid); if (result < 0) { /* Contact is not in old view; inserted */ - g_ptr_array_add (source->contacts, new_contact); - row_inserted (contact_store, offset + source->contacts->len - 1); + if (!sexp || e_book_sexp_match_contact(sexp, new_contact)) { + g_ptr_array_add (source->contacts, new_contact); + row_inserted (contact_store, offset + source->contacts->len - 1); + } else { + /* Doesnt match the search present. Let us ignore it.*/ + g_object_unref (new_contact); + } } else { /* Contact already in old view; drop the new one */ g_object_unref (new_contact); @@ -647,6 +673,8 @@ view_sequence_complete (EContactStore *c /* Free array of pending contacts (members have been either moved or unreffed) */ g_ptr_array_free (source->contacts_pending, TRUE); source->contacts_pending = NULL; + if (sexp) + g_object_unref (sexp); } /* --------------------- * @@ -965,12 +993,19 @@ void e_contact_store_set_query (EContactStore *contact_store, EBookQuery *book_query) { gint i; - + EContactStorePrivate *priv; + g_return_if_fail (E_IS_CONTACT_STORE (contact_store)); + priv = E_CONTACT_STORE_GET_PRIVATE (contact_store); + if (book_query == contact_store->query) return; + if (priv->sexp) + g_object_unref (priv->sexp); + priv->sexp = NULL; + if (contact_store->query) e_book_query_unref (contact_store->query); @@ -1217,4 +1252,58 @@ e_contact_store_get_value (GtkTreeModel field_name = e_contact_field_name (column); g_object_get_property (G_OBJECT (contact), field_name, value); +} + +void +e_contact_store_set_sexp (EContactStore *contact_store, const char *qsexp) +{ + EContactStorePrivate *priv; + + priv = E_CONTACT_STORE_GET_PRIVATE (contact_store); + + if (priv->sexp) + g_object_unref (priv->sexp); + + if (qsexp) + priv->sexp = e_book_sexp_new (qsexp); + else + priv->sexp = NULL; +} + +void +e_contact_store_rebuild_with_sexp (EContactStore *contact_store) +{ + gint i; + EContactStorePrivate *priv; + EBookSExp *sexp; + + priv = E_CONTACT_STORE_GET_PRIVATE (contact_store); + sexp = priv->sexp; + + /* if the user types so fast than we search, we may hit a freed sexp. Lets ref and unref it */ + g_object_ref (sexp); + + for (i = 0; i < contact_store->contact_sources->len; i++) { + ContactSource *source = &g_array_index (contact_store->contact_sources, ContactSource, i); + int offset = get_contact_source_offset (contact_store, i); + gint j; + + for (j = 0; j < source->contacts->len; j++) { + EContact *contact = g_ptr_array_index (source->contacts, j); + const gchar *uid = e_contact_get_const (contact, E_CONTACT_UID); + + if (!e_book_sexp_match_contact(sexp, contact)) { + g_object_unref (contact); + g_ptr_array_remove_index (source->contacts, j); + row_deleted (contact_store, offset + j); + j--; /* Stay in place */ + } + + } + + } + + g_object_unref (sexp); + + return; } Index: libedataserverui/e-name-selector-entry.c =================================================================== RCS file: /cvs/gnome/evolution-data-server/libedataserverui/e-name-selector-entry.c,v retrieving revision 1.42 diff -u -p -r1.42 e-name-selector-entry.c --- e-name-selector-entry.c 27 Nov 2006 19:54:24 -0000 1.42 +++ libedataserverui/e-name-selector-entry.c 11 Dec 2006 06:42:04 -0000 @@ -40,6 +40,7 @@ #include <libedataserverui/e-data-server-ui-marshal.h> #include "e-name-selector-entry.h" +#include "e-book-sexp.h" enum { UPDATED, @@ -55,6 +56,8 @@ typedef struct _ENameSelectorEntryPrivat struct _ENameSelectorEntryPrivate { gboolean is_completing; + char *cue_str; + EBookSExp *sexp; }; #define E_NAME_SELECTOR_ENTRY_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), E_TYPE_NAME_SELECTOR_ENTRY, ENameSelectorEntryPrivate)) @@ -463,14 +466,17 @@ escape_sexp_string (const gchar *string) } static void -set_completion_query (ENameSelectorEntry *name_selector_entry, const gchar *cue_str) +set_completion_query (ENameSelectorEntry *name_selector_entry, const gchar *cue_str, gboolean extended) { EBookQuery *book_query; gchar *query_str; gchar *encoded_cue_str; gchar *full_name_query_str; gchar *file_as_query_str; + ENameSelectorEntryPrivate *priv; + priv = E_NAME_SELECTOR_ENTRY_GET_PRIVATE (name_selector_entry); + if (!name_selector_entry->contact_store) return; @@ -499,9 +505,15 @@ set_completion_query (ENameSelectorEntry ENS_DEBUG (g_print ("%s\n", query_str)); - book_query = e_book_query_from_string (query_str); - e_contact_store_set_query (name_selector_entry->contact_store, book_query); - e_book_query_unref (book_query); + + if (extended) { + e_contact_store_set_sexp (name_selector_entry->contact_store, query_str); + e_contact_store_rebuild_with_sexp (name_selector_entry->contact_store); + } else { + book_query = e_book_query_from_string (query_str); + e_contact_store_set_query (name_selector_entry->contact_store, book_query); + e_book_query_unref (book_query); + } g_free (query_str); } @@ -834,6 +846,11 @@ clear_completion_model (ENameSelectorEnt priv = E_NAME_SELECTOR_ENTRY_GET_PRIVATE (name_selector_entry); + if (priv->cue_str) { + g_free (priv->cue_str); + priv->cue_str = NULL; + } + if (!name_selector_entry->contact_store) return; @@ -848,6 +865,9 @@ update_completion_model (ENameSelectorEn gint cursor_pos; gint range_start = 0; gint range_end = 0; + ENameSelectorEntryPrivate *priv; + + priv = E_NAME_SELECTOR_ENTRY_GET_PRIVATE (name_selector_entry); text = gtk_entry_get_text (GTK_ENTRY (name_selector_entry)); cursor_pos = gtk_editable_get_position (GTK_EDITABLE (name_selector_entry)); @@ -857,9 +877,29 @@ update_completion_model (ENameSelectorEn if (range_end - range_start >= COMPLETION_CUE_MIN_LEN && cursor_pos == range_end) { gchar *cue_str; - + gboolean extended=FALSE; + cue_str = get_entry_substring (name_selector_entry, range_start, range_end); - set_completion_query (name_selector_entry, cue_str); + if (!priv->cue_str) { + /* We are starting off a new query */ + priv->cue_str = g_strdup(cue_str); + } else { + int olen = strlen (priv->cue_str); + int nlen = strlen (cue_str); + + if (olen < nlen && g_ascii_strncasecmp(cue_str, priv->cue_str, olen) == 0) { + /* It is an extended search. So let us filter our results instead of querying more*/ + extended = TRUE; + } else { + /* No more extended. Some backspace played a role to change it. Let us build another cache */ + e_contact_store_set_sexp (name_selector_entry->contact_store, NULL); + } + g_free (priv->cue_str); + priv->cue_str = g_strdup (cue_str); + + } + + set_completion_query (name_selector_entry, cue_str, extended); g_free (cue_str); } else { /* N/A; Clear completion model */ @@ -2266,6 +2306,7 @@ e_name_selector_entry_init (ENameSelecto name_selector_entry->destination_store = e_destination_store_new (); setup_destination_store (name_selector_entry); priv->is_completing = FALSE; + priv->cue_str = NULL; } /** --- /dev/null 2006-06-16 18:37:58.000000000 +0530 +++ libedataserverui/e-book-sexp.h 2006-12-07 13:12:49.000000000 +0530 @@ -0,0 +1,62 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * e-book-sexp.h + * Copyright 2000, 2001, Ximian, Inc. + * + * Authors: + * Chris Lahey <clahey@ximian.com> + * + * 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. + */ + +#ifndef __E_BOOK_SEXP_H__ +#define __E_BOOK_SEXP_H__ + +#include <glib.h> +#include <glib-object.h> +#include <libebook/e-contact.h> + +G_BEGIN_DECLS + +#define E_TYPE_BOOK_SEXP (e_book_sexp_get_type ()) +#define E_BOOK_SEXP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_BOOK_SEXP, EBookSExp)) +#define E_BOOK_SEXP_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_BOOK_TYPE, EBookSExpClass)) +#define E_IS_BOOK_SEXP(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_BOOK_SEXP)) +#define E_IS_BOOK_SEXP_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_BOOK_SEXP)) +#define E_BOOK_SEXP_GET_CLASS(k) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_BOOK_SEXP, EBookSExpClass)) + +typedef struct _EBookSExpPrivate EBookSExpPrivate; + +typedef struct _EBookSExp EBookSExp; +typedef struct _EBookSExpClass EBookSExpClass; + +struct _EBookSExp { + GObject parent_object; + EBookSExpPrivate *priv; +}; + +struct _EBookSExpClass { + GObjectClass parent_class; +}; + +EBookSExp *e_book_sexp_new (const char *text); +GType e_book_sexp_get_type (void); + +gboolean e_book_sexp_match_vcard (EBookSExp *sexp, const char *vcard); +gboolean e_book_sexp_match_contact (EBookSExp *sexp, EContact *contact); + +G_END_DECLS + +#endif /* __E_BOOK_SEXP_H__ */ --- /dev/null 2006-11-25 17:47:37.000000000 +0530 +++ libedataserverui/e-book-sexp.c 2006-12-20 11:25:36.000000000 +0530 @@ -0,0 +1,653 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * e-book-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 <libedataserver/e-sexp.h> +#include <libedataserver/e-data-server-util.h> +#include "e-book-sexp.h" + +static GObjectClass *parent_class; + +typedef struct _SearchContext SearchContext; + +struct _EBookSExpPrivate { + ESExp *search_sexp; + SearchContext *search_context; +}; + +struct _SearchContext { + EContact *contact; +}; + +static gboolean +compare_im (EContact *contact, const char *str, + char *(*compare)(const char*, const char*), + EContactField im_field) +{ + GList *aims, *l; + gboolean found_it = FALSE; + + aims = e_contact_get (contact, im_field); + + for (l = aims; l != NULL; l = l->next) { + char *im = (char *) l->data; + + if (im && compare (im, str)) { + found_it = TRUE; + break; + } + } + + g_list_foreach (aims, (GFunc)g_free, NULL); + g_list_free (aims); + + return found_it; +} + +static gboolean +compare_im_aim (EContact *contact, const char *str, + char *(*compare)(const char*, const char*)) +{ + return compare_im (contact, str, compare, E_CONTACT_IM_AIM); +} + +static gboolean +compare_im_msn (EContact *contact, const char *str, + char *(*compare)(const char*, const char*)) +{ + return compare_im (contact, str, compare, E_CONTACT_IM_MSN); +} + +static gboolean +compare_im_icq (EContact *contact, const char *str, + char *(*compare)(const char*, const char*)) +{ + return compare_im (contact, str, compare, E_CONTACT_IM_ICQ); +} + +static gboolean +compare_im_yahoo (EContact *contact, const char *str, + char *(*compare)(const char*, const char*)) +{ + return compare_im (contact, str, compare, E_CONTACT_IM_YAHOO); +} + +static gboolean +compare_im_jabber (EContact *contact, const char *str, + char *(*compare)(const char*, const char*)) +{ + return compare_im (contact, str, compare, E_CONTACT_IM_JABBER); +} + +static gboolean +compare_im_groupwise (EContact *contact, const char *str, + char *(*compare)(const char*, const char*)) +{ + return compare_im (contact, str, compare, E_CONTACT_IM_GROUPWISE); +} + +static gboolean +compare_email (EContact *contact, const char *str, + char *(*compare)(const char*, const char*)) +{ + int i; + + for (i = E_CONTACT_EMAIL_1; i <= E_CONTACT_EMAIL_4; i ++) { + const char *email = e_contact_get_const (contact, i); + + if (email && compare(email, str)) + return TRUE; + } + + return FALSE; +} + +static gboolean +compare_phone (EContact *contact, const char *str, + char *(*compare)(const char*, const char*)) +{ + int i; + gboolean rv = FALSE; + + for (i = E_CONTACT_FIRST_PHONE_ID; i <= E_CONTACT_LAST_PHONE_ID; i ++) { + char *phone = e_contact_get (contact, i); + + rv = phone && compare(phone, str); + g_free (phone); + + if (rv) + break; + } + + return rv; +} + +static gboolean +compare_name (EContact *contact, const char *str, + char *(*compare)(const char*, const char*)) +{ + const char *name; + + name = e_contact_get_const (contact, E_CONTACT_FULL_NAME); + if (name && compare (name, str)) + return TRUE; + + name = e_contact_get_const (contact, E_CONTACT_FAMILY_NAME); + if (name && compare (name, str)) + return TRUE; + + name = e_contact_get_const (contact, E_CONTACT_GIVEN_NAME); + if (name && compare (name, str)) + return TRUE; + + name = e_contact_get_const (contact, E_CONTACT_NICKNAME); + if (name && compare (name, str)) + return TRUE; + + return FALSE; +} + +static gboolean +compare_address (EContact *contact, const char *str, + char *(*compare)(const char*, const char*)) +{ + + int i; + gboolean rv = FALSE; + + for (i = E_CONTACT_FIRST_ADDRESS_ID; i <= E_CONTACT_LAST_ADDRESS_ID; i ++) { + EContactAddress *address = e_contact_get (contact, i); + if (address) { + rv = (address->po && compare(address->po, str)) || + (address->street && compare(address->street, str)) || + (address->ext && compare(address->ext, str)) || + (address->locality && compare(address->locality, str)) || + (address->region && compare(address->region, str)) || + (address->code && compare(address->code, str)) || + (address->country && compare(address->country, str)); + + e_contact_address_free (address); + + if (rv) + break; + } + } + + return rv; + +} + +static gboolean +compare_category (EContact *contact, const char *str, + char *(*compare)(const char*, const char*)) +{ + GList *categories; + GList *iterator; + gboolean ret_val = FALSE; + + categories = e_contact_get (contact, E_CONTACT_CATEGORY_LIST); + + for (iterator = categories; iterator; iterator = iterator->next) { + const char *category = iterator->data; + + if (compare(category, str)) { + ret_val = TRUE; + break; + } + } + + g_list_foreach (categories, (GFunc)g_free, NULL); + g_list_free (categories); + + return ret_val; +} + +static struct prop_info { + EContactField field_id; + const char *query_prop; +#define PROP_TYPE_NORMAL 0x01 +#define PROP_TYPE_LIST 0x02 + int prop_type; + gboolean (*list_compare)(EContact *contact, const char *str, + char *(*compare)(const char*, const char*)); + +} prop_info_table[] = { +#define NORMAL_PROP(f,q) {f, q, PROP_TYPE_NORMAL, NULL} +#define LIST_PROP(q,c) {0, q, PROP_TYPE_LIST, c} + + /* query prop, type, list compare function */ + NORMAL_PROP ( E_CONTACT_FILE_AS, "file_as" ), + NORMAL_PROP ( E_CONTACT_UID, "id" ), + LIST_PROP ( "full_name", compare_name), /* not really a list, but we need to compare both full and surname */ + NORMAL_PROP ( E_CONTACT_HOMEPAGE_URL, "url"), + NORMAL_PROP ( E_CONTACT_BLOG_URL, "blog_url"), + NORMAL_PROP ( E_CONTACT_CALENDAR_URI, "calurl"), + NORMAL_PROP ( E_CONTACT_FREEBUSY_URL, "fburl"), + NORMAL_PROP ( E_CONTACT_ICS_CALENDAR, "icscalendar"), + NORMAL_PROP ( E_CONTACT_VIDEO_URL, "video_url"), + + NORMAL_PROP ( E_CONTACT_MAILER, "mailer"), + NORMAL_PROP ( E_CONTACT_ORG, "org"), + NORMAL_PROP ( E_CONTACT_ORG_UNIT, "org_unit"), + NORMAL_PROP ( E_CONTACT_OFFICE, "office"), + NORMAL_PROP ( E_CONTACT_TITLE, "title"), + NORMAL_PROP ( E_CONTACT_ROLE, "role"), + NORMAL_PROP ( E_CONTACT_MANAGER, "manager"), + NORMAL_PROP ( E_CONTACT_ASSISTANT, "assistant"), + NORMAL_PROP ( E_CONTACT_NICKNAME, "nickname"), + NORMAL_PROP ( E_CONTACT_SPOUSE, "spouse" ), + NORMAL_PROP ( E_CONTACT_NOTE, "note"), + LIST_PROP ( "im_aim", compare_im_aim ), + LIST_PROP ( "im_msn", compare_im_msn ), + LIST_PROP ( "im_icq", compare_im_icq ), + LIST_PROP ( "im_jabber", compare_im_jabber ), + LIST_PROP ( "im_yahoo", compare_im_yahoo ), + LIST_PROP ( "im_groupwise", compare_im_groupwise ), + LIST_PROP ( "email", compare_email ), + LIST_PROP ( "phone", compare_phone ), + LIST_PROP ( "address", compare_address ), + LIST_PROP ( "category_list", compare_category ), +}; +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 (any_field && info->field_id == E_CONTACT_UID) { + /* We need to skip UID from any field contains search + * any-field search should be supported for the + * visible fields only. + */ + truth = FALSE; + } + else if (info->prop_type == PROP_TYPE_NORMAL) { + const char *prop = NULL; + /* straight string property matches */ + + prop = e_contact_get_const (ctx->contact, info->field_id); + + if (prop && compare(prop, argv[1]->value.string)) { + truth = TRUE; + } + if ((!prop) && compare("", argv[1]->value.string)) { + truth = TRUE; + } + } + else if (info->prop_type == PROP_TYPE_LIST) { + /* the special searches that match any of the list elements */ + truth = info->list_compare (ctx->contact, argv[1]->value.string, compare); + } + + /* 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; +} + +static ESExpResult * +func_contains(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) +{ + SearchContext *ctx = data; + + return entry_compare (ctx, f, argc, argv, (char *(*)(const char*, const char*)) e_util_utf8_strstrcase); +} + +static char * +is_helper (const char *s1, const char *s2) +{ + if (!e_util_utf8_strcasecmp (s1, s2)) + return (char*)s1; + else + return NULL; +} + +static ESExpResult * +func_is(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) +{ + SearchContext *ctx = data; + + return entry_compare (ctx, f, argc, argv, is_helper); +} + +static char * +endswith_helper (const char *s1, const char *s2) +{ + char *p; + if ((p = (char*) e_util_utf8_strstrcase(s1, s2)) + && (strlen(p) == strlen(s2))) + return p; + else + return NULL; +} + +static ESExpResult * +func_endswith(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) +{ + SearchContext *ctx = data; + + return entry_compare (ctx, f, argc, argv, endswith_helper); +} + +static char * +beginswith_helper (const char *s1, const char *s2) +{ + char *p; + if ((p = (char*) e_util_utf8_strstrcase(s1, s2)) + && (p == s1)) + return p; + else + return NULL; +} + +static ESExpResult * +func_beginswith(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) +{ + SearchContext *ctx = data; + + return entry_compare (ctx, f, argc, argv, beginswith_helper); +} + +static ESExpResult * +func_exists(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) +{ + SearchContext *ctx = data; + ESExpResult *r; + int truth = FALSE; + + if (argc == 1 + && argv[0]->type == ESEXP_RES_STRING) { + char *propname; + struct prop_info *info = NULL; + int i; + + propname = argv[0]->value.string; + + for (i = 0; i < num_prop_infos; i ++) { + if (!strcmp (prop_info_table[i].query_prop, propname)) { + info = &prop_info_table[i]; + + if (info->prop_type == PROP_TYPE_NORMAL) { + const char *prop = NULL; + /* searches where the query's property + maps directly to an ecard property */ + + prop = e_contact_get_const (ctx->contact, info->field_id); + + if (prop && *prop) + truth = TRUE; + } + else if (info->prop_type == PROP_TYPE_LIST) { + /* the special searches that match any of the list elements */ + truth = info->list_compare (ctx->contact, "", (char *(*)(const char*, const char*)) e_util_utf8_strstrcase); + } + + break; + } + } + + } + r = e_sexp_result_new(f, ESEXP_RES_BOOL); + r->value.bool = truth; + + return r; +} + +static ESExpResult * +func_exists_vcard(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) +{ + SearchContext *ctx = data; + ESExpResult *r; + int truth = FALSE; + + if (argc == 1 && argv[0]->type == ESEXP_RES_STRING) { + const char *attr_name; + EVCardAttribute *attr; + GList *values; + char *s; + + attr_name = argv[0]->value.string; + attr = e_vcard_get_attribute (E_VCARD (ctx->contact), attr_name); + if (attr) { + values = e_vcard_attribute_get_values (attr); + if (g_list_length (values) > 0) { + s = values->data; + if (s[0] != '\0') { + truth = TRUE; + } + } + } + } + + r = e_sexp_result_new(f, ESEXP_RES_BOOL); + r->value.bool = truth; + + return r; +} + +/* '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[] = { + { "contains", func_contains, 0 }, + { "is", func_is, 0 }, + { "beginswith", func_beginswith, 0 }, + { "endswith", func_endswith, 0 }, + { "exists", func_exists, 0 }, + { "exists_vcard", func_exists_vcard, 0 }, +}; + +/** + * e_book_sexp_match_contact: + * @sexp: an #EBookSExp + * @contact: an #EContact + * + * Checks if @contact matches @sexp. + * + * Return value: %TRUE if the contact matches, %FALSE otherwise. + **/ +gboolean +e_book_sexp_match_contact (EBookSExp *sexp, EContact *contact) +{ + ESExpResult *r; + gboolean retval; + + if (!contact) { + g_warning ("null EContact passed to e_book_sexp_match_contact"); + return FALSE; + } + + sexp->priv->search_context->contact = g_object_ref (contact); + + 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->contact); + + e_sexp_result_free(sexp->priv->search_sexp, r); + + return retval; +} + +/** + * e_book_sexp_match_vcard: + * @sexp: an #EBookSExp + * @vcard: a VCard string + * + * Checks if @vcard matches @sexp. + * + * Return value: %TRUE if the VCard matches, %FALSE otherwise. + **/ +gboolean +e_book_sexp_match_vcard (EBookSExp *sexp, const char *vcard) +{ + EContact *contact; + gboolean retval; + + contact = e_contact_new_from_vcard (vcard); + + retval = e_book_sexp_match_contact (sexp, contact); + + g_object_unref(contact); + + return retval; +} + + + +/** + * e_book_sexp_new: + * @text: an s-expression to parse + * + * Creates a new #EBookSExp from @text. + * + * Return value: A new #EBookSExp. + **/ +EBookSExp * +e_book_sexp_new (const char *text) +{ + EBookSExp *sexp = g_object_new (E_TYPE_BOOK_SEXP, NULL); + int esexp_error; + int i; + + sexp->priv->search_sexp = e_sexp_new(); + + 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; +} + +static void +e_book_sexp_dispose (GObject *object) +{ + EBookSExp *sexp = E_BOOK_SEXP (object); + + if (sexp->priv) { + e_sexp_unref(sexp->priv->search_sexp); + + 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 +e_book_sexp_class_init (EBookSExpClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + /* Set the virtual methods. */ + + object_class->dispose = e_book_sexp_dispose; +} + +static void +e_book_sexp_init (EBookSExp *sexp) +{ + EBookSExpPrivate *priv; + + priv = g_new0 (EBookSExpPrivate, 1); + + sexp->priv = priv; + priv->search_context = g_new (SearchContext, 1); +} + +/** + * e_book_sexp_get_type: + */ +GType +e_book_sexp_get_type (void) +{ + static GType type = 0; + + if (! type) { + GTypeInfo info = { + sizeof (EBookSExpClass), + NULL, /* base_class_init */ + NULL, /* base_class_finalize */ + (GClassInitFunc) e_book_sexp_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (EBookSExp), + 0, /* n_preallocs */ + (GInstanceInitFunc) e_book_sexp_init + }; + + type = g_type_register_static (G_TYPE_OBJECT, "EBookSExp", &info, 0); + } + + return type; +}
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor