+#define CSV_COMMENT_CHAR '#'
+#define CSV_DUPLICATE_SEPARATOR " "
+#define CSV_TABLE_SIZE(t) (sizeof (t) / sizeof *(t))
+
+static int csv_conv_table[] = {
+ NAME,
+ EMAIL,
+ PHONE,
+ NOTES,
+ NICK
+};
+
+static int allcsv_conv_table[] = {
+ NAME,
+ EMAIL,
+ ADDRESS,
+ ADDRESS2,
+ CITY,
+ STATE,
+ ZIP,
+ COUNTRY,
+ PHONE,
+ WORKPHONE,
+ FAX,
+ MOBILEPHONE,
+ NICK,
+ URL,
+ NOTES,
+ ANNIVERSARY
+};
+
+static int palmcsv_conv_table[] = {
+ NAME, /* Last name */
+ NAME, /* First name */
+ NOTES, /* Title */
+ NICK, /* Company */
+ WORKPHONE,
+ PHONE,
+ FAX,
+ MOBILEPHONE,
+ EMAIL,
+ ADDRESS,
+ CITY,
+ STATE,
+ ZIP,
+ COUNTRY,
+ ANNIVERSARY,
+};
+
+static void
+csv_convert_emails(char *s)
+{
+ int i;
+ char *tmp;
+
+ if(s == NULL)
+ return;
+
+ for(i = 1; ( tmp = strchr(s, ',') ) != NULL ; i++, s = tmp + 1)
+ if(i > MAX_LIST_ITEMS - 1) {
+ *tmp = 0;
+ break;
+ }
+
+}
+
+static char *
+csv_remove_quotes(char *s)
+{
+ char *copy, *trimmed;
+ int len;
+
+ copy = trimmed = xstrdup(s);
+ strtrim(trimmed);
+
+ len = strlen(trimmed);
+ if(trimmed[len - 1] == '\"' && *trimmed == '\"') {
+ if(len < 3) {
+ xfree(copy);
+ return NULL;
+ }
+ trimmed[len - 1] = 0;
+ trimmed++;
+ trimmed = xstrdup(trimmed);
+ free(copy);
+ return trimmed;
+ }
+
+ xfree(copy);
+ return xstrdup(s);
+}
+
+static int
+csv_field_to_item(int *table_base, size_t table_size, int field)
+{
+ if(field < table_size)
+ return field_id(table_base[field]);
+
+ return -1;
+}
+
+static void
+csv_store_item(list_item item, int i, char *s)
+{
+ char *newstr = NULL;
+
+ if(!s || !*s)
+ return;
+
+ if( !(newstr = csv_remove_quotes(s)) )
+ return;
+
+ if(i >= 0) {
+ if (item[i] != NULL) {
+ char *oldstr = item[i];
+
+ item[i] = strconcat(newstr, CSV_DUPLICATE_SEPARATOR,
+ oldstr, NULL);
+ xfree(newstr);
+ xfree(oldstr);
+ } else {
+ item[i] = newstr;
+ }
+ } else {
+ xfree(newstr);
+ }
+}
+
+static int
+csv_is_valid_quote_end(char *p)
+{
+ if(*p != '\"')
+ return FALSE;
+
+ for(p++; *p; p++) {
+ if(*p == ',')
+ return TRUE;
+ else if(!ISSPACE(*p))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static int
+csv_is_valid_quote_start(char *p)
+{
+ for(; *p; p++) {
+ if(*p == '\"')
+ return TRUE;
+ else if(!ISSPACE(*p))
+ return FALSE;
+ }
+
+ return FALSE;
+}
+
+static void
+csv_parse_line(char *line, int *table_base, size_t table_size)
+{
+ char *p, *start;
+ int field;
+ bool in_quote = FALSE;
+ list_item item;
+
+ item = item_create();
+
+ for(p = start = line, field = 0; *p; p++) {
+ if(in_quote) {
+ if(csv_is_valid_quote_end(p))
+ in_quote = FALSE;
+ } else {
+ if ( (((p - start) / sizeof (char)) < 2 ) &&
+ csv_is_valid_quote_start(p) )
+ in_quote = TRUE;
+ }
+
+ if(*p == ',' && !in_quote) {
+ *p = 0;
+ csv_store_item(item,
+ csv_field_to_item(table_base,table_size,field),
+ start);
+ field++;
+ start = p + 1;
+ }
+ }
+ /*
+ * store last field
+ */
+ csv_store_item(item, csv_field_to_item(table_base, table_size, field),
+ start);
+
+ csv_convert_emails(item_fget(item, EMAIL));
+ add_item2database(item);
+ item_free(&item);
+}
+
+static int
+csv_parse_file_common(FILE *in, int *conv_table, size_t table_size)
+{
+ char *line = NULL;
+
+ while(!feof(in)) {
+ line = getaline(in);
+
+ if(line && *line && *line != CSV_COMMENT_CHAR)
+ csv_parse_line(line, conv_table, table_size);
+
+ xfree(line);
+ }
+
+ return 0;
+}
+
+static int
+csv_parse_file(FILE *in)
+{
+ return csv_parse_file_common(in, csv_conv_table,
+ CSV_TABLE_SIZE(csv_conv_table));
+}
+
+static int
+allcsv_parse_file(FILE *in)
+{
+ return csv_parse_file_common(in, allcsv_conv_table,
+ CSV_TABLE_SIZE(allcsv_conv_table));
+}
+
+static int
+palmcsv_parse_file(FILE *in)
+{
+ return csv_parse_file_common(in, palmcsv_conv_table,
+ CSV_TABLE_SIZE(palmcsv_conv_table));
+}
+
+/*
+ * end of csv import filter
+ */
+
+/*
+ * csv addressbook export filters
+ */
+
+#define CSV_LAST (-1)
+#define CSV_UNDEFINED (-2)
+#define CSV_SPECIAL(X) (-3 - (X))
+#define CSV_IS_SPECIAL(X) ((X) <= -3)
+
+static int
+csv_export_common(FILE *out, struct db_enumerator e,
+ int fields[], void (*special_func)(FILE *, int, int))
+{
+ int i;
+
+ db_enumerate_items(e) {
+ for(i = 0; fields[i] != CSV_LAST; i++) {
+ if(fields[i] == CSV_UNDEFINED)
+ fprintf(out, "\"\"");
+ else if(CSV_IS_SPECIAL(fields[i])) {
+ if(special_func)
+ (*special_func)(out, e.item, fields[i]);
+ } else
+ /*fprintf(out,(
+ strchr(safe_str(database[e.item][field_idx(fields[i])]), ',') ||
+ strchr(safe_str(database[e.item][field_idx(fields[i])]), '\"')) ?
+ "\"%s\"" : "%s",
+ safe_str(database[e.item][field_idx(fields[i])])
+ );*/
+ fprintf(out, "\"%s\"",
+ safe_str(db_fget(e.item,fields[i])));
+
+ if(fields[i + 1] != CSV_LAST)
+ fputc(',', out);
+ }
+ fputc('\n', out);
+ }
+
+ return 0;
+}
+