]> git.sur5r.net Git - glabels/blob - glabels2/src/merge-evolution.c
78c66fc532b26b5f1802575292fec9e0d381d783
[glabels] / glabels2 / src / merge-evolution.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2
3 /*
4  *  (GLABELS) Label and Business Card Creation program for GNOME
5  *
6  *  merge_evolution.c:  evolution merge backend module
7  *
8  *  Copyright (C) 2001  Jim Evins <evins@snaught.com>.
9  *  and
10  *  Copyright (C) 2005  Austin Henry <ahenry@users.sourceforge.net>
11  *
12  *  This program is free software; you can redistribute it and/or modify
13  *  it under the terms of the GNU General Public License as published by
14  *  the Free Software Foundation; either version 2 of the License, or
15  *  (at your option) any later version.
16  *
17  *  This program is distributed in the hope that it will be useful,
18  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  *  GNU General Public License for more details.
21  *
22  *  You should have received a copy of the GNU General Public License
23  *  along with this program; if not, write to the Free Software
24  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
25  */
26
27 #include <config.h>
28
29 #ifdef HAVE_LIBEBOOK
30
31
32 #include "merge-evolution.h"
33
34 #include <libebook/e-book.h>
35 #include <glib/gi18n.h>
36 #include <stdio.h>
37 #include <string.h>
38
39 #include "debug.h"
40
41 #define DEFAULT_QUERY "(exists \"full_name\")"
42
43 /*===========================================*/
44 /* Private types                             */
45 /*===========================================*/
46
47 struct _glMergeEvolutionPrivate {
48         gchar            *query;
49         EBook            *book;
50         GList            *contacts;
51         GList            *fields; /* the fields supported by the addressbook */
52 };
53
54 enum {
55         LAST_SIGNAL
56 };
57
58 enum {
59         ARG_0,
60         ARG_QUERY,
61 };
62
63 /*===========================================*/
64 /* Private globals                           */
65 /*===========================================*/
66
67 /*===========================================*/
68 /* Local function prototypes                 */
69 /*===========================================*/
70
71 static void           gl_merge_evolution_finalize        (GObject          *object);
72
73 static void           gl_merge_evolution_set_property    (GObject          *object,
74                                                           guint             param_id,
75                                                           const GValue     *value,
76                                                           GParamSpec       *pspec);
77
78 static void           gl_merge_evolution_get_property    (GObject          *object,
79                                                           guint             param_id,
80                                                           GValue           *value,
81                                                           GParamSpec       *pspec);
82
83 static GList         *gl_merge_evolution_get_key_list    (glMerge          *merge);
84 static gchar         *gl_merge_evolution_get_primary_key (glMerge          *merge);
85 static void           gl_merge_evolution_open            (glMerge          *merge);
86 static void           gl_merge_evolution_close           (glMerge          *merge);
87 static glMergeRecord *gl_merge_evolution_get_record      (glMerge          *merge);
88 static void           gl_merge_evolution_copy            (glMerge          *dst_merge,
89                                                           glMerge          *src_merge);
90
91 /* utility function prototypes go here */
92 static void           free_field_list                    (GList *fields);
93
94 \f
95 /*****************************************************************************/
96 /* Boilerplate object stuff.                                                 */
97 /*****************************************************************************/
98 G_DEFINE_TYPE (glMergeEvolution, gl_merge_evolution, GL_TYPE_MERGE);
99
100 static void
101 gl_merge_evolution_class_init (glMergeEvolutionClass *class)
102 {
103         GObjectClass *object_class = G_OBJECT_CLASS (class);
104         glMergeClass *merge_class  = GL_MERGE_CLASS (class);
105
106         gl_debug (DEBUG_MERGE, "START");
107
108         gl_merge_evolution_parent_class = g_type_class_peek_parent (class);
109
110         object_class->set_property = gl_merge_evolution_set_property;
111         object_class->get_property = gl_merge_evolution_get_property;
112
113         g_object_class_install_property
114                 (object_class,
115                  ARG_QUERY,
116                  g_param_spec_string ("query", NULL, 
117                                       "Query used to select records from the addressbook",
118                                       "(exists \"full_name\")",
119                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
120
121         object_class->finalize = gl_merge_evolution_finalize;
122
123         merge_class->get_key_list    = gl_merge_evolution_get_key_list;
124         merge_class->get_primary_key = gl_merge_evolution_get_primary_key;
125         merge_class->open            = gl_merge_evolution_open;
126         merge_class->close           = gl_merge_evolution_close;
127         merge_class->get_record      = gl_merge_evolution_get_record;
128         merge_class->copy            = gl_merge_evolution_copy;
129
130         gl_debug (DEBUG_MERGE, "END");
131 }
132
133 static void
134 gl_merge_evolution_init (glMergeEvolution *merge_evolution)
135 {
136         gl_debug (DEBUG_MERGE, "START");
137
138         merge_evolution->priv = g_new0 (glMergeEvolutionPrivate, 1);
139         merge_evolution->priv->query = g_strdup(DEFAULT_QUERY);
140
141         gl_debug (DEBUG_MERGE, "END");
142 }
143
144 static void
145 gl_merge_evolution_finalize (GObject *object)
146 {
147         glMergeEvolution *merge_evolution = GL_MERGE_EVOLUTION (object);
148
149         gl_debug (DEBUG_MERGE, "START");
150
151         g_return_if_fail (object && GL_IS_MERGE_EVOLUTION (object));
152
153         free_field_list(merge_evolution->priv->fields);
154         g_free (merge_evolution->priv->query);
155         g_free (merge_evolution->priv);
156
157         G_OBJECT_CLASS (gl_merge_evolution_parent_class)->finalize (object);
158
159         gl_debug (DEBUG_MERGE, "END");
160 }
161
162 /*--------------------------------------------------------------------------*/
163 /* Set argument.                                                            */
164 /*--------------------------------------------------------------------------*/
165 static void
166 gl_merge_evolution_set_property (GObject      *object,
167                                  guint         param_id,
168                                  const GValue *value,
169                                  GParamSpec   *pspec)
170 {
171         glMergeEvolution *merge_evolution;
172
173         merge_evolution = GL_MERGE_EVOLUTION (object);
174
175         switch (param_id) {
176
177         case ARG_QUERY:
178                 g_free (merge_evolution->priv->query);
179                 merge_evolution->priv->query = g_value_dup_string (value);
180                 gl_debug (DEBUG_MERGE, "ARG \"query\" = \"%s\"",
181                           merge_evolution->priv->query);
182                 break;
183
184         default:
185                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
186                 break;
187
188         }
189
190 }
191
192 /*--------------------------------------------------------------------------*/
193 /* Get argument.                                                            */
194 /*--------------------------------------------------------------------------*/
195 static void
196 gl_merge_evolution_get_property (GObject     *object,
197                                  guint        param_id,
198                                  GValue      *value,
199                                  GParamSpec  *pspec)
200 {
201         glMergeEvolution *merge_evolution;
202
203         merge_evolution = GL_MERGE_EVOLUTION (object);
204
205         switch (param_id) {
206
207         case ARG_QUERY:
208                 g_value_set_string (value, merge_evolution->priv->query);
209                 break;
210
211         default:
212                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
213                 break;
214
215         }
216
217 }
218
219 /*--------------------------------------------------------------------------*/
220 /* Get key list.                                                            */
221 /*--------------------------------------------------------------------------*/
222 static GList *
223 gl_merge_evolution_get_key_list (glMerge *merge)
224 {
225         glMergeEvolution   *merge_evolution;
226         GList              *key_list = NULL;
227         GList              *iter;
228         
229         gl_debug (DEBUG_MERGE, "BEGIN");
230
231         merge_evolution = GL_MERGE_EVOLUTION (merge);
232
233         /* for the previously retrieved supported fileds, go through them and find
234          * their pretty names */
235         for (iter = merge_evolution->priv->fields; 
236                  iter != NULL; 
237                  iter = g_list_next(iter)) 
238         {
239                 key_list = g_list_prepend (key_list, 
240                         g_strdup (e_contact_pretty_name (*(EContactField *)iter->data)));
241         }
242
243         key_list = g_list_reverse (key_list);
244
245         gl_debug (DEBUG_MERGE, "END");
246
247         return key_list;
248 }
249
250 /*--------------------------------------------------------------------------*/
251 /* Get "primary" key.                                                       */
252 /*--------------------------------------------------------------------------*/
253 static gchar *
254 gl_merge_evolution_get_primary_key (glMerge *merge)
255 {
256         return g_strdup (e_contact_pretty_name(E_CONTACT_FILE_AS));
257 }
258
259 /*--------------------------------------------------------------------------*/
260 /* Open merge source.                                                       */
261 /*--------------------------------------------------------------------------*/
262 static void
263 gl_merge_evolution_open (glMerge *merge)
264 {
265         glMergeEvolution *merge_evolution;
266         EBookQuery *query;
267         gboolean status;
268         GList *fields, *iter;
269         EContactField *field_id;
270         GError *error;
271
272         gl_debug (DEBUG_MERGE, "BEGIN");
273
274         merge_evolution = GL_MERGE_EVOLUTION (merge);
275
276         query = e_book_query_from_string(merge_evolution->priv->query);
277         if (!query) {
278                 g_warning (_("Couldn't construct query"));
279                 return;
280         }
281
282         merge_evolution->priv->book = e_book_new_system_addressbook(&error);
283         if (!merge_evolution->priv->book) {
284                 g_warning (_("Couldn't open addressbook: %s"), error->message);
285                 e_book_query_unref(query);
286                 g_error_free (error);
287                 return;
288         }
289
290         if (!e_book_open(merge_evolution->priv->book, TRUE, &error)) {
291                 g_warning (_("Couldn't open addressbook: %s"), error->message);
292                 g_error_free (error);
293                 e_book_query_unref(query);
294                 g_object_unref(merge_evolution->priv->book);
295                 merge_evolution->priv->book = NULL;
296                 return;
297         }
298
299         /* fetch the list of fields supported by this address book */
300         status = e_book_get_supported_fields(merge_evolution->priv->book,
301                                                                                  &fields, &error);
302         if (status == FALSE) {
303                 g_warning (_("Couldn't list available fields: %s"), error->message);
304                 g_error_free (error);
305                 e_book_query_unref(query);
306                 g_object_unref(merge_evolution->priv->book);
307                 merge_evolution->priv->book = NULL;
308                 return;
309         }
310
311         /* generate a list of field_ids, and put that into private->fields */
312         for (iter = fields; iter != NULL; iter = g_list_next(iter)) {
313                 field_id = g_new(EContactField, 1);
314                 *field_id = e_contact_field_id(iter->data);
315
316                 /* above this value, the data aren't strings anymore */
317                 if (*field_id >= E_CONTACT_LAST_SIMPLE_STRING) {
318                         g_free (field_id);
319                         continue;
320                 }
321
322                 merge_evolution->priv->fields = 
323                         g_list_prepend(merge_evolution->priv->fields, field_id);
324         }
325         free_field_list(fields); /* don't need the list of names anymore */
326
327         gl_debug(DEBUG_MERGE, "Field list length: %d", g_list_length(merge_evolution->priv->fields));
328
329         /* finally retrieve the contacts */
330         status = e_book_get_contacts (merge_evolution->priv->book,
331                                       query,
332                                       &merge_evolution->priv->contacts,
333                                       &error);
334         if (status == FALSE) {
335                 g_warning (_("Couldn't get contacts: %s"), error->message);
336                 g_error_free (error);
337                 e_book_query_unref(query);
338                 free_field_list(merge_evolution->priv->fields);
339                 g_object_unref(merge_evolution->priv->book);
340                 merge_evolution->priv->book = NULL;
341
342                 return;
343         }
344
345         e_book_query_unref(query);
346
347         gl_debug (DEBUG_MERGE, "END");
348
349         return;
350         /* XXX I should probably sort the list by name (or the file-as element)*/
351 }
352
353 /*--------------------------------------------------------------------------*/
354 /* Close merge source.                                                      */
355 /*--------------------------------------------------------------------------*/
356 static void
357 gl_merge_evolution_close (glMerge *merge)
358 {
359         glMergeEvolution *merge_evolution;
360         GList *iter;
361
362         merge_evolution = GL_MERGE_EVOLUTION (merge);
363
364         /* unref all of the objects created in _open */
365         g_object_unref(merge_evolution->priv->book);
366         merge_evolution->priv->book = NULL;
367
368         for (iter = merge_evolution->priv->contacts; 
369              iter != NULL; 
370              iter = g_list_next(iter))
371         {
372                 EContact *contact = E_CONTACT (iter->data);
373
374                 g_object_unref(contact);
375         }
376         g_list_free(merge_evolution->priv->contacts);
377         merge_evolution->priv->contacts = NULL;
378 }
379
380 /*--------------------------------------------------------------------------*/
381 /* Get next record from merge source, NULL if no records left (i.e EOF)     */
382 /*--------------------------------------------------------------------------*/
383 static glMergeRecord *
384 gl_merge_evolution_get_record (glMerge *merge)
385 {
386         glMergeEvolution   *merge_evolution;
387         glMergeRecord *record;
388         glMergeField  *field;
389         EContactField field_id;
390
391         GList *head, *iter; 
392         EContact *contact;
393
394         merge_evolution = GL_MERGE_EVOLUTION (merge);
395
396         head = merge_evolution->priv->contacts;
397         if (head == NULL) {
398                 return NULL; /* past the last record */
399         }
400         contact = E_CONTACT(head->data);
401
402         record = g_new0 (glMergeRecord, 1);
403         record->select_flag = TRUE;
404
405         /* Take the interesting fields one by one from the contact, and put them
406          * into the glMergeRecord structure. When done, free up the resources for
407          * that contact */
408
409         /* iterate through the supported fields, and add them to the list */
410         for (iter = merge_evolution->priv->fields;
411              iter != NULL;
412              iter = g_list_next(iter))
413         {
414                 gchar *value;
415                 field_id = *(EContactField *)iter->data;
416                 value = g_strdup (e_contact_get_const (contact, field_id));
417
418                 if (value) {
419                         field = g_new0 (glMergeField, 1);
420                         field->key = g_strdup (e_contact_pretty_name (field_id));
421                         field->value = value;
422                         record->field_list = g_list_prepend (record->field_list, field);
423                 }
424         }
425
426         record->field_list = g_list_reverse (record->field_list);
427
428         /* do a destructive read */
429         g_object_unref (contact);
430         merge_evolution->priv->contacts = 
431                 g_list_remove_link (merge_evolution->priv->contacts, head);
432         g_list_free_1 (head);
433
434         return record;
435 }
436
437 /*---------------------------------------------------------------------------*/
438 /* Copy merge_evolution specific fields.                                     */
439 /*---------------------------------------------------------------------------*/
440 static void
441 gl_merge_evolution_copy (glMerge *dst_merge,
442                     glMerge *src_merge)
443 {
444         GList *src_iter, *dst_iter;
445
446         gl_debug (DEBUG_MERGE, "BEGIN");
447
448         glMergeEvolution *dst_merge_evolution;
449         glMergeEvolution *src_merge_evolution;
450
451         dst_merge_evolution = GL_MERGE_EVOLUTION (dst_merge);
452         src_merge_evolution = GL_MERGE_EVOLUTION (src_merge);
453
454         dst_merge_evolution->priv->query = g_strdup(src_merge_evolution->priv->query);
455
456         dst_merge_evolution->priv->fields = g_list_copy(src_merge_evolution->priv->fields);
457         for (src_iter = src_merge_evolution->priv->fields,
458                      dst_iter = dst_merge_evolution->priv->fields; 
459              src_iter != NULL && dst_iter != NULL; 
460              src_iter = g_list_next(src_iter), dst_iter = g_list_next(dst_iter))
461         {
462                 dst_iter->data = g_new(EContactField, 1);
463                 if (src_iter->data) { /* this better not be null, but... */
464                         memcpy(dst_iter->data, src_iter->data, sizeof(EContactField));
465                 }
466         }
467
468         /* I don't know that there's a good way to do a deep copy of the various
469          * libebook structures/objects, so I'm just going to leave them out.  They
470          * are all regenerated on gl_merge_evolution_open, anyway */
471
472         gl_debug (DEBUG_MERGE, "END");
473 }
474
475 /*---------------------------------------------------------------------------*/
476 /* Free the list of supported fields                                         */
477 /*---------------------------------------------------------------------------*/
478 static void
479 free_field_list (GList *fields)
480 {
481         GList *iter;
482
483         for (iter = fields; iter != NULL; iter = g_list_next(iter)) 
484         {
485                 if (iter->data) {
486                         g_free(iter->data);
487                 }
488         }
489         g_list_free(fields);
490         fields = NULL;
491 }
492
493
494 #endif /* HAVE_LIBEBOOK */