]> git.deb.at Git - pkg/abook.git/commitdiff
Import vCard file format.
authorMichael Krolikowski <mkroli@yahoo.de>
Thu, 5 Jan 2012 22:20:57 +0000 (23:20 +0100)
committerRaphaël Droz <raphael.droz+floss@gmail.com>
Sat, 5 May 2012 16:33:52 +0000 (18:33 +0200)
filter.c
misc.c
misc.h

index 6946f9a5da0fbe6ac685bb411562530a9ecb99f2..b70d918b181237ab331d612d64788bc49bc04610 100644 (file)
--- a/filter.c
+++ b/filter.c
@@ -44,6 +44,7 @@ static int    pine_parse_file(FILE *in);
 static int     csv_parse_file(FILE *in);
 static int     allcsv_parse_file(FILE *in);
 static int     palmcsv_parse_file(FILE *in);
+static int     vcard_parse_file(FILE *in);
 
 /*
  * export filter prototypes
@@ -75,6 +76,7 @@ struct abook_input_filter i_filters[] = {
        { "csv", N_("comma separated values"), csv_parse_file },
        { "allcsv", N_("comma separated values (all fields)"), allcsv_parse_file },
        { "palmcsv", N_("Palm comma separated values"), palmcsv_parse_file },
+       { "vcard", N_("vCard file"), vcard_parse_file },
        { "\0", NULL, NULL }
 };
 
@@ -1330,6 +1332,262 @@ palmcsv_parse_file(FILE *in)
  * end of csv import filter
  */
 
