aboutsummaryrefslogtreecommitdiffstats
path: root/addressbook/backend/ebook/e-card.c
diff options
context:
space:
mode:
authorNat Friedman <nat@src.gnome.org>2000-01-25 13:28:18 +0800
committerNat Friedman <nat@src.gnome.org>2000-01-25 13:28:18 +0800
commitfd4379ff20fe9c9e3b4f4028095b9659687002ff (patch)
tree78af76526262d746417a1e2007fd712f8d4ce584 /addressbook/backend/ebook/e-card.c
parenta315f0321395423c3c52adb4bb3063c433948dd5 (diff)
downloadgsoc2013-evolution-fd4379ff20fe9c9e3b4f4028095b9659687002ff.tar.gz
gsoc2013-evolution-fd4379ff20fe9c9e3b4f4028095b9659687002ff.tar.zst
gsoc2013-evolution-fd4379ff20fe9c9e3b4f4028095b9659687002ff.zip
More work.
svn path=/trunk/; revision=1626
Diffstat (limited to 'addressbook/backend/ebook/e-card.c')
-rw-r--r--addressbook/backend/ebook/e-card.c1856
1 files changed, 1856 insertions, 0 deletions
diff --git a/addressbook/backend/ebook/e-card.c b/addressbook/backend/ebook/e-card.c
new file mode 100644
index 0000000000..bc5b13deae
--- /dev/null
+++ b/addressbook/backend/ebook/e-card.c
@@ -0,0 +1,1856 @@
+/*
+ * Authors:
+ * Arturo Espinosa (arturo@nuclecu.unam.mx)
+ * Nat Friedman (nat@helixcode.com)
+ *
+ * Copyright (C) 2000 Helix Code, Inc.
+ * Copyright (C) 1999 The Free Software Foundation
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+
+#include "../libversit/vcc.h"
+#include <e-card-pairs.h>
+#include <e-card.h>
+
+#define is_a_prop_of(obj,prop) isAPropertyOf (obj,prop)
+#define str_val(obj) the_str = (vObjectValueType (obj))? fakeCString (vObjectUStringZValue (obj)) : calloc (1, 1)
+#define has(obj,prop) (vo = isAPropertyOf (obj, prop))
+
+static VObject *card_convert_to_vobject (Card *crd);
+
+/*
+ * ECard lifecycle management and vCard loading/saving.
+ */
+
+/**
+ * e_card_new:
+ */
+ECard *
+e_card_new (void)
+{
+ ECard *c;
+
+ c = g_new0 (ECard, 1);
+
+ c->fname =
+ c->mailer =
+ c->title =
+ c->role =
+ c->comment =
+ c->categories =
+ c->url =
+ c->uid = e_card_prop_str_empty ();
+
+ c->photo.type = PHOTO_JPEG;
+ c->logo.type = PHOTO_JPEG;
+ c->rev.utc = -1;
+ c->sound.type = SOUND_PHONETIC;
+ c->key.type = KEY_PGP;
+
+ c->categories.prop.encod = ENC_QUOTED_PRINTABLE;
+ c->comment.prop.encod = ENC_QUOTED_PRINTABLE;
+
+ c->name.prop = c->photo.prop = c->bday.prop = c->timezn.prop =
+ c->geopos.prop = c->logo.prop = c->org.prop = c->rev.prop =
+ c->sound.prop = c->key.prop = c->deladdr.prop = c->dellabel.prop =
+ c->phone.prop = c->email.prop = c->xtension.prop = c->prop = e_card_prop_empty ();
+
+ c->prop.type = PROP_CARD;
+ c->fname.prop.type = PROP_FNAME;
+ c->name.prop.type = PROP_NAME;
+ c->photo.prop.type = PROP_PHOTO;
+ c->bday.prop.type = PROP_BDAY;
+
+ c->deladdr.prop.type = PROP_DELADDR_LIST;
+ c->dellabel.prop.type = PROP_DELLABEL_LIST;
+ c->phone.prop.type = PROP_PHONE_LIST;
+ c->email.prop.type = PROP_EMAIL_LIST;
+ c->xtension.prop.type = PROP_XTENSION_LIST;
+ c->mailer.prop.type = PROP_MAILER;
+ c->timezn.prop.type = PROP_TIMEZN;
+ c->geopos.prop.type = PROP_GEOPOS;
+ c->title.prop.type = PROP_TITLE;
+ c->role.prop.type = PROP_ROLE;
+ c->logo.prop.type = PROP_LOGO;
+ c->org.prop.type = PROP_ORG;
+ c->categories.prop.type = PROP_CATEGORIES;
+ c->comment.prop.type = PROP_COMMENT;
+ c->rev.prop.type = PROP_REV;
+ c->sound.prop.type = PROP_SOUND;
+ c->url.prop.type = PROP_URL;
+ c->uid.prop.type = PROP_UID;
+ c->key.prop.type = PROP_KEY;
+
+ return c;
+}
+
+static void
+e_card_str_free (CardStrProperty *sp)
+{
+ g_free (sp->str);
+
+ e_card_prop_free (sp->prop);
+}
+
+static void
+e_card_name_free (CardName *name)
+{
+ g_free (name->family);
+ g_free (name->given);
+ g_free (name->additional);
+ g_free (name->prefix);
+ g_free (name->suffix);
+
+ e_card_prop_free (name->prop);
+}
+
+static void
+e_card_photo_free (CardPhoto *photo)
+{
+ g_free (photo->data);
+
+ e_card_prop_free (photo->prop);
+}
+
+/**
+ * e_card_free:
+ */
+void
+e_card_free (ECard *card)
+{
+ GList *l;
+
+ g_return_if_fail (card != NULL);
+
+ e_card_name_free (& card->name);
+ e_card_str_free (& card->fname);
+
+ e_card_photo_free (card->photo);
+
+ e_card_logo_free (card->logo);
+ e_card_org_free (card->org);
+ e_card_key_free (card->key);
+ e_card_sound_free (card->sound);
+
+ e_card_prop_str_free (& card->mailer);
+ e_card_prop_str_free (& card->title);
+ e_card_prop_str_free (& card->role);
+ e_card_prop_str_free (& card->categories);
+ e_card_prop_str_free (& card->comment);
+ e_card_prop_str_free (& card->url);
+ e_card_prop_str_free (& card->uid);
+
+ /* address is a little more complicated */
+ card_prop_free (card->deladdr.prop);
+ while ((l = card->deladdr.l)) {
+
+ e_card_deladdr_free ((CardDelAddr *) l->data);
+
+ card->deladdr.l = g_list_remove_link (card->deladdr.l, l);
+ g_list_free (l);
+ }
+
+ g_free (card);
+}
+
+typedef struct
+{
+ char c;
+ int id;
+
+ GList *sons;
+} tree;
+
+extern CardProperty
+e_card_prop_empty (void)
+{
+ CardProperty prop;
+
+ prop.used = FALSE;
+
+ prop.type = PROP_NONE;
+ prop.encod = ENC_7BIT;
+ prop.value = VAL_INLINE;
+ prop.charset = NULL;
+ prop.lang = NULL;
+ prop.grp = NULL;
+ prop.xtension = NULL;
+
+ prop.user_data = NULL;
+
+ return prop;
+}
+
+static CardStrProperty
+e_card_prop_str_empty (void)
+{
+ CardStrProperty strprop;
+
+ strprop.prop = card_prop_empty ();
+ strprop.str = NULL;
+
+ return strprop;
+}
+
+/* Intended to check asserts. */
+extern int card_check_prop (CardProperty prop)
+{
+ if (((prop.used == FALSE) || (prop.used == TRUE)) &&
+ ((prop.type >= PROP_NONE) && (prop.type <= PROP_LAST)) &&
+ ((prop.encod >= ENC_NONE) && (prop.encod <= ENC_LAST)) &&
+ ((prop.value >= VAL_NONE) && (prop.value <= VAL_LAST)))
+ return TRUE;
+
+ return FALSE;
+}
+
+extern void
+card_prop_free (CardProperty prop)
+{
+ GList *l;
+
+ g_free (prop.charset);
+ g_free (prop.lang);
+
+ for (l = prop.xtension; l; l = l->next) {
+ CardXAttribute *xa = (CardXAttribute *) l->data;
+ g_free (xa->name);
+ g_free (xa->data);
+ }
+
+ g_list_free (l);
+
+ prop.used = FALSE;
+}
+
+e_card_deladdr_free (ECardDelAddr *c)
+{
+ card_prop_free (c->prop);
+
+ g_free (p->pobox);
+ g_free (p->ext);
+ g_free (p->street);
+ g_free (p->city);
+ g_free (p->region);
+ g_free (p->code);
+ g_free (p->country);
+}
+
+void
+card_free (Card *crd)
+{
+}
+
+static tree *
+new_tree (char c, int id)
+{
+ tree *t;
+
+ t = malloc (sizeof (tree));
+ t->c = c;
+ t->id = id;
+ t->sons = NULL;
+
+ return t;
+}
+
+static void
+add_branch (tree *t, char *str, int id)
+{
+ tree *tmp;
+ char *end;
+
+ end = str + strlen (str) + 1;
+
+ while (str != end) {
+ tmp = new_tree (*str, id);
+ t->sons = g_list_append (t->sons, (gpointer) tmp);
+ t = tmp;
+
+ str ++;
+ }
+}
+
+static tree *
+add_to_tree (tree *t, struct pair p)
+{
+ GList *node;
+ char *c, *end;
+ tree *tmp;
+
+ c = p.str;
+ end = c + strlen (c) + 1;
+ tmp = t;
+
+ while (c != end) {
+ for (node = tmp->sons; node; node = node->next)
+ if (((tree *) node->data)->c == *c) {
+ break;
+ }
+
+ if (node) {
+ tmp = (tree *) node->data;
+ tmp->id = 0;
+ c++;
+ }
+ else {
+ add_branch (tmp, c, p.id);
+ break;
+ }
+ }
+
+ return t;
+}
+
+static tree *
+create_search_tree (void)
+{
+ tree *t;
+ int i;
+
+ t = new_tree (0, 0);
+ for (i = 0; prop_lookup[i].str; i++)
+ t = add_to_tree (t, prop_lookup[i]);
+
+ return t;
+}
+
+static int
+card_lookup_name (const char *c)
+{
+ static tree *search_tree = NULL;
+ GList *node;
+ tree *tmp;
+ const char *end;
+
+ if (!search_tree)
+ search_tree = create_search_tree ();
+
+ tmp = search_tree;
+ end = c + strlen (c) + 1;
+
+ while (tmp->id == 0 && c != end) {
+ for (node = tmp->sons; node; node = node->next)
+ if (((tree *) node->data)->c == *c) {
+ break;
+ }
+
+ if (node) {
+ tmp = (tree *) node->data;
+ c++;
+ }
+ else
+ return 0;
+ }
+
+ return tmp->id;
+}
+
+static enum PhotoType
+get_photo_type (VObject *o)
+{
+ VObject *vo;
+ int i;
+
+ for (i = 0; photo_pairs[i].str; i++)
+ if (has (o, photo_pairs[i].str))
+ return photo_pairs[i].id;
+
+ g_warning ("? < No PhotoType for Photo property. Falling back to JPEG.");
+ return PHOTO_JPEG;
+}
+
+static int
+get_addr_type (VObject *o)
+{
+ VObject *vo;
+ int ret = 0;
+ int i;
+
+ for (i = 0; addr_pairs[i].str; i++)
+ if (has (o, addr_pairs[i].str))
+ ret |= addr_pairs[i].id;
+
+ return ret;
+}
+
+static int
+get_phone_type (VObject *o)
+{
+ VObject *vo;
+ int ret = 0;
+ int i;
+
+ for (i = 0; phone_pairs[i].str; i++)
+ if (has (o, phone_pairs[i].str))
+ ret |= phone_pairs[i].id;
+
+ return ret;
+}
+
+static enum EMailType
+get_email_type (VObject *o)
+{
+ VObject *vo;
+ int i;
+
+ for (i = 0; email_pairs[i].str; i++)
+ if (has (o, email_pairs[i].str))
+ return email_pairs[i].id;
+
+ g_warning ("? < No EMailType for EMail property. Falling back to INET.");
+ return EMAIL_INET;
+}
+
+static CardProperty
+get_CardProperty (VObject *o)
+{
+ VObjectIterator i;
+ CardProperty prop;
+
+ prop = card_prop_empty ();
+ prop.used = TRUE;
+
+ initPropIterator (&i, o);
+ while (moreIteration (&i)) {
+ VObject *vo = nextVObject (&i);
+ const char *n = vObjectName (vo);
+ int propid;
+
+ propid = card_lookup_name (n);
+
+ switch (propid) {
+
+ case PROP_VALUE:
+
+ if (has (vo, VCContentIDProp))
+ prop.value = VAL_CID;
+ else if (has (vo, VCURLValueProp))
+ prop.value = VAL_URL;
+ break;
+
+ case PROP_ENCODING:
+ if (has (vo, VCQuotedPrintableProp))
+ prop.encod = ENC_QUOTED_PRINTABLE;
+ else if (has (vo, VC8bitProp))
+ prop.encod = ENC_8BIT;
+ else if (has (vo, VCBase64Prop))
+ prop.encod = ENC_BASE64;
+ break;
+
+ case PROP_QUOTED_PRINTABLE:
+ prop.encod = ENC_QUOTED_PRINTABLE;
+ break;
+
+ case PROP_8BIT:
+ prop.encod = ENC_8BIT;
+ break;
+
+ case PROP_BASE64:
+ prop.encod = ENC_BASE64;
+ break;
+
+ case PROP_LANG:
+ if (vObjectValueType (vo)) {
+ prop.lang =
+ g_strdup (vObjectStringZValue (vo));
+ } else
+ g_warning ("? < No value for LANG attribute.");
+ break;
+
+ case PROP_CHARSET:
+ if (vObjectValueType (vo)) {
+ prop.charset =
+ g_strdup (vObjectStringZValue (vo));
+ g_warning (prop.charset);
+ } else
+ g_warning ("? < No value for CHARSET attribute.");
+ break;
+ default:
+ {
+ CardXAttribute *c;
+
+ c = malloc (sizeof (CardXAttribute));
+ c->name = g_strdup (n);
+
+ if (vObjectValueType (vo))
+ c->data =
+ g_strdup (vObjectStringZValue (vo));
+ else
+ c->data = NULL;
+
+ prop.xtension =
+ g_list_append (prop.xtension, c);
+ }
+ }
+ }
+
+ return prop;
+}
+
+static gboolean
+e_card_prop_has (VObject *o,
+ const char *id)
+{
+ g_assert (o != NULL);
+ g_assert (id != NULL);
+
+ if (isAPropertyOf (o, id) == NULL)
+ return FALSE;
+
+ return TRUE;
+}
+
+static const char *
+e_card_prop_get_str (VObject *o,
+ const char *id)
+{
+ VObject *strobj;
+
+ g_assert (o != NULL);
+ g_assert (id != NULL);
+
+ strobj = isAPropertyOf (o, id);
+
+ if (strobj == NULL)
+ return g_strdup ("");
+
+ if (vObjectValueType (strobj) != NULL) {
+ char *str;
+ char *g_str;
+
+ str = fakeCString (vObjectStringZValue (strobj));
+ g_str = g_strdup (str);
+ free (str);
+
+ return g_str;
+ }
+
+ return g_strdup ("");
+}
+
+static ECardName *
+e_card_get_name (VObject *o)
+{
+ CardName *name;
+ VObject *vo;
+ char *the_str;
+
+ name = g_new0 (ECardName, 1);
+
+ name->family = e_card_prop_get_substr (o, VCFamilyNameProp);
+ name->given = e_card_prop_get_substr (o, VCGivenNameProp);
+ name->additional = e_card_prop_get_substr (o, VCAdditionalNamesProp);
+ name->prefix = e_card_prop_get_substr (o, VCNamePrefixesProp);
+ name->suffix = e_card_prop_get_substr (o, VCNameSuffixesProp);
+
+ return name;
+}
+
+static CardBDay
+strtoCardBDay (char *str)
+{
+ char *s;
+ int i;
+ CardBDay bday;
+
+ bday.year = 0;
+ bday.month = 0;
+ bday.day = 0;
+
+ if (strchr (str, '-')) {
+ for (s = strtok (str, "-"), i = 0; s;
+ s = strtok (NULL, "-"), i++)
+ switch (i) {
+ case 0:
+ bday.year = atoi (s);
+ break;
+ case 1:
+ bday.month = atoi (s);
+ break;
+ case 2:
+ bday.day = atoi (s);
+ break;
+ default:
+ g_warning ("? < Too many values for BDay property.");
+ }
+
+ if (i < 2)
+ g_warning ("? < Too few values for BDay property.");
+ } else {
+ if (strlen (str) >= 8) {
+ bday.day = atoi (str + 6);
+ str[6] = 0;
+ bday.month = atoi (str + 4);
+ str[4] = 0;
+ bday.year = atoi (str);
+ } else
+ g_warning ("? < Bad format for BDay property.");
+ }
+
+ return bday;
+}
+
+static ECardDelAddr *
+e_card_get_del_addr (VObject *o)
+{
+ ECardDelAddr *addr;
+
+ addr = g_new0 (ECardDelAddr, 1);
+
+ addr->type = get_addr_type (o);
+ addr->po = e_card_prop_get_substr (o, VCPostalBoxProp);
+ addr->ext = e_card_prop_get_substr (o, VCExtAddressProp);
+ addr->street = e_card_prop_get_substr (o, VCStreetAddressProp);
+ addr->city = e_card_prop_get_substr (o, VCCityProp);
+ addr->region = e_card_prop_get_substr (o, VCRegionProp);
+ addr->code = e_card_prop_get_substr (o, VCPostalBoxProp);
+ addr->country = e_card_prop_get_substr (o, VCCountryNameProp);
+
+ return addr;
+}
+
+static CardDelLabel *
+get_CardDelLabel (VObject *o)
+{
+ CardDelLabel *dellabel;
+ char *the_str;
+
+ dellabel = malloc (sizeof (CardDelLabel));
+
+ dellabel->type = get_addr_type (o);
+ dellabel->data = g_strdup (str_val (o));
+
+ free (the_str);
+ return dellabel;
+}
+
+static CardPhone *
+get_CardPhone (VObject *o)
+{
+ CardPhone *ret;
+ char *the_str;
+
+ ret = malloc (sizeof (CardPhone));
+ ret->type = get_phone_type (o);
+ ret->data = g_strdup (str_val (o));
+
+ free (the_str);
+
+ return ret;
+}
+
+static CardEMail *
+get_CardEMail (VObject *o)
+{
+ CardEMail *ret;
+ char *the_str;
+
+ ret = malloc (sizeof (CardEMail));
+ ret->type = get_email_type (o);
+ ret->data = g_strdup (str_val (o));
+
+ free (the_str);
+
+ return ret;
+}
+
+static CardTimeZone
+strtoCardTimeZone (char *str)
+{
+ char s[3];
+ CardTimeZone tz;
+
+ if (*str == '-') {
+ tz.sign = -1;
+ str++;
+ } else
+ tz.sign = 1;
+
+ tz.hours = 0;
+ tz.mins = 0;
+
+ s[2] = 0;
+ if (strlen (str) > 2) {
+ s[0] = str[0];
+ s[1] = str[1];
+ tz.hours = atoi (s);
+ } else {
+ g_warning ("? < TimeZone value is too short.");
+ return tz;
+ }
+
+ str += 2;
+ if (*str == ':')
+ str++;
+
+ if (strlen (str) >= 2) {
+ s[0] = str[0];
+ s[1] = str[1];
+ tz.mins = atoi (s);
+ } else {
+ g_warning ("? < TimeZone value is too short.");
+ return tz;
+ }
+
+ if (strlen (str) > 3)
+ g_warning ("? < TimeZone value is too long.");
+
+ return tz;
+}
+
+static CardGeoPos
+strtoCardGeoPos (char *str)
+{
+ CardGeoPos gp;
+ char *s;
+
+ gp.lon = 0;
+ gp.lat = 0;
+
+ s = strchr (str, ',');
+
+ if (! s) {
+ g_warning ("? < Bad format for GeoPos property.");
+ return gp;
+ }
+
+ *s = 0;
+ s++;
+
+ gp.lon = atof (str);
+ gp.lat = atof (s);
+
+ return gp;
+}
+
+static CardOrg *
+e_card_vobject_to_org (VObject *o)
+{
+ VObject *vo;
+ char *the_str;
+ CardOrg *org;
+
+ org = g_new0 (CardOrg, 1);
+
+ if (has (o, VCOrgNameProp)) {
+ org.name = g_strdup (str_val (vo));
+ free (the_str);
+ }
+ if (has (o, VCOrgUnitProp)) {
+ org.unit1 = g_strdup (str_val (vo));
+ free (the_str);
+ }
+ if (has (o, VCOrgUnit2Prop)) {
+ org.unit2 = g_strdup (str_val (vo));
+ free (the_str);
+ }
+ if (has (o, VCOrgUnit3Prop)) {
+ org.unit3 = g_strdup (str_val (vo));
+ free (the_str);
+ }
+ if (has (o, VCOrgUnit4Prop)) {
+ org.unit4 = g_strdup (str_val (vo));
+ free (the_str);
+ }
+
+ return org;
+}
+
+static CardXProperty *
+get_XProp (VObject *o)
+{
+ char *the_str;
+ CardXProperty *ret;
+
+ ret = malloc (sizeof (CardXProperty));
+ ret->name = g_strdup (vObjectName (o));
+ ret->data = g_strdup (str_val (o));
+ free (the_str);
+
+ return ret;
+}
+
+static CardRev
+strtoCardRev (char *str)
+{
+ char s[3], *t, *ss;
+ int len, i;
+ CardRev rev;
+
+ rev.utc = 0;
+ len = strlen (str);
+
+ if (str[len] == 'Z') { /* Is it UTC? */
+ rev.utc = 1;
+ str[len] = 0;
+ }
+
+ s[2] = 0;
+ t = strchr (str, 'T');
+ if (t) { /* Take the Time */
+ *t = 0;
+ t++;
+ if (strlen (t) > 2) {
+ s[0] = t[0];
+ s[1] = t[1];
+ rev.tm.tm_hour = atoi (s);
+ } else {
+ g_warning ("? < Rev value is too short.");
+ return rev;
+ }
+
+ t += 2;
+ if (*t == ':') /* Ignore ':' separator */
+ t++;
+
+ if (strlen (t) > 2) {
+ s[0] = t[0];
+ s[1] = t[1];
+ rev.tm.tm_min = atoi (s);
+ } else {
+ g_warning ("? < Rev value is too short.");
+ return rev;
+ }
+
+ t += 2;
+ if (*t == ':')
+ t++;
+
+ if (strlen (t) > 2) {
+ s[0] = t[0];
+ s[1] = t[1];
+ rev.tm.tm_sec = atoi (s);
+ } else {
+ g_warning ("? < Rev value is too short.");
+ return rev;
+ }
+
+ if (strlen (str) > 3)
+ g_warning ("? < Rev value is too long.");
+
+ } else {
+ g_warning ("? < No time value for Rev property.");
+ }
+
+ /* Now the date (the part before the T) */
+
+ if (strchr (str, '-')) { /* extended iso 8601 */
+ for (ss = strtok (str, "-"), i = 0; ss;
+ ss = strtok (NULL, "-"), i++)
+ switch (i) {
+ case 0:
+ rev.tm.tm_year = atoi (ss);
+ break;
+ case 1:
+ rev.tm.tm_mon = atoi (ss);
+ break;
+ case 2:
+ rev.tm.tm_mday = atoi (ss);
+ break;
+ default:
+ g_warning ("? < Too many values for Rev property.");
+ }
+
+ if (i < 2)
+ g_warning ("? < Too few values for Rev property.");
+ } else {
+ if (strlen (str) >= 8) { /* short representation */
+ rev.tm.tm_mday = atoi (str + 6);
+ str[6] = 0;
+ rev.tm.tm_mon = atoi (str + 4);
+ str[4] = 0;
+ rev.tm.tm_year = atoi (str);
+ } else
+ g_warning ("? < Bad format for Rev property.");
+ }
+
+ return rev;
+}
+
+static enum KeyType
+get_key_type (VObject *o)
+{
+ VObject *vo;
+ int i;
+
+ for (i = 0; key_pairs[i].str; i++)
+ if (has (o, key_pairs[i].str))
+ return key_pairs[i].id;
+
+ g_warning ("? < No KeyType for Key property. Falling back to PGP.");
+ return KEY_PGP;
+}
+
+static CardPhoto
+get_CardPhoto (VObject *o)
+{
+ VObject *vo;
+ char *the_str;
+ CardPhoto photo;
+
+ photo.type = get_photo_type (o);
+
+ if (has (o, VCDataSizeProp)) {
+ photo.size = vObjectIntegerValue (vo);
+ photo.data = malloc (photo.size);
+ memcpy (photo.data, vObjectAnyValue (o), photo.size);
+ } else {
+ photo.size = strlen (str_val (o)) + 1;
+ photo.data = g_strdup (the_str);
+ free (the_str);
+ }
+
+ return photo;
+}
+
+static enum SoundType
+get_sound_type (VObject *o)
+{
+ VObject *vo;
+ int i;
+
+ for (i = 0; sound_pairs[i].str; i++)
+ if (has (o, sound_pairs[i].str))
+ return sound_pairs[i].id;
+
+ return SOUND_PHONETIC;
+}
+
+static CardSound
+get_CardSound (VObject *o)
+{
+ VObject *vo;
+ char *the_str;
+ CardSound sound;
+
+ sound.type = get_sound_type (o);
+
+ if (has (o, VCDataSizeProp)) {
+ sound.size = vObjectIntegerValue (vo);
+ sound.data = malloc (sound.size);
+ memcpy (sound.data, vObjectAnyValue (o), sound.size);
+ } else {
+ sound.size = strlen (str_val (o));
+ sound.data = g_strdup (the_str);
+ free (the_str);
+ }
+
+ return sound;
+}
+
+/* Loads our card contents from a VObject */
+static ECard *
+e_card_construct_from_vobject (ECard *card,
+ VObject *vcrd)
+{
+ VObjectIterator i;
+ Card *crd;
+ char *the_str;
+
+ initPropIterator (&i, vcrd);
+ crd = card_new ();
+
+ while (moreIteration (&i)) {
+ VObject *o = nextVObject (&i);
+ const char *n = vObjectName (o);
+ int propid;
+ CardProperty *prop = NULL;
+
+ propid = card_lookup_name (n);
+
+ switch (propid) {
+ case PROP_FNAME:
+ prop = &crd->fname.prop;
+ crd->fname.str = g_strdup (str_val (o));
+ free (the_str);
+ break;
+ case PROP_NAME:
+ prop = &crd->name.prop;
+ crd->name = e_card_get_name (o);
+ break;
+ case PROP_PHOTO:
+ prop = &crd->photo.prop;
+ crd->photo = get_CardPhoto (o);
+ break;
+ case PROP_BDAY:
+ prop = &crd->bday.prop;
+ crd->bday = strtoCardBDay (str_val (o));
+ free (the_str);
+ break;
+ case PROP_DELADDR:
+ {
+ CardDelAddr *c;
+ c = get_CardDelAddr (o);
+ prop = &c->prop;
+ crd->deladdr.l = g_list_append (crd->deladdr.l, c);
+ }
+ break;
+ case PROP_DELLABEL:
+ {
+ CardDelLabel *c;
+ c = get_CardDelLabel (o);
+ prop = &c->prop;
+ crd->dellabel.l = g_list_append (crd->dellabel.l, c);
+ }
+ break;
+ case PROP_PHONE:
+ {
+ CardPhone *c;
+
+ c = get_CardPhone (o);
+ prop = &c->prop;
+ crd->phone.l = g_list_append (crd->phone.l, c);
+ }
+ break;
+ case PROP_EMAIL:
+ {
+ CardEMail *c;
+
+ c = get_CardEMail (o);
+ prop = &c->prop;
+ crd->email.l = g_list_append (crd->email.l, c);
+ }
+ break;
+ case PROP_MAILER:
+ prop = &crd->mailer.prop;
+ crd->mailer.str = g_strdup (str_val (o));
+ free (the_str);
+ break;
+ case PROP_TIMEZN:
+ prop = &crd->timezn.prop;
+ crd->timezn = strtoCardTimeZone (str_val (o));
+ free (the_str);
+ break;
+ case PROP_GEOPOS:
+ prop = &crd->geopos.prop;
+ crd->geopos = strtoCardGeoPos (str_val (o));
+ break;
+ case PROP_TITLE:
+ prop = &crd->title.prop;
+ crd->title.str = g_strdup (str_val (o));
+ free (the_str);
+ break;
+ case PROP_ROLE:
+ prop = &crd->role.prop;
+ crd->role.str = g_strdup (str_val (o));
+ free (the_str);
+ break;
+ case PROP_LOGO:
+ prop = &crd->logo.prop;
+ crd->logo = get_CardPhoto (o);
+ break;
+ case PROP_AGENT:
+ crd->agent = card_create_from_vobject (o);
+ break;
+ case PROP_ORG:
+ prop = &crd->org.prop;
+ crd->org = get_CardOrg (o);
+ break;
+ case PROP_CATEGORIES:
+ prop = &crd->categories.prop;
+ crd->categories.str = g_strdup (str_val (o));
+ crd->categories.prop.encod = ENC_QUOTED_PRINTABLE;
+ free (the_str);
+ break;
+ case PROP_COMMENT:
+ prop = &crd->comment.prop;
+ crd->comment.str = g_strdup (str_val (o));
+ crd->comment.prop.encod = ENC_QUOTED_PRINTABLE;
+ free (the_str);
+ break;
+ case PROP_REV:
+ prop = &crd->rev.prop;
+ crd->rev = strtoCardRev (str_val (o));
+ free (the_str);
+ break;
+ case PROP_SOUND:
+ prop = &crd->sound.prop;
+ crd->sound = get_CardSound (o);
+ break;
+ case PROP_URL:
+ prop = &crd->url.prop;
+ crd->url.str = g_strdup (str_val (o));
+ free (the_str);
+ break;
+ case PROP_UID:
+ prop = &crd->uid.prop;
+ crd->uid.str = g_strdup (str_val (o));
+ free (the_str);
+ break;
+ case PROP_VERSION:
+ {
+ char *str;
+ str = str_val (o);
+ if (strcmp (str, "2.1"))
+ g_warning ("? < Version doesn't match.");
+ free (the_str);
+ }
+ break;
+ case PROP_KEY:
+ prop = &crd->key.prop;
+ crd->key.type = get_key_type (o);
+ crd->key.data = g_strdup (str_val (o));
+ free (the_str);
+ break;
+ default:
+ {
+ CardXProperty *c;
+
+ c = get_XProp (o);
+ prop = &c->prop;
+ crd->xtension.l = g_list_append (crd->xtension.l, c);
+ }
+ break;
+ }
+
+ if (prop) {
+ *prop = get_CardProperty (o);
+ prop->type = propid;
+ }
+ }
+
+ return crd;
+}
+
+/* Loads a card from a file */
+GList *
+card_load (GList *crdlist, char *fname)
+{
+ VObject *vobj, *tmp;
+
+ vobj = Parse_MIME_FromFileName (fname);
+ if (!vobj) {
+ g_warning ("Could not load the cardfile");
+ return NULL;
+ }
+
+ while (vobj) {
+ const char *n = vObjectName (vobj);
+
+ if (strcmp (n, VCCardProp) == 0) {
+ crdlist = g_list_append (crdlist, (gpointer)
+ card_create_from_vobject (vobj));
+ }
+ tmp = vobj;
+ vobj = nextVObjectInList (vobj);
+ cleanVObject (tmp);
+ }
+
+ cleanVObject (vobj);
+ cleanStrTbl ();
+ return crdlist;
+}
+
+static VObject *
+add_strProp (VObject *o, const char *id, char *val)
+{
+ VObject *vo = NULL;
+
+ if (val)
+ vo = addPropValue (o, id, val);
+
+ return vo;
+}
+
+static VObject *
+add_CardProperty (VObject *o, CardProperty *prop)
+{
+ GList *node;
+
+ switch (prop->encod) {
+ case ENC_BASE64:
+ addProp (o, VCBase64Prop);
+ break;
+ case ENC_QUOTED_PRINTABLE:
+ addProp (o, VCQuotedPrintableProp);
+ break;
+ case ENC_8BIT:
+ addProp (o, VC8bitProp);
+ break;
+ case ENC_7BIT:
+ /* Do nothing: 7BIT is the default. Avoids file clutter. */
+ break;
+ default:
+ g_warning ("? < Card had invalid encoding type.");
+ }
+
+ switch (prop->value) {
+ case VAL_CID:
+ addProp (o, VCContentIDProp);
+ break;
+ case VAL_URL:
+ addProp (o, VCURLValueProp);
+ break;
+ case VAL_INLINE:
+ /* Do nothing: INLINE is the default. Avoids file clutter. */
+ break;
+ default:
+ g_warning ("? < Card had invalid value type.");
+ }
+
+ for (node = prop->xtension; node; node = node->next) {
+ CardXAttribute *xa = (CardXAttribute *) node->data;
+ if (xa->data)
+ addPropValue (o, xa->name, xa->data);
+ else
+ addProp (o, xa->name);
+ }
+
+ add_strProp (o, VCCharSetProp, prop->charset);
+ add_strProp (o, VCLanguageProp, prop->lang);
+
+ return o;
+}
+
+static VObject *
+add_CardStrProperty (VObject *vobj, const char *id, CardStrProperty *strprop)
+{
+ VObject *vprop;
+
+ if (strprop->prop.used) {
+ vprop = add_strProp (vobj, id, strprop->str);
+ add_CardProperty (vprop, &strprop->prop);
+ }
+
+ return vobj;
+}
+
+static VObject *
+add_PhotoType (VObject *o, enum PhotoType photo_type)
+{
+ int i;
+
+ for (i = 0; photo_pairs[i].str; i++)
+ if (photo_type == photo_pairs[i].id) {
+ addProp (o, photo_pairs[i].str);
+ return o;
+ }
+
+ g_warning ("? > No PhotoType for Photo property. Falling back to JPEG.");
+ addProp (o, VCJPEGProp);
+
+ return o;
+}
+
+static VObject *
+add_AddrType (VObject *o, int addr_type)
+{
+ int i;
+
+ for (i = 0; addr_pairs[i].str; i++)
+ if (addr_type & addr_pairs[i].id)
+ addProp (o, addr_pairs[i].str);
+
+ return o;
+}
+
+static void
+add_strAddrType (GString *string, int addr_type)
+{
+ int i, first = 1;
+ char *str;
+
+ if (addr_type) {
+ g_string_append (string, " (");
+
+ for (i = 0; addr_pairs[i].str; i++)
+ if (addr_type & addr_pairs[i].id) {
+ if (!first)
+ g_string_append (string, ", ");
+ first = 0;
+ str = my_cap (addr_pairs[i].str);
+ g_string_append (string, str);
+ g_free (str);
+ }
+
+ g_string_append_c (string, ')');
+ }
+}
+
+static VObject *
+add_PhoneType (VObject *o, int phone_type)
+{
+ int i;
+
+ for (i = 0; phone_pairs[i].str; i++)
+ if (phone_type & phone_pairs[i].id)
+ addProp (o, phone_pairs[i].str);
+
+ return o;
+}
+
+static void
+add_strPhoneType (GString *string, int phone_type)
+{
+ int i, first = 1;
+ char *str;
+
+ if (phone_type) {
+ g_string_append (string, " (");
+
+ for (i = 0; phone_pairs[i].str; i++)
+ if (phone_type & phone_pairs[i].id) {
+ if (!first)
+ g_string_append (string, ", ");
+ first = 0;
+ str = my_cap (phone_pairs[i].str);
+ g_string_append (string, str);
+ g_free (str);
+ }
+
+ g_string_append_c (string, ')');
+ }
+}
+
+static VObject *
+add_EMailType (VObject *o, enum EMailType email_type)
+{
+ int i;
+
+ for (i = 0; email_pairs[i].str; i++)
+ if (email_type == email_pairs[i].id) {
+ addProp (o, email_pairs[i].str);
+ return o;
+ }
+
+ g_warning ("? > No EMailType for EMail property. Falling back to INET.");
+ addProp (o, VCInternetProp);
+
+ return o;
+}
+
+static void
+add_strEMailType (GString *string, int email_type)
+{
+ int i;
+ char *str;
+
+ if (email_type) {
+ g_string_append (string, " (");
+
+ for (i = 0; email_pairs[i].str; i++)
+ if (email_type == email_pairs[i].id) {
+ str = my_cap (email_pairs[i].str);
+ g_string_append (string, str);
+ g_free (str);
+ break;
+ }
+
+ g_string_append_c (string, ')');
+ }
+}
+
+static VObject *
+add_KeyType (VObject *o, enum KeyType key_type)
+{
+ int i;
+
+ for (i = 0; key_pairs[i].str; i++)
+ if (key_type == key_pairs[i].id) {
+ addProp (o, key_pairs[i].str);
+ return o;
+ }
+
+ g_warning ("? > No KeyType for Key property. Falling back to PGP.");
+ addProp (o, VCPGPProp);
+
+ return o;
+}
+
+static void
+add_strKeyType (GString *string, int key_type)
+{
+ int i;
+ char *str;
+
+ if (key_type) {
+ g_string_append (string, " (");
+
+ for (i = 0; key_pairs[i].str; i++)
+ if (key_type == key_pairs[i].id) {
+ str = my_cap (key_pairs[i].str);
+ g_string_append (string, str);
+ g_free (str);
+ break;
+ }
+
+ g_string_append_c (string, ')');
+ }
+}
+
+static VObject *
+add_SoundType (VObject *o, enum SoundType sound_type)
+{
+ int i;
+
+ for (i = 0; sound_pairs[i].str; i++)
+ if (sound_type == sound_pairs[i].id) {
+ addProp (o, sound_pairs[i].str);
+ return o;
+ }
+
+ return o;
+}
+
+char *card_bday_str (CardBDay bday)
+{
+ char *str;
+
+ str = malloc (12);
+ snprintf (str, 12, "%04d-%02d-%02d", bday.year, bday.month, bday.day);
+
+ return str;
+}
+
+char *card_timezn_str (CardTimeZone timezn)
+{
+ char *str;
+
+ str = malloc (7);
+ snprintf (str, 7, (timezn.sign == -1)? "-%02d:%02d" : "%02d:%02d",
+ timezn.hours, timezn.mins);
+ return str;
+}
+
+char *card_geopos_str (CardGeoPos geopos)
+{
+ char *str;
+
+ str = malloc (15);
+ snprintf (str, 15, "%03.02f,%03.02f", geopos.lon, geopos.lat);
+ return str;
+}
+
+
+static VObject *
+card_convert_to_vobject (Card *crd)
+{
+ VObject *vobj, *vprop;
+
+ vobj = newVObject (VCCardProp);
+
+ add_CardStrProperty (vobj, VCFullNameProp, &crd->fname);
+ if (crd->name.prop.used) {
+ vprop = addProp (vobj, VCNameProp);
+ add_strProp (vprop, VCFamilyNameProp, crd->name.family);
+ add_strProp (vprop, VCGivenNameProp, crd->name.given);
+ add_strProp (vprop, VCAdditionalNamesProp, crd->name.additional);
+ add_strProp (vprop, VCNamePrefixesProp, crd->name.prefix);
+ add_strProp (vprop, VCNameSuffixesProp, crd->name.suffix);
+ add_CardProperty (vprop, &crd->name.prop);
+ }
+
+ if (crd->photo.prop.used) {
+ vprop = addPropSizedValue (vobj, VCPhotoProp,
+ crd->photo.data, crd->photo.size);
+ add_PhotoType (vprop, crd->photo.type);
+ add_CardProperty (vprop, &crd->photo.prop);
+ }
+
+ if (crd->bday.prop.used) {
+ char *date_str;
+
+ date_str = card_bday_str (crd->bday);
+ vprop = addPropValue (vobj, VCBirthDateProp, date_str);
+ free (date_str);
+ add_CardProperty (vprop, &crd->bday.prop);
+ }
+
+ if (crd->xtension.l) {
+ GList *node;
+
+ for (node = crd->xtension.l; node; node = node->next) {
+ CardXProperty *xp = (CardXProperty *) node->data;
+ addPropValue (vobj, xp->name, xp->data);
+ add_CardProperty (vobj, &xp->prop);
+ }
+ }
+
+
+ if (crd->deladdr.l) {
+ GList *node;
+
+ for (node = crd->deladdr.l; node; node = node->next) {
+ CardDelAddr *deladdr = (CardDelAddr *) node->data;
+
+ if (deladdr->prop.used) {
+ vprop = addProp (vobj, VCAdrProp);
+ add_AddrType (vprop, deladdr->type);
+ add_strProp (vprop, VCPostalBoxProp, deladdr->po);
+ add_strProp (vprop, VCExtAddressProp,deladdr->ext);
+ add_strProp (vprop, VCStreetAddressProp,deladdr->street);
+ add_strProp (vprop, VCCityProp, deladdr->city);
+ add_strProp (vprop, VCRegionProp, deladdr->region);
+ add_strProp (vprop, VCPostalCodeProp, deladdr->code);
+ add_strProp (vprop, VCCountryNameProp, deladdr->country);
+ add_CardProperty (vprop, &deladdr->prop);
+ }
+ }
+ }
+
+ if (crd->dellabel.l) {
+ GList *node;
+
+ for (node = crd->dellabel.l; node; node = node->next) {
+ CardDelLabel *dellabel = (CardDelLabel *) node->data;
+
+ vprop = add_strProp (vobj, VCDeliveryLabelProp,
+ dellabel->data);
+ add_AddrType (vprop, dellabel->type);
+ add_CardProperty (vprop, &dellabel->prop);
+ }
+ }
+
+ if (crd->phone.l) {
+ GList *node;
+
+ for (node = crd->phone.l; node; node = node->next) {
+ CardPhone *phone = (CardPhone *) node->data;
+
+ if (phone->prop.used) {
+ vprop = add_strProp (vobj, VCTelephoneProp,
+ (phone->data)?
+ phone->data: "");
+ add_PhoneType (vprop, phone->type);
+ add_CardProperty (vprop, &phone->prop);
+ }
+ }
+ }
+
+ if (crd->email.l) {
+ GList *node;
+
+ for (node = crd->email.l; node; node = node->next) {
+ CardEMail *email = (CardEMail *) node->data;
+
+ if (email->prop.used) {
+ vprop = add_strProp (vobj, VCEmailAddressProp,
+ email->data);
+ add_EMailType (vprop, email->type);
+ add_CardProperty (vprop, &email->prop);
+ }
+ }
+ }
+
+ add_CardStrProperty (vobj, VCMailerProp, &crd->mailer);
+
+ if (crd->timezn.prop.used) {
+ char *str;
+
+ str = card_timezn_str (crd->timezn);
+ vprop = addPropValue (vobj, VCTimeZoneProp, str);
+ free (str);
+ add_CardProperty (vprop, &crd->timezn.prop);
+ }
+
+ if (crd->geopos.prop.used) {
+ char *str;
+
+ str = card_geopos_str (crd->geopos);
+ vprop = addPropValue (vobj, VCGeoLocationProp, str);
+ free (str);
+ add_CardProperty (vprop, &crd->geopos.prop);
+ }
+
+ add_CardStrProperty (vobj, VCTitleProp, &crd->title);
+ add_CardStrProperty (vobj, VCBusinessRoleProp, &crd->role);
+
+ if (crd->logo.prop.used) {
+ vprop = addPropSizedValue (vobj, VCLogoProp,
+ crd->logo.data, crd->logo.size);
+ add_PhotoType (vprop, crd->logo.type);
+ add_CardProperty (vprop, &crd->logo.prop);
+ }
+
+ if (crd->agent)
+ addVObjectProp (vobj, card_convert_to_vobject (crd->agent));
+
+ if (crd->org.prop.used) {
+ vprop = addProp (vobj, VCOrgProp);
+ add_strProp (vprop, VCOrgNameProp, crd->org.name);
+ add_strProp (vprop, VCOrgUnitProp, crd->org.unit1);
+ add_strProp (vprop, VCOrgUnit2Prop, crd->org.unit2);
+ add_strProp (vprop, VCOrgUnit3Prop, crd->org.unit3);
+ add_strProp (vprop, VCOrgUnit4Prop, crd->org.unit4);
+ add_CardProperty (vprop, &crd->org.prop);
+ }
+
+ add_CardStrProperty (vobj, VCCategoriesProp, &crd->categories);
+ add_CardStrProperty (vobj, VCCommentProp, &crd->comment);
+
+ if (crd->sound.prop.used) {
+ if (crd->sound.type != SOUND_PHONETIC)
+ vprop = addPropSizedValue (vobj, VCPronunciationProp,
+ crd->sound.data, crd->sound.size);
+ else
+ vprop = addPropValue (vobj, VCPronunciationProp,
+ crd->sound.data);
+
+ add_SoundType (vprop, crd->sound.type);
+ add_CardProperty (vprop, &crd->sound.prop);
+ }
+
+ add_CardStrProperty (vobj, VCURLProp, &crd->url);
+ add_CardStrProperty (vobj, VCUniqueStringProp, &crd->uid);
+
+ if (crd->key.prop.used) {
+ vprop = addPropValue (vobj, VCPublicKeyProp, crd->key.data);
+ add_KeyType (vprop, crd->key.type);
+ add_CardProperty (vprop, &crd->key.prop);
+ }
+
+ return vobj;
+}
+
+static void add_CardStrProperty_to_string (GString *string, char *prop_name,
+ CardStrProperty *strprop)
+{
+ if (strprop->prop.used) {
+ if (prop_name)
+ g_string_append (string, prop_name);
+
+ g_string_append (string, strprop->str);
+ }
+}
+
+static void add_strProp_to_string (GString *string, char *prop_name, char *val)
+{
+ if (val) {
+ if (prop_name)
+ g_string_append (string, prop_name);
+
+ g_string_append (string, val);
+ }
+}
+
+static void addProp_to_string (GString *string, char *prop_name)
+{
+ if (prop_name)
+ g_string_append (string, prop_name);
+}
+
+char *
+card_to_string (Card *crd)
+{
+ GString *string;
+ char *ret;
+
+ string = g_string_new ("");
+
+ add_CardStrProperty_to_string (string, _ ("Card: "), &crd->fname);
+ if (crd->name.prop.used) {
+ addProp_to_string (string, _ ("\nName: "));
+ add_strProp_to_string (string, _ ("\n Prefix: "), crd->name.prefix);
+ add_strProp_to_string (string, _ ("\n Given: "), crd->name.given);
+ add_strProp_to_string (string, _ ("\n Additional: "), crd->name.additional);
+ add_strProp_to_string (string, _ ("\n Family: "), crd->name.family);
+ add_strProp_to_string (string, _ ("\n Suffix: "), crd->name.suffix);
+ g_string_append_c (string, '\n');
+ }
+
+/* if (crd->photo.prop.used) {
+ addPropSizedValue (string, _ ("\nPhoto: "),
+ crd->photo.data, crd->photo.size);
+ add_PhotoType (string, crd->photo.type);
+ }*/
+
+ if (crd->bday.prop.used) {
+ char *date_str;
+
+ date_str = card_bday_str (crd->bday);
+ add_strProp_to_string (string, _ ("\nBirth Date: "), date_str);
+ free (date_str);
+ }
+
+ if (crd->deladdr.l) {
+ GList *node;
+
+ for (node = crd->deladdr.l; node; node = node->next) {
+ CardDelAddr *deladdr = (CardDelAddr *) node->data;
+
+ if (deladdr->prop.used) {
+ addProp_to_string (string, _ ("\nAddress:"));
+ add_strAddrType (string, deladdr->type);
+ add_strProp_to_string (string, _ ("\n Postal Box: "), deladdr->po);
+ add_strProp_to_string (string, _ ("\n Ext: "),deladdr->ext);
+ add_strProp_to_string (string, _ ("\n Street: "),deladdr->street);
+ add_strProp_to_string (string, _ ("\n City: "), deladdr->city);
+ add_strProp_to_string (string, _ ("\n Region: "), deladdr->region);
+ add_strProp_to_string (string, _ ("\n Postal Code: "), deladdr->code);
+ add_strProp_to_string (string, _ ("\n Country: "), deladdr->country);
+ }
+ }
+
+ g_string_append_c (string, '\n');
+ }
+
+ if (crd->dellabel.l) {
+ GList *node;
+
+ for (node = crd->dellabel.l; node; node = node->next) {
+ CardDelLabel *dellabel = (CardDelLabel *) node->data;
+
+ add_strProp_to_string (string, _ ("\nDelivery Label: "),
+ dellabel->data);
+ add_strAddrType (string, dellabel->type);
+ }
+ }
+
+ if (crd->phone.l) {
+ GList *node;
+ char *sep;
+
+ if (crd->phone.l->next) {
+ sep = " ";
+ g_string_append (string, _ ("\nTelephones:\n"));
+ } else {
+ sep = " ";
+ g_string_append (string, _ ("\nTelephone:"));
+ }
+
+ for (node = crd->phone.l; node; node = node->next) {
+ CardPhone *phone = (CardPhone *) node->data;
+
+ if (phone->prop.used) {
+ g_string_append (string, sep);
+ g_string_append (string, phone->data);
+ add_strPhoneType (string, phone->type);
+ g_string_append_c (string, '\n');
+ }
+ }
+
+ if (crd->phone.l->next)
+ g_string_append_c (string, '\n');
+ }
+
+ if (crd->email.l) {
+ GList *node;
+ char *sep;
+
+ if (crd->email.l->next) {
+ sep = " ";
+ g_string_append (string, _ ("\nE-mail:\n"));
+ } else {
+ sep = " ";
+ g_string_append (string, _ ("\nE-mail:"));
+ }
+
+
+ for (node = crd->email.l; node; node = node->next) {
+ CardEMail *email = (CardEMail *) node->data;
+
+ if (email->prop.used) {
+ g_string_append (string, sep);
+ g_string_append (string, email->data);
+ add_strEMailType (string, email->type);
+ g_string_append_c (string, '\n');
+ }
+ }
+
+ if (crd->email.l->next)
+ g_string_append_c (string, '\n');
+ }
+
+ add_CardStrProperty_to_string (string, _ ("\nMailer: "), &crd->mailer);
+
+ if (crd->timezn.prop.used) {
+ char *str;
+
+ str = card_timezn_str (crd->timezn);
+ add_strProp_to_string (string, _ ("\nTime Zone: "), str);
+ free (str);
+ }
+
+ if (crd->geopos.prop.used) {
+ char *str;
+
+ str = card_geopos_str (crd->geopos);
+ add_strProp_to_string (string, _ ("\nGeo Location: "), str);
+ free (str);
+ }
+
+ add_CardStrProperty_to_string (string, _ ("\nTitle: "), &crd->title);
+ add_CardStrProperty_to_string (string, _ ("\nBusiness Role: "), &crd->role);
+
+/* if (crd->logo.prop.used) {
+ addPropSizedValue (string, _ ("\nLogo: "),
+ crd->logo.data, crd->logo.size);
+ add_PhotoType (string, crd->logo.type);
+ }*/
+
+/* if (crd->agent)
+ addstringectProp (string, card_convert_to_stringect (crd->agent));*/
+
+ if (crd->org.prop.used) {
+ addProp_to_string (string, _ ("\nOrg: "));
+ add_strProp_to_string (string, _ ("\n Name: "), crd->org.name);
+ add_strProp_to_string (string, _ ("\n Unit: "), crd->org.unit1);
+ add_strProp_to_string (string, _ ("\n Unit2: "), crd->org.unit2);
+ add_strProp_to_string (string, _ ("\n Unit3: "), crd->org.unit3);
+ add_strProp_to_string (string, _ ("\n Unit4: "), crd->org.unit4);
+ g_string_append_c (string, '\n');
+ }
+
+ add_CardStrProperty_to_string (string, _ ("\nCategories: "), &crd->categories);
+ add_CardStrProperty_to_string (string, _ ("\nComment: "), &crd->comment);
+
+/* if (crd->sound.prop.used) {
+ if (crd->sound.type != SOUND_PHONETIC)
+ addPropSizedValue (string, _ ("\nPronunciation: "),
+ crd->sound.data, crd->sound.size);
+ else
+ add_strProp_to_string (string, _ ("\nPronunciation: "),
+ crd->sound.data);
+
+ add_SoundType (string, crd->sound.type);
+ }*/
+
+ add_CardStrProperty_to_string (string, _ ("\nURL: "), &crd->url);
+ add_CardStrProperty_to_string (string, _ ("\nUnique String: "), &crd->uid);
+
+ if (crd->key.prop.used) {
+ add_strProp_to_string (string, _ ("\nPublic Key: "), crd->key.data);
+ add_strKeyType (string, crd->key.type);
+ }
+
+ ret = g_strdup (string->str);
+ g_string_free (string, TRUE);
+
+ return ret;
+}
+
+char *
+card_to_vobj_string (Card *crd)
+{
+ VObject *object;
+ char *data, *ret_val;
+
+ g_assert (crd != NULL);
+
+ object = card_convert_to_vobject (crd);
+ data = writeMemVObject (0, 0, object);
+ ret_val = g_strdup (data);
+ free (data);
+
+ cleanVObject (object);
+
+ return ret_val;
+}
+
+void
+card_save (Card *crd, FILE *fp)
+{
+ VObject *object;
+
+ g_return_if_fail (crd != NULL);
+
+ object = card_convert_to_vobject (crd);
+ writeVObject (fp, object);
+ cleanVObject (object);
+}