]> git.sur5r.net Git - glabels/blob - src/merge-vcard.c
Imported Upstream version 3.4.0
[glabels] / src / merge-vcard.c
1 /*
2  *  merge-vcard.c
3  *  Copyright (C) 2001-2009  Jim Evins <evins@snaught.com>.
4  *  and
5  *  Copyright (C) 2005  Austin Henry <ahenry@users.sourceforge.net>
6  *
7  *  This file is part of gLabels.
8  *
9  *  gLabels is free software: you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation, either version 3 of the License, or
12  *  (at your option) any later version.
13  *
14  *  gLabels is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with gLabels.  If not, see <http://www.gnu.org/licenses/>.
21  */
22
23 #include <config.h>
24
25 #ifdef HAVE_LIBEBOOK
26
27
28 #include "merge-vcard.h"
29
30 #include <libebook/libebook.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <errno.h>
34
35 #include "debug.h"
36
37
38 /*===========================================*/
39 /* Private types                             */
40 /*===========================================*/
41
42 struct _glMergeVCardPrivate {
43         FILE        *fp;
44 };
45
46 enum {
47         LAST_SIGNAL
48 };
49
50 enum {
51         ARG_0
52 };
53
54
55 /*===========================================*/
56 /* Private globals                           */
57 /*===========================================*/
58
59
60 /*===========================================*/
61 /* Local function prototypes                 */
62 /*===========================================*/
63
64 static void           gl_merge_vcard_finalize        (GObject          *object);
65
66 static void           gl_merge_vcard_set_property    (GObject          *object,
67                                                       guint             param_id,
68                                                       const GValue     *value,
69                                                       GParamSpec       *pspec);
70
71 static void           gl_merge_vcard_get_property    (GObject          *object,
72                                                       guint             param_id,
73                                                       GValue           *value,
74                                                       GParamSpec       *pspec);
75
76 static GList         *gl_merge_vcard_get_key_list    (const glMerge    *merge);
77 static gchar         *gl_merge_vcard_get_primary_key (const glMerge    *merge);
78 static void           gl_merge_vcard_open            (glMerge          *merge);
79 static void           gl_merge_vcard_close           (glMerge          *merge);
80 static glMergeRecord *gl_merge_vcard_get_record      (glMerge          *merge);
81 static void           gl_merge_vcard_copy            (glMerge          *dst_merge,
82                                                       const glMerge    *src_merge);
83 static char *         parse_next_vcard               (FILE             *fp);
84
85
86 /*****************************************************************************/
87 /* Boilerplate object stuff.                                                 */
88 /*****************************************************************************/
89 G_DEFINE_TYPE (glMergeVCard, gl_merge_vcard, GL_TYPE_MERGE)
90
91
92 static void
93 gl_merge_vcard_class_init (glMergeVCardClass *class)
94 {
95         GObjectClass *object_class = G_OBJECT_CLASS (class);
96         glMergeClass *merge_class  = GL_MERGE_CLASS (class);
97
98         gl_debug (DEBUG_MERGE, "START");
99
100         gl_merge_vcard_parent_class = g_type_class_peek_parent (class);
101
102         object_class->set_property = gl_merge_vcard_set_property;
103         object_class->get_property = gl_merge_vcard_get_property;
104
105         object_class->finalize = gl_merge_vcard_finalize;
106
107         merge_class->get_key_list    = gl_merge_vcard_get_key_list;
108         merge_class->get_primary_key = gl_merge_vcard_get_primary_key;
109         merge_class->open            = gl_merge_vcard_open;
110         merge_class->close           = gl_merge_vcard_close;
111         merge_class->get_record      = gl_merge_vcard_get_record;
112         merge_class->copy            = gl_merge_vcard_copy;
113
114         gl_debug (DEBUG_MERGE, "END");
115 }
116
117
118 static void
119 gl_merge_vcard_init (glMergeVCard *merge_vcard)
120 {
121         gl_debug (DEBUG_MERGE, "START");
122
123         merge_vcard->priv = g_new0 (glMergeVCardPrivate, 1);
124
125         gl_debug (DEBUG_MERGE, "END");
126 }
127
128
129 static void
130 gl_merge_vcard_finalize (GObject *object)
131 {
132         glMergeVCard *merge_vcard = GL_MERGE_VCARD (object);
133
134         gl_debug (DEBUG_MERGE, "START");
135
136         g_return_if_fail (object && GL_IS_MERGE_VCARD (object));
137
138         g_free (merge_vcard->priv);
139
140         G_OBJECT_CLASS (gl_merge_vcard_parent_class)->finalize (object);
141
142         gl_debug (DEBUG_MERGE, "END");
143 }
144
145
146 /*--------------------------------------------------------------------------*/
147 /* Set argument.                                                            */
148 /*--------------------------------------------------------------------------*/
149 static void
150 gl_merge_vcard_set_property (GObject      *object,
151                              guint         param_id,
152                              const GValue *value,
153                              GParamSpec   *pspec)
154 {
155         switch (param_id) {
156
157         /* Currently no vcard specific properties. */
158
159         default:
160                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
161                 break;
162         }
163 }
164
165
166 /*--------------------------------------------------------------------------*/
167 /* Get argument.                                                            */
168 /*--------------------------------------------------------------------------*/
169 static void
170 gl_merge_vcard_get_property (GObject     *object,
171                              guint        param_id,
172                              GValue      *value,
173                              GParamSpec  *pspec)
174 {
175         switch (param_id) {
176
177         /* Currently no vcard specific properties. */
178
179         default:
180                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
181                 break;
182         }
183
184 }
185
186
187 /*--------------------------------------------------------------------------*/
188 /* Get key list.                                                            */
189 /*--------------------------------------------------------------------------*/
190 static GList *
191 gl_merge_vcard_get_key_list (const glMerge *merge)
192 {
193         GList          *key_list = NULL;
194         EContactField   field_id;
195         
196         gl_debug (DEBUG_MERGE, "BEGIN");
197
198         for ( field_id = E_CONTACT_FIELD_FIRST; field_id <= E_CONTACT_LAST_SIMPLE_STRING; field_id++ )
199         {
200                 key_list = g_list_append (key_list, g_strdup (e_contact_pretty_name (field_id)));
201         }
202
203         gl_debug (DEBUG_MERGE, "END");
204
205         return key_list;
206 }
207
208
209 /*--------------------------------------------------------------------------*/
210 /* Get "primary" key.                                                       */
211 /*--------------------------------------------------------------------------*/
212 static gchar *
213 gl_merge_vcard_get_primary_key (const glMerge *merge)
214 {
215         return g_strdup (e_contact_pretty_name(E_CONTACT_FILE_AS));
216 }
217
218
219 /*--------------------------------------------------------------------------*/
220 /* Open merge source.                                                       */
221 /*--------------------------------------------------------------------------*/
222 static void
223 gl_merge_vcard_open (glMerge *merge)
224 {
225         glMergeVCard *merge_vcard;
226         gchar        *src;
227
228         merge_vcard = GL_MERGE_VCARD (merge);
229
230         src = gl_merge_get_src (merge);
231
232         if (src != NULL) {
233                 merge_vcard->priv->fp = fopen (src, "r");
234         }
235
236         g_free (src);
237
238         return;
239 }
240
241
242 /*--------------------------------------------------------------------------*/
243 /* Close merge source.                                                      */
244 /*--------------------------------------------------------------------------*/
245 static void
246 gl_merge_vcard_close (glMerge *merge)
247 {
248         glMergeVCard *merge_vcard;
249
250         merge_vcard = GL_MERGE_VCARD (merge);
251
252         if (merge_vcard->priv->fp != NULL) {
253                 fclose (merge_vcard->priv->fp);
254                 merge_vcard->priv->fp = NULL;
255         }
256 }
257
258
259 static gchar *
260 maybe_field (const gchar *str)
261 {
262         if (str && *str) {
263                 /* Copy it, allocating enough for an extra newline */
264                 gchar *copy = g_strconcat (str, "\n", NULL);
265                 /* Strip trailing whitespace */
266                 size_t len = strlen (g_strchomp (copy));
267                 /* Add back in a single newline */
268                 if (len > 0)
269                         copy[len] = '\n';
270                 return copy;
271         }
272
273         return g_strdup ("");
274 }
275
276 /*--------------------------------------------------------------------------*/
277 /* Get next record from merge source, NULL if no records left (i.e EOF)     */
278 /*--------------------------------------------------------------------------*/
279 static glMergeRecord *
280 gl_merge_vcard_get_record (glMerge *merge)
281 {
282         glMergeVCard  *merge_vcard;
283         glMergeRecord *record;
284         EContactField  field_id;
285         glMergeField  *field;
286
287         char *vcard;
288         EContact *contact;
289
290         merge_vcard = GL_MERGE_VCARD (merge);
291
292         vcard = parse_next_vcard(merge_vcard->priv->fp);
293         if (vcard == NULL || vcard[0] == '\0') {
294                 return NULL; /* EOF */
295         }
296         contact = e_contact_new_from_vcard(vcard);
297         if (contact == NULL) {
298                 return NULL; /* invalid vcard */
299         }
300
301         record = g_new0 (glMergeRecord, 1);
302         record->select_flag = TRUE;
303
304         /* Take the interesting fields one by one from the contact, and put them
305          * into the glMergeRecord structure. When done, free up the resources for
306          * that contact */
307
308         for ( field_id = E_CONTACT_FIELD_FIRST; field_id <= E_CONTACT_LAST_SIMPLE_STRING; field_id++ )
309         {
310                 gchar *value;
311                 value = g_strdup (e_contact_get_const (contact, field_id));
312
313                 if (!value &&
314                     field_id >= E_CONTACT_ADDRESS_LABEL_HOME &&
315                     field_id <= E_CONTACT_ADDRESS_LABEL_OTHER) {
316                         EContactAddress *address;
317                         EContactField addrfield;
318                         addrfield = (field_id -
319                                      E_CONTACT_ADDRESS_LABEL_HOME +
320                                      E_CONTACT_ADDRESS_HOME);
321                         address = e_contact_get (contact, addrfield);
322                         if (address) {
323                                 gchar *val;
324                                 gchar *field;
325                                 GString *gstr = g_string_new ("");
326
327                                 field = maybe_field (address->street);
328                                 g_string_append_printf (gstr, "%s", field);
329                                 g_free (field);
330
331                                 field = maybe_field (address->ext);
332                                 g_string_append_printf (gstr, "%s", field);
333                                 g_free (field);
334
335                                 field = maybe_field (address->locality);
336                                 g_string_append_printf (gstr, "%s", field);
337                                 g_free (field);
338
339                                 field = maybe_field (address->region);
340                                 g_string_append_printf (gstr, "%s", field);
341                                 g_free (field);
342
343                                 field = maybe_field (address->code);
344                                 g_string_append_printf (gstr, "%s", field);
345                                 g_free (field);
346
347                                 field = maybe_field (address->country);
348                                 g_string_append_printf (gstr, "%s", field);
349                                 g_free (field);
350
351                                 value = g_strdup (gstr->str);
352                                 g_strchomp (value);
353                                 g_string_free (gstr, TRUE);
354                                 e_contact_address_free (address);
355                         }
356                 }
357
358                 if (value) {
359                         field = g_new0 (glMergeField, 1);
360                         field->key = g_strdup (e_contact_pretty_name (field_id));
361                         field->value = value;
362                         record->field_list = g_list_prepend (record->field_list, field);
363                 }
364         }
365
366         record->field_list = g_list_reverse (record->field_list);
367
368
369         /* free the contact */
370         g_object_unref (contact);
371         g_free(vcard);
372
373         return record;
374 }
375
376
377 /*---------------------------------------------------------------------------*/
378 /* Copy merge_vcard specific fields.                                         */
379 /*---------------------------------------------------------------------------*/
380 static void
381 gl_merge_vcard_copy (glMerge       *dst_merge,
382                      const glMerge *src_merge)
383 {
384         /* Currently nothing to copy. */
385 }
386
387
388 /*---------------------------------------------------------------------------*/
389 /* PRIVATE: pull out a full VCard from the open file                         */
390 /* Arguments:                                                                */
391 /*  fp - an open stream to parse in put from                                 */
392 /* Returns:                                                                  */
393 /*  a pointer to the buffer containing the vcard, the empty string on        */
394 /*  end-of-file or error, this buffer needs to be free by the caller         */
395 /*---------------------------------------------------------------------------*/
396 static char * 
397 parse_next_vcard (FILE *fp)
398 {
399         gboolean  found_begin = FALSE;
400         gboolean  found_end = FALSE;
401         char     *vcard;
402         char      line[512];
403         int       size = 2048;
404         int       cursize = 0;
405
406         /* if no source has been set up, don't try to read from the file */
407         if (!fp) {
408                 return NULL;
409         }
410
411         vcard = g_malloc0(size);
412
413         while (found_end == FALSE && fgets(line, sizeof(line), fp))
414         {
415                 if (found_begin == TRUE)
416                 {
417                         if (g_ascii_strncasecmp(line, "END:VCARD", strlen("END:VCARD")) == 0)
418                         {
419                                 found_end = TRUE;
420                         }
421                 }
422                 else
423                 {
424                         if (g_ascii_strncasecmp(line, "BEGIN:VCARD", strlen("BEGIN:VCARD")) == 0)
425                         {
426                                 found_begin = TRUE;
427                         } 
428                         else
429                         {
430                                 continue; /* skip lines not in a vcard */
431                         }
432                 }
433
434                 /* if the buffer passed us isn't big enough, reallocate it */
435                 cursize += strlen(line);
436                 if (cursize >= size)
437                 {
438                         size *= 2;
439                         vcard = (char *)g_realloc(vcard, size); /* aborts program on error */
440                 }
441
442                 /* add the line (or portion thereof) to the vcard */
443                 strncat(vcard, line, size);
444         }
445
446         return vcard;
447 }
448
449
450
451 #endif /* HAVE_LIBEBOOK */
452
453
454
455 /*
456  * Local Variables:       -- emacs
457  * mode: C                -- emacs
458  * c-basic-offset: 8      -- emacs
459  * tab-width: 8           -- emacs
460  * indent-tabs-mode: nil  -- emacs
461  * End:                   -- emacs
462  */