3 * Copyright (C) 2001-2009 Jim Evins <evins@snaught.com>.
5 * Copyright (C) 2005 Austin Henry <ahenry@users.sourceforge.net>
7 * Copyright (C) 2007 Peter Cherriman <glabels-devel2712@bubieyehyeh.me.uk>
9 * This file is part of gLabels.
11 * gLabels is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
16 * gLabels is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with gLabels. If not, see <http://www.gnu.org/licenses/>.
30 #include "merge-evolution.h"
32 #include <libebook/e-book.h>
33 #include <glib/gi18n.h>
37 #include <libglabels.h>
41 #define DEFAULT_QUERY "(exists \"full_name\")"
44 /*===========================================*/
46 /*===========================================*/
48 struct _glMergeEvolutionPrivate {
52 GList *fields; /* the fields supported by the addressbook */
65 /*===========================================*/
67 /*===========================================*/
69 /*===========================================*/
70 /* Local function prototypes */
71 /*===========================================*/
73 static void gl_merge_evolution_finalize (GObject *object);
75 static void gl_merge_evolution_set_property (GObject *object,
80 static void gl_merge_evolution_get_property (GObject *object,
85 static GList *gl_merge_evolution_get_key_list (const glMerge *merge);
86 static gchar *gl_merge_evolution_get_primary_key (const glMerge *merge);
87 static void gl_merge_evolution_open (glMerge *merge);
88 static void gl_merge_evolution_close (glMerge *merge);
89 static glMergeRecord *gl_merge_evolution_get_record (glMerge *merge);
90 static void gl_merge_evolution_copy (glMerge *dst_merge,
91 const glMerge *src_merge);
93 /* utility function prototypes go here */
94 static void free_field_list (GList *fields);
97 /*****************************************************************************/
98 /* Boilerplate object stuff. */
99 /*****************************************************************************/
100 G_DEFINE_TYPE (glMergeEvolution, gl_merge_evolution, GL_TYPE_MERGE)
103 gl_merge_evolution_class_init (glMergeEvolutionClass *class)
105 GObjectClass *object_class = G_OBJECT_CLASS (class);
106 glMergeClass *merge_class = GL_MERGE_CLASS (class);
108 gl_debug (DEBUG_MERGE, "START");
110 gl_merge_evolution_parent_class = g_type_class_peek_parent (class);
112 object_class->set_property = gl_merge_evolution_set_property;
113 object_class->get_property = gl_merge_evolution_get_property;
115 g_object_class_install_property
118 g_param_spec_string ("query", NULL,
119 "Query used to select records from the addressbook",
120 "(exists \"full_name\")",
121 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
123 object_class->finalize = gl_merge_evolution_finalize;
125 merge_class->get_key_list = gl_merge_evolution_get_key_list;
126 merge_class->get_primary_key = gl_merge_evolution_get_primary_key;
127 merge_class->open = gl_merge_evolution_open;
128 merge_class->close = gl_merge_evolution_close;
129 merge_class->get_record = gl_merge_evolution_get_record;
130 merge_class->copy = gl_merge_evolution_copy;
132 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");
149 gl_merge_evolution_finalize (GObject *object)
151 glMergeEvolution *merge_evolution = GL_MERGE_EVOLUTION (object);
153 gl_debug (DEBUG_MERGE, "START");
155 g_return_if_fail (object && GL_IS_MERGE_EVOLUTION (object));
157 free_field_list(merge_evolution->priv->fields);
158 g_free (merge_evolution->priv->query);
159 g_free (merge_evolution->priv);
161 G_OBJECT_CLASS (gl_merge_evolution_parent_class)->finalize (object);
163 gl_debug (DEBUG_MERGE, "END");
167 /*--------------------------------------------------------------------------*/
169 /*--------------------------------------------------------------------------*/
171 gl_merge_evolution_set_property (GObject *object,
176 glMergeEvolution *merge_evolution;
178 merge_evolution = GL_MERGE_EVOLUTION (object);
183 g_free (merge_evolution->priv->query);
184 merge_evolution->priv->query = g_value_dup_string (value);
185 gl_debug (DEBUG_MERGE, "ARG \"query\" = \"%s\"",
186 merge_evolution->priv->query);
190 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
198 /*--------------------------------------------------------------------------*/
200 /*--------------------------------------------------------------------------*/
202 gl_merge_evolution_get_property (GObject *object,
207 glMergeEvolution *merge_evolution;
209 merge_evolution = GL_MERGE_EVOLUTION (object);
214 g_value_set_string (value, merge_evolution->priv->query);
218 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
226 /*--------------------------------------------------------------------------*/
228 /*--------------------------------------------------------------------------*/
230 gl_merge_evolution_get_key_list (const glMerge *merge)
232 glMergeEvolution *merge_evolution;
233 GList *key_list = NULL;
236 gl_debug (DEBUG_MERGE, "BEGIN");
238 merge_evolution = GL_MERGE_EVOLUTION (merge);
240 /* for the previously retrieved supported fileds, go through them and find
241 * their pretty names */
242 for (iter = merge_evolution->priv->fields;
244 iter = g_list_next(iter))
246 key_list = g_list_prepend (key_list,
247 g_strdup (e_contact_pretty_name (*(EContactField *)iter->data)));
250 key_list = g_list_reverse (key_list);
252 gl_debug (DEBUG_MERGE, "END");
258 /*--------------------------------------------------------------------------*/
259 /* Get "primary" key. */
260 /*--------------------------------------------------------------------------*/
262 gl_merge_evolution_get_primary_key (const glMerge *merge)
264 return g_strdup (e_contact_pretty_name(E_CONTACT_FILE_AS));
268 /* Sort compare function for sorting contacts by file-as element
269 * by Peter Cherriman (PJC)
270 * called by GList* g_list_sort(GList *list, sort_contact_by_file_as);
272 static gint sort_contact_by_file_as(gconstpointer *a, gconstpointer *b)
275 * Returns : negative value if a < b; zero if a = b; positive value if a > b
278 /* Check and cast a and b to EContact */
279 EContact *contact_a = E_CONTACT(a);
280 EContact *contact_b = E_CONTACT(b);
282 /* Extract file_as for each contact and compare... */
283 gchar *a_file_as = e_contact_get (contact_a, E_CONTACT_FILE_AS);
284 gchar *b_file_as = e_contact_get (contact_b, E_CONTACT_FILE_AS);
285 gint res = lgl_str_utf8_casecmp(a_file_as, b_file_as);
287 gl_debug(DEBUG_MERGE, "Sort comparing contacts '%s' and '%s' = %d", a_file_as, b_file_as, res);
289 /* free file_as strings created earlier.... */
297 /*--------------------------------------------------------------------------*/
298 /* Open merge source. */
299 /*--------------------------------------------------------------------------*/
301 gl_merge_evolution_open (glMerge *merge)
303 glMergeEvolution *merge_evolution;
306 GList *fields, *iter;
307 EContactField *field_id;
308 GError *error = NULL;
310 gl_debug (DEBUG_MERGE, "BEGIN");
312 merge_evolution = GL_MERGE_EVOLUTION (merge);
314 query = e_book_query_from_string(merge_evolution->priv->query);
316 g_warning ("Couldn't construct query");
320 merge_evolution->priv->book = e_book_new_system_addressbook(&error);
321 if (!merge_evolution->priv->book) {
322 g_warning ("Couldn't open addressbook.");
325 g_warning ("e_book_new_system_addressbook: %s", error->message);
326 g_error_free (error);
328 e_book_query_unref(query);
332 if (!e_book_open(merge_evolution->priv->book, FALSE, &error)) {
333 g_warning ("Couldn't open addressbook.");
336 g_warning ("e_book_open: %s", error->message);
337 g_error_free (error);
339 e_book_query_unref(query);
340 g_object_unref(merge_evolution->priv->book);
341 merge_evolution->priv->book = NULL;
345 /* fetch the list of fields supported by this address book */
346 status = e_book_get_supported_fields(merge_evolution->priv->book, &fields, &error);
347 if (status == FALSE) {
348 g_warning ("Couldn't list available fields.");
351 g_warning ("e_book_get_supported_fields: %s", error->message);
352 g_error_free (error);
354 e_book_query_unref(query);
355 g_object_unref(merge_evolution->priv->book);
356 merge_evolution->priv->book = NULL;
360 /* generate a list of field_ids, and put that into private->fields */
361 for (iter = fields; iter != NULL; iter = g_list_next(iter)) {
362 field_id = g_new(EContactField, 1);
363 *field_id = e_contact_field_id(iter->data);
365 /* above this value, the data aren't strings anymore */
366 if (*field_id > E_CONTACT_LAST_SIMPLE_STRING) {
371 merge_evolution->priv->fields =
372 g_list_prepend(merge_evolution->priv->fields, field_id);
374 free_field_list(fields); /* don't need the list of names anymore */
376 gl_debug(DEBUG_MERGE, "Field list length: %d", g_list_length(merge_evolution->priv->fields));
378 /* finally retrieve the contacts */
379 status = e_book_get_contacts (merge_evolution->priv->book,
381 &merge_evolution->priv->contacts,
383 if (status == FALSE) {
384 g_warning ("Couldn't get contacts.");
387 g_warning ("e_book_get_contacts: %s", error->message);
388 g_error_free (error);
390 e_book_query_unref(query);
391 free_field_list(merge_evolution->priv->fields);
392 g_object_unref(merge_evolution->priv->book);
393 merge_evolution->priv->book = NULL;
398 e_book_query_unref(query);
400 /* Sort contacts using file-as element....
401 * by Peter Cherriman (PJC)
403 gl_debug (DEBUG_MERGE, "Starting sort");
404 merge_evolution->priv->contacts = g_list_sort(merge_evolution->priv->contacts, (GCompareFunc)sort_contact_by_file_as);
405 gl_debug (DEBUG_MERGE, "Ended sort");
407 gl_debug (DEBUG_MERGE, "END");
413 /*--------------------------------------------------------------------------*/
414 /* Close merge source. */
415 /*--------------------------------------------------------------------------*/
417 gl_merge_evolution_close (glMerge *merge)
419 glMergeEvolution *merge_evolution;
422 merge_evolution = GL_MERGE_EVOLUTION (merge);
424 /* unref all of the objects created in _open */
425 g_object_unref(merge_evolution->priv->book);
426 merge_evolution->priv->book = NULL;
428 for (iter = merge_evolution->priv->contacts;
430 iter = g_list_next(iter))
432 EContact *contact = E_CONTACT (iter->data);
434 g_object_unref(contact);
436 g_list_free(merge_evolution->priv->contacts);
437 merge_evolution->priv->contacts = NULL;
441 /*--------------------------------------------------------------------------*/
442 /* Get next record from merge source, NULL if no records left (i.e EOF) */
443 /*--------------------------------------------------------------------------*/
444 static glMergeRecord *
445 gl_merge_evolution_get_record (glMerge *merge)
447 glMergeEvolution *merge_evolution;
448 glMergeRecord *record;
450 EContactField field_id;
455 merge_evolution = GL_MERGE_EVOLUTION (merge);
457 head = merge_evolution->priv->contacts;
459 return NULL; /* past the last record */
461 contact = E_CONTACT(head->data);
463 record = g_new0 (glMergeRecord, 1);
464 record->select_flag = TRUE;
466 /* Take the interesting fields one by one from the contact, and put them
467 * into the glMergeRecord structure. When done, free up the resources for
470 /* iterate through the supported fields, and add them to the list */
471 for (iter = merge_evolution->priv->fields;
473 iter = g_list_next(iter))
476 field_id = *(EContactField *)iter->data;
477 value = g_strdup (e_contact_get_const (contact, field_id));
480 field = g_new0 (glMergeField, 1);
481 field->key = g_strdup (e_contact_pretty_name (field_id));
482 field->value = value;
483 record->field_list = g_list_prepend (record->field_list, field);
487 record->field_list = g_list_reverse (record->field_list);
489 /* do a destructive read */
490 g_object_unref (contact);
491 merge_evolution->priv->contacts =
492 g_list_remove_link (merge_evolution->priv->contacts, head);
493 g_list_free_1 (head);
499 /*---------------------------------------------------------------------------*/
500 /* Copy merge_evolution specific fields. */
501 /*---------------------------------------------------------------------------*/
503 gl_merge_evolution_copy (glMerge *dst_merge,
504 const glMerge *src_merge)
506 GList *src_iter, *dst_iter;
508 glMergeEvolution *dst_merge_evolution;
509 glMergeEvolution *src_merge_evolution;
511 gl_debug (DEBUG_MERGE, "BEGIN");
513 dst_merge_evolution = GL_MERGE_EVOLUTION (dst_merge);
514 src_merge_evolution = GL_MERGE_EVOLUTION (src_merge);
516 dst_merge_evolution->priv->query = g_strdup(src_merge_evolution->priv->query);
518 dst_merge_evolution->priv->fields = g_list_copy(src_merge_evolution->priv->fields);
519 for (src_iter = src_merge_evolution->priv->fields,
520 dst_iter = dst_merge_evolution->priv->fields;
521 src_iter != NULL && dst_iter != NULL;
522 src_iter = g_list_next(src_iter), dst_iter = g_list_next(dst_iter))
524 dst_iter->data = g_new(EContactField, 1);
525 if (src_iter->data) { /* this better not be null, but... */
526 memcpy(dst_iter->data, src_iter->data, sizeof(EContactField));
530 /* I don't know that there's a good way to do a deep copy of the various
531 * libebook structures/objects, so I'm just going to leave them out. They
532 * are all regenerated on gl_merge_evolution_open, anyway */
534 gl_debug (DEBUG_MERGE, "END");
538 /*---------------------------------------------------------------------------*/
539 /* Free the list of supported fields */
540 /*---------------------------------------------------------------------------*/
542 free_field_list (GList *fields)
546 for (iter = fields; iter != NULL; iter = g_list_next(iter))
557 #endif /* HAVE_LIBEBOOK */
562 * Local Variables: -- emacs
564 * c-basic-offset: 8 -- emacs
565 * tab-width: 8 -- emacs
566 * indent-tabs-mode: nil -- emacs