+/*
+ * vCard import filter
+ */
+
+static char *vcard_fields[] = {
+       "FN",                   /* NAME */
+       "EMAIL",                /* EMAIL */
+       "ADR",                  /* ADDRESS */
+       "ADR",                  /* ADDRESS2 - not used */
+       "ADR",                  /* CITY */
+       "ADR",                  /* STATE */
+       "ADR",                  /* ZIP */
+       "ADR",                  /* COUNTRY */
+       "TEL",                  /* PHONE */
+       "TEL",                  /* WORKPHONE */
+       "TEL",                  /* FAX */
+       "TEL",                  /* MOBILEPHONE */
+       "NICKNAME",             /* NICK */
+       "URL",                  /* URL */
+       "NOTE",                 /* NOTES */
+       NULL                    /* not implemented: ANNIVERSARY, ITEM_FIELDS */
+};
+
+/*
+ * mappings between vCard ADR field and abook's ADDRESS
+ * see rfc2426 section 3.2.1
+ */
+static int vcard_address_fields[] = {
+       -1,                     /* vCard(post office box) - not used */
+       -1,                     /* vCard(the extended address) - not used */
+       2,                      /* vCard(the street address) - ADDRESS */
+       4,                      /* vCard(the locality) - CITY */
+       5,                      /* vCard(the region) - STATE */
+       6,                      /* vCard(the postal code) - ZIP */
+       7                       /* vCard(the country name) - COUNTRY */
+};
+
+enum {
+       VCARD_KEY = 0,
+       VCARD_KEY_ATTRIBUTE,
+       VCARD_VALUE,
+};
+
+static char *
+vcard_get_line_element(char *line, int element)
+{
+       int i;
+       char *line_copy = 0;
+       char *result = 0;
+       char *key = 0;
+       char *key_attr = 0;
+       char *value = 0;
+
+       line_copy = xstrdup(line);
+
+       /* make newline characters if exist end of string */
+       for(i=0; line_copy[i]; i++) {
+               if(line_copy[i] == '\r' || line_copy[i] == '\n') {
+                       line_copy[i] = '\0';
+                       break;
+               }
+       }
+
+       /* separate key from value */
+       for(i=0; line_copy[i]; i++) {
+               if(line_copy[i] == ':') {
+                       line_copy[i] = '\0';
+                       key = line_copy;
+                       value = &line_copy[i+1];
+                       break;
+               }
+       }
+
+       /* separate key from key attributes */
+       if (key) {
+               for(i=0; key[i]; i++) {
+                       if(key[i] == ';') {
+                               key[i] = '\0';
+                               key_attr = &key[i+1];
+                               break;
+                       }
+               }
+       }
+
+       switch(element) {
+       case VCARD_KEY:
+               if(key)
+                       result = xstrdup(key);
+               break;
+       case VCARD_KEY_ATTRIBUTE:
+               if(key_attr)
+                       result = xstrdup(key_attr);
+               break;
+       case VCARD_VALUE:
+               if(value)
+                       result = xstrdup(value);
+               break;
+       }
+
+       xfree(line_copy);
+       return result;
+}
+
+static void
+vcard_parse_email(list_item item, char *line)
+{
+       char *email;
+
+       email = vcard_get_line_element(line, VCARD_VALUE);
+
+       if(item[1]) {
+               item[1] = strconcat(item[1], ",", email, 0);
+               xfree(email);
+       }
+       else {
+               item[1] = email;
+       }
+}
+
+static void
+vcard_parse_address(list_item item, char *line)
+{
+       int i;
+       int k;
+       char *value;
+       char *address_field;
+
+       value = vcard_get_line_element(line, VCARD_VALUE);
+       if(!value)
+               return;
+
+       address_field = value;
+       for(i=k=0; value[i]; i++) {
+               if(value[i] == ';') {
+                       value[i] = '\0';
+                       if(vcard_address_fields[k] >= 0) {
+                               item[vcard_address_fields[k]] = xstrdup(address_field);
+                       }
+                       address_field = &value[i+1];
+                       k++;
+                       if((k+1)==(sizeof(vcard_address_fields)/sizeof(*vcard_address_fields)))
+                               break;
+               }
+       }
+       item[vcard_address_fields[k]] = xstrdup(address_field);
+       xfree(value);
+}
+
+static void
+vcard_parse_phone(list_item item, char *line)
+{
+       int index = 8;
+       char *type = vcard_get_line_element(line, VCARD_KEY_ATTRIBUTE);
+       char *value = vcard_get_line_element(line, VCARD_VALUE);
+
+       /* set the standard number */
+       if (!type) {
+               item[index] = value;
+       }
+
+       /*
+        * see rfc2426 section 3.3.1
+        */
+       else if (strstr(type, "TYPE=") == type){
+               if (strcasestr(type, "home")) {
+                       item[index] = xstrdup(value);
+               }
+               if (strcasestr(type, "work")) {
+                       item[index+1] = xstrdup(value);
+               }
+               if (strcasestr(type, "fax")) {
+                       item[index+2] = xstrdup(value);
+               }
+               if (strcasestr(type, "cell")) {
+                       item[index+3] = xstrdup(value);
+               }
+
+               xfree(type);
+               xfree(value);
+       }
+}
+
+static void
+vcard_parse_line(list_item item, char *line)
+{
+       int i;
+       char *key;
+
+       for(i=0; vcard_fields[i]; i++) {
+               key = vcard_fields[i];
+
+               if(!strncmp(key, line, strlen(key))) {
+                       if(i == 1) {
+                               vcard_parse_email(item, line);
+                       }
+                       else if(i == 2) {
+                               vcard_parse_address(item, line);
+                       }
+                       else if(i == 8) {
+                               vcard_parse_phone(item, line);
+                       }
+                       else {
+                               item[i] = vcard_get_line_element(line, VCARD_VALUE);
+                       }
+                       break;
+               }
+       }
+}
+
+static void
+vcard_parse_item(FILE *in)
+{
+       char *line = NULL;
+       list_item item = item_create();
+
+       while(!feof(in)) {
+               line = getaline(in);
+
+               if(line && !strncmp("END:VCARD", line, 9)) {
+                       xfree(line);
+                       break;
+               }
+               else if(line) {
+                       vcard_parse_line(item, line);
+                       xfree(line);
+               }
+       }
+
+       add_item2database(item);
+       item_free(&item);
+}
+
+static int
+vcard_parse_file(FILE *in)
+{
+       char *line = NULL;
+
+       while(!feof(in)) {
+               line = getaline(in);
+
+               if(line && !strncmp("BEGIN:VCARD", line, 11)) {
+                       xfree(line);
+                       vcard_parse_item(in);
+               }
+               else if(line) {
+                       xfree(line);
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * end of vCard import filter
+ */
+
 /*
  * csv addressbook export filters
  */
diff --git a/misc.c b/misc.c
index f72475da74287ffee67c43666fc49e6a91dc7283..308c196c31f6ad3364ece033cc5905b2dd5b58d6 100644 (file)
--- a/misc.c
+++ b/misc.c
@@ -77,6 +77,27 @@ is_number(char *p)
        return 1;
 }
 
+char *
+strcasestr(char *haystack, char *needle)
+{
+       int i;
+       int k;
+
+       assert(haystack != NULL);
+       assert(needle != NULL);
+
+       for(i=0; i<strlen(haystack)-strlen(needle)+1; i++) {
+               for(k=0; k<strlen(needle); k++, i++) {
+                       if (tolower(haystack[i]) != tolower(needle[k]))
+                               break;
+                       else if ((k+1) == strlen(needle))
+                               return &haystack[i];
+               }
+       }
+
+       return NULL;
+}
+
 
 #ifdef HAVE_CONFIG_H
 #      include "config.h"
diff --git a/misc.h b/misc.h
index fadd0ae072717bf2c31506dfdc0b1fd537f2a284..c5f7ac1ba3acdacfb220afb6489ead8c8b462f1c 100644 (file)
--- a/misc.h
+++ b/misc.h
@@ -18,6 +18,8 @@ char          *strtrim(char *);
 
 int            is_number(char *s);
 
+char           *strcasestr(char *haystack, char *needle);
+
 char           *strdup_printf(const char *format, ... );
 char           *strconcat(const char *str, ...);