1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
4 * (GLABELS) Label and Business Card Creation program for GNOME
6 * merge_evolution.c: evolution merge backend module
8 * Copyright (C) 2001 Jim Evins <evins@snaught.com>.
10 * Copyright (C) 2005 Austin Henry <ahenry@users.sourceforge.net>
12 * Copyright (C) 2007 Peter Cherriman <glabels-devel2712@bubieyehyeh.me.uk>
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 #include "merge-evolution.h"
36 #include <libebook/e-book.h>
37 #include <glib/gi18n.h>
40 #include <libglabels/str.h>
44 #define DEFAULT_QUERY "(exists \"full_name\")"
46 /*===========================================*/
48 /*===========================================*/
50 struct _glMergeEvolutionPrivate {
54 GList *fields; /* the fields supported by the addressbook */
66 /*===========================================*/
68 /*===========================================*/
70 /*===========================================*/
71 /* Local function prototypes */
72 /*===========================================*/
74 static void gl_merge_evolution_finalize (GObject *object);
76 static void gl_merge_evolution_set_property (GObject *object,
81 static void gl_merge_evolution_get_property (GObject *object,
86 static GList *gl_merge_evolution_get_key_list (glMerge *merge);
87 static gchar *gl_merge_evolution_get_primary_key (glMerge *merge);
88 static void gl_merge_evolution_open (glMerge *merge);
89 static void gl_merge_evolution_close (glMerge *merge);
90 static glMergeRecord *gl_merge_evolution_get_record (glMerge *merge);
91 static void gl_merge_evolution_copy (glMerge *dst_merge,
94 /* utility function prototypes go here */
95 static void free_field_list (GList *fields);
98 /*****************************************************************************/
99 /* Boilerplate object stuff. */
100 /*****************************************************************************/
101 G_DEFINE_TYPE (glMergeEvolution, gl_merge_evolution, GL_TYPE_MERGE);
104 gl_merge_evolution_class_init (glMergeEvolutionClass *class)
106 GObjectClass *object_class = G_OBJECT_CLASS (class);
107 glMergeClass *merge_class = GL_MERGE_CLASS (class);
109 gl_debug (DEBUG_MERGE, "START");
111 gl_merge_evolution_parent_class = g_type_class_peek_parent (class);
113 object_class->set_property = gl_merge_evolution_set_property;
114 object_class->get_property = gl_merge_evolution_get_property;
116 g_object_class_install_property
119 g_param_spec_string ("query", NULL,
120 "Query used to select records from the addressbook",
121 "(exists \"full_name\")",
122 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
124 object_class->finalize = gl_merge_evolution_finalize;
126 merge_class->get_key_list = gl_merge_evolution_get_key_list;
127 merge_class->get_primary_key = gl_merge_evolution_get_primary_key;
128 merge_class->open = gl_merge_evolution_open;
129 merge_class->close = gl_merge_evolution_close;
130 merge_class->get_record = gl_merge_evolution_get_record;
131 merge_class->copy = gl_merge_evolution_copy;
133 gl_debug (DEBUG_MERGE, "END");
137 gl_merge_evolution_init (glMergeEvolution *merge_evolution)
139 gl_debug (DEBUG_MERGE, "START");
141 merge_evolution->priv = g_new0 (glMergeEvolutionPrivate, 1);
142 merge_evolution->priv->query = g_strdup(DEFAULT_QUERY);
144 gl_debug (DEBUG_MERGE, "END");
148 gl_merge_evolution_finalize (GObject *object)
150 glMergeEvolution *merge_evolution = GL_MERGE_EVOLUTION (object);
152 gl_debug (DEBUG_MERGE, "START");
154 g_return_if_fail (object && GL_IS_MERGE_EVOLUTION (object));
156 free_field_list(merge_evolution->priv->fields);
157 g_free (merge_evolution->priv->query);
158 g_free (merge_evolution->priv);
160 G_OBJECT_CLASS (gl_merge_evolution_parent_class)->finalize (object);
162 gl_debug (DEBUG_MERGE, "END");
165 /*--------------------------------------------------------------------------*/
167 /*--------------------------------------------------------------------------*/
169 gl_merge_evolution_set_property (GObject *object,
174 glMergeEvolution *merge_evolution;
176 merge_evolution = GL_MERGE_EVOLUTION (object);
181 g_free (merge_evolution->priv->query);
182 merge_evolution->priv->query = g_value_dup_string (value);
183 gl_debug (DEBUG_MERGE, "ARG \"query\" = \"%s\"",
184 merge_evolution->priv->query);
188 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
195 /*--------------------------------------------------------------------------*/
197 /*--------------------------------------------------------------------------*/
199 gl_merge_evolution_get_property (GObject *object,
204 glMergeEvolution *merge_evolution;
206 merge_evolution = GL_MERGE_EVOLUTION (object);
211 g_value_set_string (value, merge_evolution->priv->query);
215 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
222 /*--------------------------------------------------------------------------*/
224 /*--------------------------------------------------------------------------*/
226 gl_merge_evolution_get_key_list (glMerge *merge)
228 glMergeEvolution *merge_evolution;
229 GList *key_list = NULL;
232 gl_debug (DEBUG_MERGE, "BEGIN");
234 merge_evolution = GL_MERGE_EVOLUTION (merge);
236 /* for the previously retrieved supported fileds, go through them and find
237 * their pretty names */
238 for (iter = merge_evolution->priv->fields;
240 iter = g_list_next(iter))
242 key_list = g_list_prepend (key_list,
243 g_strdup (e_contact_pretty_name (*(EContactField *)iter->data)));
246 key_list = g_list_reverse (key_list);
248 gl_debug (DEBUG_MERGE, "END");
253 /*--------------------------------------------------------------------------*/
254 /* Get "primary" key. */
255 /*--------------------------------------------------------------------------*/
257 gl_merge_evolution_get_primary_key (glMerge *merge)
259 return g_strdup (e_contact_pretty_name(E_CONTACT_FILE_AS));
262 /* Sort compare function for sorting contacts by file-as element
263 * by Peter Cherriman (PJC)
264 * called by GList* g_list_sort(GList *list, sort_contact_by_file_as);
266 static gint sort_contact_by_file_as(gconstpointer *a, gconstpointer *b)
269 * Returns : negative value if a < b; zero if a = b; positive value if a > b
272 // Check and cast a and b to EContact
273 EContact *contact_a = E_CONTACT(a);
274 EContact *contact_b = E_CONTACT(b);
276 // Extract file_as for each contact and compare...
277 gchar *a_file_as = e_contact_get (contact_a, E_CONTACT_FILE_AS);
278 gchar *b_file_as = e_contact_get (contact_b, E_CONTACT_FILE_AS);
279 gint res = lgl_str_utf8_casecmp(a_file_as, b_file_as);
281 gl_debug(DEBUG_MERGE, "Sort comparing contacts '%s' and '%s' = %d", a_file_as, b_file_as, res);
283 // free file_as strings created earlier....
290 /*--------------------------------------------------------------------------*/
291 /* Open merge source. */
292 /*--------------------------------------------------------------------------*/
294 gl_merge_evolution_open (glMerge *merge)
296 glMergeEvolution *merge_evolution;
299 GList *fields, *iter;
300 EContactField *field_id;
301 GError *error = NULL;
303 gl_debug (DEBUG_MERGE, "BEGIN");
305 merge_evolution = GL_MERGE_EVOLUTION (merge);
307 query = e_book_query_from_string(merge_evolution->priv->query);
309 g_warning (_("Couldn't construct query"));
313 merge_evolution->priv->book = e_book_new_system_addressbook(&error);
314 if (!merge_evolution->priv->book) {
315 g_warning (_("Couldn't open addressbook."));
318 g_warning ("e_book_new_system_addressbook: %s", error->message);
319 g_error_free (error);
321 e_book_query_unref(query);
325 if (!e_book_open(merge_evolution->priv->book, FALSE, &error)) {
326 g_warning (_("Couldn't open addressbook."));
329 g_warning ("e_book_open: %s", error->message);
330 g_error_free (error);
332 e_book_query_unref(query);
333 g_object_unref(merge_evolution->priv->book);
334 merge_evolution->priv->book = NULL;
338 /* fetch the list of fields supported by this address book */
339 status = e_book_get_supported_fields(merge_evolution->priv->book, &fields, &error);
340 if (status == FALSE) {
341 g_warning (_("Couldn't list available fields."));
344 g_warning ("e_book_get_supported_fields: %s", error->message);
345 g_error_free (error);
347 e_book_query_unref(query);
348 g_object_unref(merge_evolution->priv->book);
349 merge_evolution->priv->book = NULL;
353 /* generate a list of field_ids, and put that into private->fields */
354 for (iter = fields; iter != NULL; iter = g_list_next(iter)) {
355 field_id = g_new(EContactField, 1);
356 *field_id = e_contact_field_id(iter->data);
358 /* above this value, the data aren't strings anymore */
359 if (*field_id >= E_CONTACT_LAST_SIMPLE_STRING) {
364 merge_evolution->priv->fields =
365 g_list_prepend(merge_evolution->priv->fields, field_id);
367 free_field_list(fields); /* don't need the list of names anymore */
369 gl_debug(DEBUG_MERGE, "Field list length: %d", g_list_length(merge_evolution->priv->fields));
371 /* finally retrieve the contacts */
372 status = e_book_get_contacts (merge_evolution->priv->book,
374 &merge_evolution->priv->contacts,
376 if (status == FALSE) {
377 g_warning (_("Couldn't get contacts."));
380 g_warning ("e_book_get_contacts: %s", error->message);
381 g_error_free (error);
383 e_book_query_unref(query);
384 free_field_list(merge_evolution->priv->fields);
385 g_object_unref(merge_evolution->priv->book);
386 merge_evolution->priv->book = NULL;
391 e_book_query_unref(query);
393 /* Sort contacts using file-as element....
394 * by Peter Cherriman (PJC)
396 gl_debug (DEBUG_MERGE, "Starting sort");
397 merge_evolution->priv->contacts = g_list_sort(merge_evolution->priv->contacts, (GCompareFunc)sort_contact_by_file_as);
398 gl_debug (DEBUG_MERGE, "Ended sort");
400 gl_debug (DEBUG_MERGE, "END");
405 /*--------------------------------------------------------------------------*/
406 /* Close merge source. */
407 /*--------------------------------------------------------------------------*/
409 gl_merge_evolution_close (glMerge *merge)
411 glMergeEvolution *merge_evolution;
414 merge_evolution = GL_MERGE_EVOLUTION (merge);
416 /* unref all of the objects created in _open */
417 g_object_unref(merge_evolution->priv->book);
418 merge_evolution->priv->book = NULL;
420 for (iter = merge_evolution->priv->contacts;
422 iter = g_list_next(iter))
424 EContact *contact = E_CONTACT (iter->data);
426 g_object_unref(contact);
428 g_list_free(merge_evolution->priv->contacts);
429 merge_evolution->priv->contacts = NULL;
432 /*--------------------------------------------------------------------------*/
433 /* Get next record from merge source, NULL if no records left (i.e EOF) */
434 /*--------------------------------------------------------------------------*/
435 static glMergeRecord *
436 gl_merge_evolution_get_record (glMerge *merge)
438 glMergeEvolution *merge_evolution;
439 glMergeRecord *record;
441 EContactField field_id;
446 merge_evolution = GL_MERGE_EVOLUTION (merge);
448 head = merge_evolution->priv->contacts;
450 return NULL; /* past the last record */
452 contact = E_CONTACT(head->data);
454 record = g_new0 (glMergeRecord, 1);
455 record->select_flag = TRUE;
457 /* Take the interesting fields one by one from the contact, and put them
458 * into the glMergeRecord structure. When done, free up the resources for
461 /* iterate through the supported fields, and add them to the list */
462 for (iter = merge_evolution->priv->fields;
464 iter = g_list_next(iter))
467 field_id = *(EContactField *)iter->data;
468 value = g_strdup (e_contact_get_const (contact, field_id));
471 field = g_new0 (glMergeField, 1);
472 field->key = g_strdup (e_contact_pretty_name (field_id));
473 field->value = value;
474 record->field_list = g_list_prepend (record->field_list, field);
478 record->field_list = g_list_reverse (record->field_list);
480 /* do a destructive read */
481 g_object_unref (contact);
482 merge_evolution->priv->contacts =
483 g_list_remove_link (merge_evolution->priv->contacts, head);
484 g_list_free_1 (head);
489 /*---------------------------------------------------------------------------*/
490 /* Copy merge_evolution specific fields. */
491 /*---------------------------------------------------------------------------*/
493 gl_merge_evolution_copy (glMerge *dst_merge,
496 GList *src_iter, *dst_iter;
498 gl_debug (DEBUG_MERGE, "BEGIN");
500 glMergeEvolution *dst_merge_evolution;
501 glMergeEvolution *src_merge_evolution;
503 dst_merge_evolution = GL_MERGE_EVOLUTION (dst_merge);
504 src_merge_evolution = GL_MERGE_EVOLUTION (src_merge);
506 dst_merge_evolution->priv->query = g_strdup(src_merge_evolution->priv->query);
508 dst_merge_evolution->priv->fields = g_list_copy(src_merge_evolution->priv->fields);
509 for (src_iter = src_merge_evolution->priv->fields,
510 dst_iter = dst_merge_evolution->priv->fields;
511 src_iter != NULL && dst_iter != NULL;
512 src_iter = g_list_next(src_iter), dst_iter = g_list_next(dst_iter))
514 dst_iter->data = g_new(EContactField, 1);
515 if (src_iter->data) { /* this better not be null, but... */
516 memcpy(dst_iter->data, src_iter->data, sizeof(EContactField));
520 /* I don't know that there's a good way to do a deep copy of the various
521 * libebook structures/objects, so I'm just going to leave them out. They
522 * are all regenerated on gl_merge_evolution_open, anyway */
524 gl_debug (DEBUG_MERGE, "END");
527 /*---------------------------------------------------------------------------*/
528 /* Free the list of supported fields */
529 /*---------------------------------------------------------------------------*/
531 free_field_list (GList *fields)
535 for (iter = fields; iter != NULL; iter = g_list_next(iter))
546 #endif /* HAVE_LIBEBOOK */