3 * Copyright (C) 2001-2009 Jim Evins <evins@snaught.com>.
5 * Copyright (C) 2005 Austin Henry <ahenry@users.sourceforge.net>
7 * This file is part of gLabels.
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.
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.
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/>.
28 #include "merge-vcard.h"
30 #include <libebook/libebook.h>
38 /*===========================================*/
40 /*===========================================*/
42 struct _glMergeVCardPrivate {
55 /*===========================================*/
57 /*===========================================*/
60 /*===========================================*/
61 /* Local function prototypes */
62 /*===========================================*/
64 static void gl_merge_vcard_finalize (GObject *object);
66 static void gl_merge_vcard_set_property (GObject *object,
71 static void gl_merge_vcard_get_property (GObject *object,
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);
86 /*****************************************************************************/
87 /* Boilerplate object stuff. */
88 /*****************************************************************************/
89 G_DEFINE_TYPE (glMergeVCard, gl_merge_vcard, GL_TYPE_MERGE)
93 gl_merge_vcard_class_init (glMergeVCardClass *class)
95 GObjectClass *object_class = G_OBJECT_CLASS (class);
96 glMergeClass *merge_class = GL_MERGE_CLASS (class);
98 gl_debug (DEBUG_MERGE, "START");
100 gl_merge_vcard_parent_class = g_type_class_peek_parent (class);
102 object_class->set_property = gl_merge_vcard_set_property;
103 object_class->get_property = gl_merge_vcard_get_property;
105 object_class->finalize = gl_merge_vcard_finalize;
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;
114 gl_debug (DEBUG_MERGE, "END");
119 gl_merge_vcard_init (glMergeVCard *merge_vcard)
121 gl_debug (DEBUG_MERGE, "START");
123 merge_vcard->priv = g_new0 (glMergeVCardPrivate, 1);
125 gl_debug (DEBUG_MERGE, "END");
130 gl_merge_vcard_finalize (GObject *object)
132 glMergeVCard *merge_vcard = GL_MERGE_VCARD (object);
134 gl_debug (DEBUG_MERGE, "START");
136 g_return_if_fail (object && GL_IS_MERGE_VCARD (object));
138 g_free (merge_vcard->priv);
140 G_OBJECT_CLASS (gl_merge_vcard_parent_class)->finalize (object);
142 gl_debug (DEBUG_MERGE, "END");
146 /*--------------------------------------------------------------------------*/
148 /*--------------------------------------------------------------------------*/
150 gl_merge_vcard_set_property (GObject *object,
157 /* Currently no vcard specific properties. */
160 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
166 /*--------------------------------------------------------------------------*/
168 /*--------------------------------------------------------------------------*/
170 gl_merge_vcard_get_property (GObject *object,
177 /* Currently no vcard specific properties. */
180 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
187 /*--------------------------------------------------------------------------*/
189 /*--------------------------------------------------------------------------*/
191 gl_merge_vcard_get_key_list (const glMerge *merge)
193 GList *key_list = NULL;
194 EContactField field_id;
196 gl_debug (DEBUG_MERGE, "BEGIN");
198 for ( field_id = E_CONTACT_FIELD_FIRST; field_id <= E_CONTACT_LAST_SIMPLE_STRING; field_id++ )
200 key_list = g_list_append (key_list, g_strdup (e_contact_pretty_name (field_id)));
203 gl_debug (DEBUG_MERGE, "END");
209 /*--------------------------------------------------------------------------*/
210 /* Get "primary" key. */
211 /*--------------------------------------------------------------------------*/
213 gl_merge_vcard_get_primary_key (const glMerge *merge)
215 return g_strdup (e_contact_pretty_name(E_CONTACT_FILE_AS));
219 /*--------------------------------------------------------------------------*/
220 /* Open merge source. */
221 /*--------------------------------------------------------------------------*/
223 gl_merge_vcard_open (glMerge *merge)
225 glMergeVCard *merge_vcard;
228 merge_vcard = GL_MERGE_VCARD (merge);
230 src = gl_merge_get_src (merge);
233 merge_vcard->priv->fp = fopen (src, "r");
242 /*--------------------------------------------------------------------------*/
243 /* Close merge source. */
244 /*--------------------------------------------------------------------------*/
246 gl_merge_vcard_close (glMerge *merge)
248 glMergeVCard *merge_vcard;
250 merge_vcard = GL_MERGE_VCARD (merge);
252 if (merge_vcard->priv->fp != NULL) {
253 fclose (merge_vcard->priv->fp);
254 merge_vcard->priv->fp = NULL;
260 maybe_field (const gchar *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 */
273 return g_strdup ("");
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)
282 glMergeVCard *merge_vcard;
283 glMergeRecord *record;
284 EContactField field_id;
290 merge_vcard = GL_MERGE_VCARD (merge);
292 vcard = parse_next_vcard(merge_vcard->priv->fp);
293 if (vcard == NULL || vcard[0] == '\0') {
294 return NULL; /* EOF */
296 contact = e_contact_new_from_vcard(vcard);
297 if (contact == NULL) {
298 return NULL; /* invalid vcard */
301 record = g_new0 (glMergeRecord, 1);
302 record->select_flag = TRUE;
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
308 for ( field_id = E_CONTACT_FIELD_FIRST; field_id <= E_CONTACT_LAST_SIMPLE_STRING; field_id++ )
311 value = g_strdup (e_contact_get_const (contact, field_id));
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);
325 GString *gstr = g_string_new ("");
327 field = maybe_field (address->street);
328 g_string_append_printf (gstr, "%s", field);
331 field = maybe_field (address->ext);
332 g_string_append_printf (gstr, "%s", field);
335 field = maybe_field (address->locality);
336 g_string_append_printf (gstr, "%s", field);
339 field = maybe_field (address->region);
340 g_string_append_printf (gstr, "%s", field);
343 field = maybe_field (address->code);
344 g_string_append_printf (gstr, "%s", field);
347 field = maybe_field (address->country);
348 g_string_append_printf (gstr, "%s", field);
351 value = g_strdup (gstr->str);
353 g_string_free (gstr, TRUE);
354 e_contact_address_free (address);
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);
366 record->field_list = g_list_reverse (record->field_list);
369 /* free the contact */
370 g_object_unref (contact);
377 /*---------------------------------------------------------------------------*/
378 /* Copy merge_vcard specific fields. */
379 /*---------------------------------------------------------------------------*/
381 gl_merge_vcard_copy (glMerge *dst_merge,
382 const glMerge *src_merge)
384 /* Currently nothing to copy. */
388 /*---------------------------------------------------------------------------*/
389 /* PRIVATE: pull out a full VCard from the open file */
391 /* fp - an open stream to parse in put from */
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 /*---------------------------------------------------------------------------*/
397 parse_next_vcard (FILE *fp)
399 gboolean found_begin = FALSE;
400 gboolean found_end = FALSE;
406 /* if no source has been set up, don't try to read from the file */
411 vcard = g_malloc0(size);
413 while (found_end == FALSE && fgets(line, sizeof(line), fp))
415 if (found_begin == TRUE)
417 if (g_ascii_strncasecmp(line, "END:VCARD", strlen("END:VCARD")) == 0)
424 if (g_ascii_strncasecmp(line, "BEGIN:VCARD", strlen("BEGIN:VCARD")) == 0)
430 continue; /* skip lines not in a vcard */
434 /* if the buffer passed us isn't big enough, reallocate it */
435 cursize += strlen(line);
439 vcard = (char *)g_realloc(vcard, size); /* aborts program on error */
442 /* add the line (or portion thereof) to the vcard */
443 strncat(vcard, line, size);
451 #endif /* HAVE_LIBEBOOK */
456 * Local Variables: -- emacs
458 * c-basic-offset: 8 -- emacs
459 * tab-width: 8 -- emacs
460 * indent-tabs-mode: nil -- emacs