Added lib/silcvcard/
authorPekka Riikonen <priikone@silcnet.org>
Wed, 20 Sep 2006 21:16:30 +0000 (21:16 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Wed, 20 Sep 2006 21:16:30 +0000 (21:16 +0000)
lib/Makefile.ad
lib/configure.ad
lib/silcutil/DIRECTORY
lib/silcutil/Makefile.ad
lib/silcvcard/DIRECTORY [new file with mode: 0644]
lib/silcvcard/Makefile.ad [new file with mode: 0644]
lib/silcvcard/silcvcard.c [new file with mode: 0644]
lib/silcvcard/silcvcard.h [new file with mode: 0644]

index 944bdc548397fc544adc970fdaeb760e43946012..4622541c7c7c5883b77d60dc5185362de21a6be9 100644 (file)
@@ -39,7 +39,16 @@ SILCLIB_DIRS =               \
 #ifdef SILC_DIST_ASN1
        silcasn1        \
 #endif SILC_DIST_ASN1
-       silcske
+       silcske         \
+#ifdef SILC_DIST_HTTP
+       silchttp        \
+#endif SILC_DIST_HTTP
+#ifdef SILC_DIST_IDCACHE
+       silcidcache     \
+#endif SILC_DIST_IDCACHE
+#ifdef SILC_DIST_IDCACHE
+       silcvcard       \
+#endif SILC_DIST_IDCACHE
 
 SILCLIB = libsilc.a
 
@@ -55,7 +64,7 @@ SILCSERVERLIB_DIRS = silcserver
 SILCSERVERLIB = libsilcserver.a
 #endif SILC_DIST_SERVERLIB
 
-SUBDIRS = $(SILCLIB_DIRS) $(SILCSERVERLIB_DIRS) ###$(SILCCLIENTLIB_DIRS)
+SUBDIRS = $(SILCLIB_DIRS) $(SILCSERVERLIB_DIRS) $(SILCCLIENTLIB_DIRS)
 
 CLEANFILES = libsilc.a libsilcclient.a libsilcserver.a
 DISTCLEANFILES = libsilc.a libsilcclient.a libsilcserver.a
@@ -65,7 +74,7 @@ remove:
        -rm -f libsilcclient.a
        -rm -f libsilcserver.a
 
-all:   remove $(SILCLIB) $(SILCSERVERLIB) ###$(SILCCLIENTLIB)
+all:   remove $(SILCLIB) $(SILCSERVERLIB) $(SILCCLIENTLIB)
 
 #ifdef SILC_DIST_TOOLKIT
 install-exec-hook:
index 7db18ac01d37d4008c4a0e5a9105d63b40c5b86c..c065b9b78b662224c349b8109dd8e1479d2a0f18 100644 (file)
@@ -56,6 +56,9 @@ SILC_LIB_INCLUDES="$SILC_LIB_INCLUDES -I$SILC_TOP_SRCDIR/lib/silchttp"
 #ifdef SILC_DIST_IDCACHE
 SILC_LIB_INCLUDES="$SILC_LIB_INCLUDES -I$SILC_TOP_SRCDIR/lib/silcidcache"
 #endif SILC_DIST_IDCACHE
+#ifdef SILC_DIST_VCARD
+SILC_LIB_INCLUDES="$SILC_LIB_INCLUDES -I$SILC_TOP_SRCDIR/lib/silcvcard"
+#endif SILC_DIST_VCARD
 
 ##
 ## Library versioning.
@@ -225,6 +228,12 @@ lib/silcidcache/Makefile
 )
 #endif SILC_DIST_IDCACHE
 
+#ifdef SILC_DIST_VCARD
+AC_CONFIG_FILES(
+lib/silcvcard/Makefile
+)
+#endif SILC_DIST_VCARD
+
 fi     # compile_libs
 
 #endif SILC_DIST_LIB
index abe7f837a9b70b1093daa7577c097c2a20f2ae04..79b2020f3c368c730c564c7dc069e8aa1767d916 100644 (file)
@@ -23,7 +23,6 @@
 @LINK=silcutil.html:SILC Util Interface
 @LINK=silclist.html:SILC List Interface
 @LINK=silcdlist.html:SILC Dynamic List Interface
-@LINK=silcvcard.html:SILC VCard Interface
 @LINK=silcapputil.html:SILC Application Utilities
 -->
 
index 3037fe24656966023bd9dac8f5acb5d2dff943e1..fc3db5856912baaa2c339acf5169f37f354bb042 100644 (file)
@@ -56,7 +56,6 @@ libsilcutil_la_SOURCES = \
        silcstrutil.c   \
        silcutil.c      \
        silchashtable.c \
-       silcvcard.c     \
        silcapputil.c   \
        silcutf8.c      \
        silcstringprep.c \
@@ -89,7 +88,6 @@ include_HEADERS =     \
        silcfileutil.h  \
        silcutil.h      \
        silcstrutil.h   \
-       silcvcard.h     \
        silcapputil.h   \
        silcutf8.h      \
        silcstringprep.h \
diff --git a/lib/silcvcard/DIRECTORY b/lib/silcvcard/DIRECTORY
new file mode 100644 (file)
index 0000000..da9710c
--- /dev/null
@@ -0,0 +1,21 @@
+<!--
+@LIBRARY=SILC VCard Library
+@FILENAME=silcvcardlib.html
+@LINK=silcvcard.html:SILC VCard Interface
+-->
+
+<big><b>SILC VCard Library</b></big>
+<br />
+<small>Directory: lib/silcvcard/</small>
+<br />
+<small>Library: libvcard.a, libvcard.lib</small>
+<br /><br />
+<b>Introduction</b>
+
+<br /><br />
+SILC VCard Library provides interface for creating and processing VCards, 
+defined in the RFC 2426.  The VCard 3.0 standard is implemented by the 
+library.
+
+<br /><br />
+@LINKS@
diff --git a/lib/silcvcard/Makefile.ad b/lib/silcvcard/Makefile.ad
new file mode 100644 (file)
index 0000000..8e34c69
--- /dev/null
@@ -0,0 +1,34 @@
+#
+#  Makefile.ad
+#
+#  Author: Pekka Riikonen <priikone@silcnet.org>
+#
+#  Copyright (C) 2006 Pekka Riikonen
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; version 2 of the License.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+noinst_LTLIBRARIES = libsilcvcard.la
+
+libsilcvcard_la_SOURCES =      \
+       silcvcard.c
+
+#ifdef SILC_DIST_TOOLKIT
+include_HEADERS =              \
+       silcvcard.h
+
+#SILC_EXTRA_DIST = tests
+#endif SILC_DIST_TOOLKIT
+
+EXTRA_DIST = *.h $(SILC_EXTRA_DIST)
+
+include $(top_srcdir)/Makefile.defines.in
diff --git a/lib/silcvcard/silcvcard.c b/lib/silcvcard/silcvcard.c
new file mode 100644 (file)
index 0000000..dad057e
--- /dev/null
@@ -0,0 +1,463 @@
+/*
+
+  silcvcard.c
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 2002 - 2005 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/* $Id$ */
+/* Implementation of the VCard (RFC 2426) */
+
+#include "silc.h"
+
+#define VCARD_HEADER "BEGIN:VCARD\n"
+#define VCARD_VERSION "VERSION:3.0\n"
+#define VCARD_FOOTER "END:VCARD\n"
+
+/* Encode VCard */
+
+unsigned char *silc_vcard_encode(SilcVCard vcard, SilcUInt32 *vcard_len)
+{
+  SilcBufferStruct buffer;
+  int i;
+
+  if (!vcard->full_name || !vcard->family_name || !vcard->first_name)
+    return NULL;
+
+  memset(&buffer, 0, sizeof(buffer));
+  silc_buffer_strformat(
+       &buffer,
+       VCARD_HEADER,
+       VCARD_VERSION,
+       "FN:", vcard->full_name, "\n",
+       "N:", vcard->family_name, ";", vcard->first_name, ";",
+       vcard->middle_names, ";", vcard->prefix, ";", vcard->suffix, "\n",
+       SILC_STRFMT_END);
+
+  if (vcard->nickname)
+    silc_buffer_strformat(&buffer,
+                         "NICKNAME:", vcard->nickname, "\n",
+                         SILC_STRFMT_END);
+  if (vcard->bday)
+    silc_buffer_strformat(&buffer,
+                         "BDAY:", vcard->bday, "\n",
+                         SILC_STRFMT_END);
+  if (vcard->title)
+    silc_buffer_strformat(&buffer,
+                         "TITLE:", vcard->title, "\n",
+                         SILC_STRFMT_END);
+  if (vcard->role)
+    silc_buffer_strformat(&buffer,
+                         "ROLE:", vcard->role, "\n",
+                         SILC_STRFMT_END);
+  if (vcard->org_name)
+    silc_buffer_strformat(&buffer,
+                         "ORG:", vcard->org_name, ";", vcard->org_unit, "\n",
+                         SILC_STRFMT_END);
+  if (vcard->categories)
+    silc_buffer_strformat(&buffer,
+                         "CATEGORIES:", vcard->categories, "\n",
+                         SILC_STRFMT_END);
+  if (vcard->catclass)
+    silc_buffer_strformat(&buffer,
+                         "CLASS:", vcard->catclass, "\n",
+                         SILC_STRFMT_END);
+  if (vcard->url)
+    silc_buffer_strformat(&buffer,
+                         "URL:", vcard->url, "\n",
+                         SILC_STRFMT_END);
+  if (vcard->label)
+    silc_buffer_strformat(&buffer,
+                         "LABEL;", vcard->url, "\n",
+                         SILC_STRFMT_END);
+  for (i = 0; i < vcard->num_addrs; i++) {
+    silc_buffer_strformat(&buffer,
+                         "ADR;TYPE=",
+                         vcard->addrs[i].type, ":",
+                         vcard->addrs[i].pbox, ";",
+                         vcard->addrs[i].ext_addr, ";",
+                         vcard->addrs[i].street_addr, ";",
+                         vcard->addrs[i].city, ";",
+                         vcard->addrs[i].state, ";",
+                         vcard->addrs[i].code, ";",
+                         vcard->addrs[i].country, "\n",
+                         SILC_STRFMT_END);
+  }
+  for (i = 0; i < vcard->num_tels; i++) {
+    silc_buffer_strformat(&buffer,
+                         "TEL;TYPE=",
+                         vcard->tels[i].type, ":",
+                         vcard->tels[i].telnum, "\n",
+                         SILC_STRFMT_END);
+  }
+  for (i = 0; i < vcard->num_emails; i++) {
+    silc_buffer_strformat(&buffer,
+                         "EMAIL;TYPE=",
+                         vcard->emails[i].type, ":",
+                         vcard->emails[i].address, "\n",
+                         SILC_STRFMT_END);
+  }
+  if (vcard->note)
+    silc_buffer_strformat(&buffer,
+                         "NOTE:", vcard->note, "\n",
+                         SILC_STRFMT_END);
+  if (vcard->rev)
+    silc_buffer_strformat(&buffer,
+                         "REV:", vcard->rev, "\n",
+                         SILC_STRFMT_END);
+
+  silc_buffer_strformat(&buffer, VCARD_FOOTER, SILC_STRFMT_END);
+
+  if (vcard_len)
+    *vcard_len = silc_buffer_truelen(&buffer);
+
+  return buffer.head;
+}
+
+/* Take one token */
+#define VCARD_TOKEN(x)                         \
+  if (!(x)) {                                  \
+    (x) = silc_memdup(val + off, i - off);     \
+    off = i + 1;                               \
+    continue;                                  \
+  }
+
+/* Take on TYPE= token and prepare for next token, accept the
+   type also without TYPE= as it is possible */
+#define VCARD_TYPETOKEN(x)                                     \
+  if (!(x)) {                                                  \
+    int tmpi = 0;                                              \
+    if (!strncasecmp(val + off, "TYPE=", 5))                   \
+      tmpi = 5;                                                        \
+    (x) = silc_memdup(val + off + tmpi, i - off - tmpi - 1);   \
+    tmpi = off + tmpi + strlen((x)) + 1;                       \
+    off = i;                                                   \
+    i = tmpi;                                                  \
+  }
+
+/* Take last token */
+#define VCARD_LASTTOKEN(x)                     \
+  if (!(x)) {                                  \
+    if (off < len)                             \
+      (x) = silc_memdup(val + off, len - off); \
+  }                                            \
+
+/* Get one (single) field */
+#define VCARD_FIELD(val, c, x)                         \
+do {                                                   \
+  if (!strncasecmp(val, (c), strlen((c)))) {           \
+    int tmpl = strlen((c));                            \
+    if ((x))                                           \
+      break;                                           \
+    if (len - tmpl > 0)                                        \
+      (x) = silc_memdup(val + tmpl, len - tmpl);       \
+    goto next;                                         \
+  }                                                    \
+} while(0)
+
+/* Decode VCard */
+
+SilcBool silc_vcard_decode(const unsigned char *data, SilcUInt32 data_len,
+                      SilcVCard vcard)
+{
+  unsigned char *val;
+  SilcBool has_begin = FALSE, has_end = FALSE;
+  int len, i, off = 0;
+
+  val = (unsigned char *)data;
+  while (val) {
+    len = 0;
+    for (i = (val - data); i < data_len; i++) {
+      if (data[i] == '\0' || data[i] == '\n') {
+       len = i - (val - data);
+       break;
+      }
+    }
+    if (!len || len > data_len - (val - data))
+      break;
+
+    /* Check for mandatory header and footer */
+    if (!strncasecmp(val, VCARD_HEADER, strlen(VCARD_HEADER))) {
+      has_begin = TRUE;
+      goto next;
+    }
+    if (!strncasecmp(val, VCARD_FOOTER, strlen(VCARD_FOOTER))) {
+      has_end = TRUE;
+      goto next;
+    }
+
+    /* Get single fields */
+    VCARD_FIELD(val, "FN:", vcard->full_name);
+    VCARD_FIELD(val, "NICKNAME:", vcard->nickname);
+    VCARD_FIELD(val, "BDAY:", vcard->bday);
+    VCARD_FIELD(val, "TITLE:", vcard->title);
+    VCARD_FIELD(val, "ROLE:", vcard->role);
+    VCARD_FIELD(val, "CATEGORIES:", vcard->categories);
+    VCARD_FIELD(val, "CLASS:", vcard->catclass);
+    VCARD_FIELD(val, "URL:", vcard->url);
+    VCARD_FIELD(val, "LABEL;", vcard->label);
+    VCARD_FIELD(val, "NOTE:", vcard->note);
+    VCARD_FIELD(val, "REV:", vcard->rev);
+
+    /* Get multi-column fields */
+
+    if (!strncasecmp(val, "N:", 2)) {
+      if (vcard->family_name)
+       break;
+      if (len - 2) {
+       off = 2;
+       for (i = off; i < len; i++)
+         if (val[i] == ';') {
+           VCARD_TOKEN(vcard->family_name);
+           VCARD_TOKEN(vcard->first_name);
+           VCARD_TOKEN(vcard->middle_names);
+           VCARD_TOKEN(vcard->prefix);
+         }
+       if (!vcard->family_name && !vcard->first_name) {
+         VCARD_LASTTOKEN(vcard->family_name);
+         off += (len - off);
+       }
+       if (!vcard->first_name) {
+         VCARD_LASTTOKEN(vcard->first_name);
+       } else {
+         VCARD_LASTTOKEN(vcard->suffix);
+       }
+      }
+      goto next;
+    }
+
+    if (!strncasecmp(val, "ORG:", 4)) {
+      if (vcard->org_name)
+       continue;
+      if (len - 4) {
+       off = 4;
+       for (i = off; i < len; i++) {
+         if (val[i] == ';') {
+           VCARD_TOKEN(vcard->org_name);
+           break;
+         }
+       }
+       /* It's possible to have ORG without last ';', so check for it */
+       if (!vcard->org_name) {
+         VCARD_LASTTOKEN(vcard->org_name);
+       } else {
+         VCARD_LASTTOKEN(vcard->org_unit);
+       }
+      }
+      goto next;
+    }
+
+    if (!strncasecmp(val, "ADR;", 4)) {
+      vcard->addrs = silc_realloc(vcard->addrs, sizeof(*vcard->addrs) *
+                                 (vcard->num_addrs + 1));
+      memset(&vcard->addrs[vcard->num_addrs], 0, sizeof(*vcard->addrs));
+      if (len - 4) {
+       off = 4;
+       for (i = off; i < len; i++)
+         if (val[i] == ';') {
+           VCARD_TYPETOKEN(vcard->addrs[vcard->num_addrs].type);
+           VCARD_TOKEN(vcard->addrs[vcard->num_addrs].pbox);
+           VCARD_TOKEN(vcard->addrs[vcard->num_addrs].ext_addr);
+           VCARD_TOKEN(vcard->addrs[vcard->num_addrs].street_addr);
+           VCARD_TOKEN(vcard->addrs[vcard->num_addrs].city);
+           VCARD_TOKEN(vcard->addrs[vcard->num_addrs].state);
+           VCARD_TOKEN(vcard->addrs[vcard->num_addrs].code);
+         }
+       VCARD_LASTTOKEN(vcard->addrs[vcard->num_addrs].country);
+      }
+      vcard->num_addrs++;
+      goto next;
+    }
+
+    if (!strncasecmp(val, "TEL;", 4)) {
+      vcard->tels = silc_realloc(vcard->tels, sizeof(*vcard->tels) *
+                                (vcard->num_tels + 1));
+      memset(&vcard->tels[vcard->num_tels], 0, sizeof(*vcard->tels));
+      if (len - 4) {
+       off = 4;
+       for (i = off; i < len; i++)
+         if (val[i] == ':') {
+           i++;
+           VCARD_TYPETOKEN(vcard->tels[vcard->num_tels].type);
+           break;
+         }
+       VCARD_LASTTOKEN(vcard->tels[vcard->num_tels].telnum);
+      }
+      vcard->num_tels++;
+      goto next;
+    }
+
+    if (!strncasecmp(val, "EMAIL;", 6)) {
+      vcard->emails = silc_realloc(vcard->emails, sizeof(*vcard->emails) *
+                                  (vcard->num_emails + 1));
+      memset(&vcard->emails[vcard->num_emails], 0, sizeof(*vcard->emails));
+      if (len - 6) {
+       off = 6;
+       for (i = off; i < len; i++)
+         if (val[i] == ':') {
+           i++;
+           VCARD_TYPETOKEN(vcard->emails[vcard->num_emails].type);
+           break;
+         }
+       VCARD_LASTTOKEN(vcard->emails[vcard->num_emails].address);
+      }
+      vcard->num_emails++;
+      goto next;
+    }
+
+  next:
+    val = strchr(val, '\n');
+    if (!val)
+      break;
+    val++;
+    if (!val || !(*val))
+      break;
+  }
+
+  if (!has_begin || !has_end || !vcard->full_name) {
+    silc_vcard_free(vcard);
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/* Allocate vcard context */
+
+SilcVCard silc_vcard_alloc(void)
+{
+  SilcVCard vcard = silc_calloc(1, sizeof(*vcard));
+  if (!vcard)
+    return NULL;
+  vcard->dynamic = TRUE;
+  return vcard;
+}
+
+/* Free the vcard structure */
+
+void silc_vcard_free(SilcVCard vcard)
+{
+  int i;
+
+  silc_free(vcard->full_name);
+  silc_free(vcard->family_name);
+  silc_free(vcard->first_name);
+  silc_free(vcard->middle_names);
+  silc_free(vcard->prefix);
+  silc_free(vcard->suffix);
+  silc_free(vcard->nickname);
+  silc_free(vcard->bday);
+  silc_free(vcard->title);
+  silc_free(vcard->role);
+  silc_free(vcard->org_name);
+  silc_free(vcard->org_unit);
+  silc_free(vcard->categories);
+  silc_free(vcard->catclass);
+  silc_free(vcard->url);
+  silc_free(vcard->label);
+  for (i = 0; i < vcard->num_addrs; i++) {
+    silc_free(vcard->addrs[i].type);
+    silc_free(vcard->addrs[i].pbox);
+    silc_free(vcard->addrs[i].ext_addr);
+    silc_free(vcard->addrs[i].street_addr);
+    silc_free(vcard->addrs[i].city);
+    silc_free(vcard->addrs[i].state);
+    silc_free(vcard->addrs[i].code);
+    silc_free(vcard->addrs[i].country);
+  }
+  silc_free(vcard->addrs);
+  for (i = 0; i < vcard->num_tels; i++) {
+    silc_free(vcard->tels[i].type);
+    silc_free(vcard->tels[i].telnum);
+  }
+  silc_free(vcard->tels);
+  for (i = 0; i < vcard->num_emails; i++) {
+    silc_free(vcard->emails[i].type);
+    silc_free(vcard->emails[i].address);
+  }
+  silc_free(vcard->emails);
+  silc_free(vcard->note);
+  silc_free(vcard->rev);
+  if (!vcard->dynamic)
+    memset(vcard, 0, sizeof(*vcard));
+
+  if (vcard->dynamic) {
+    memset(vcard, 0, sizeof(*vcard));
+    silc_free(vcard);
+  }
+}
+
+/* Print card to file stream */
+
+void silc_vcard_fprintf(SilcVCard vcard, FILE *stream)
+{
+  int i;
+  fprintf(stream, "%s", VCARD_HEADER);
+  fprintf(stream, "%s", VCARD_VERSION);
+  if (vcard->full_name)
+    fprintf(stream, "FN:%s\n", vcard->full_name);
+  if (vcard->family_name)
+    fprintf(stream, "N:%s;%s;%s;%s;%s\n",
+           vcard->family_name,
+           vcard->first_name ? vcard->first_name : "",
+           vcard->middle_names ? vcard->middle_names : "",
+           vcard->prefix ? vcard->prefix : "",
+           vcard->suffix ? vcard->suffix : "");
+  if (vcard->nickname)
+    fprintf(stream, "NICKNAME:%s\n", vcard->nickname);
+  if (vcard->bday)
+    fprintf(stream, "BDAY:%s\n", vcard->bday);
+  if (vcard->title)
+    fprintf(stream, "TITLE:%s\n", vcard->title);
+  if (vcard->role)
+    fprintf(stream, "ROLE:%s\n", vcard->role);
+  if (vcard->org_name)
+    fprintf(stream, "ORG:%s;%s\n", vcard->org_name,
+           vcard->org_unit ? vcard->org_unit : "");
+  if (vcard->categories)
+    fprintf(stream, "CATEGORIES:%s\n", vcard->categories);
+  if (vcard->catclass)
+    fprintf(stream, "CLASS:%s\n", vcard->catclass);
+  if (vcard->url)
+    fprintf(stream, "URL:%s\n", vcard->url);
+  if (vcard->label)
+    fprintf(stream, "LABEL;%s\n", vcard->label);
+  for (i = 0; i < vcard->num_addrs; i++) {
+    fprintf(stream, "ADR;TYPE=%s:%s;%s;%s;%s;%s;%s;%s\n",
+           vcard->addrs[i].type,
+           vcard->addrs[i].pbox ? vcard->addrs[i].pbox : "",
+           vcard->addrs[i].ext_addr ? vcard->addrs[i].ext_addr : "",
+           vcard->addrs[i].street_addr ? vcard->addrs[i].street_addr : "",
+           vcard->addrs[i].city ? vcard->addrs[i].city : "",
+           vcard->addrs[i].state ? vcard->addrs[i].state : "",
+           vcard->addrs[i].code ? vcard->addrs[i].code : "",
+           vcard->addrs[i].country ? vcard->addrs[i].country : "");
+  }
+  for (i = 0; i < vcard->num_tels; i++) {
+    fprintf(stream, "TEL;TYPE=%s:%s\n",
+           vcard->tels[i].type,
+           vcard->tels[i].telnum ? vcard->tels[i].telnum : "");
+  }
+  for (i = 0; i < vcard->num_emails; i++) {
+    fprintf(stream, "EMAIL;TYPE=%s:%s\n",
+           vcard->emails[i].type,
+           vcard->emails[i].address ? vcard->emails[i].address : "");
+  }
+  if (vcard->note)
+    fprintf(stream, "NOTE:%s\n", vcard->note);
+  if (vcard->rev)
+    fprintf(stream, "REV:%s\n", vcard->rev);
+  fprintf(stream, "%s", VCARD_FOOTER);
+  fflush(stream);
+}
diff --git a/lib/silcvcard/silcvcard.h b/lib/silcvcard/silcvcard.h
new file mode 100644 (file)
index 0000000..c71ebba
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+
+  silcvcard.h
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 2002 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+/****h* silcvcard/SILC VCard
+ *
+ * DESCRIPTION
+ *
+ * Implementation of the VCard 3.0 standard (RFC 2426) that can be used
+ * with Requested Attributes (in WHOIS command) to deliver personal
+ * information.  All fields are not supported since some of the
+ * information are not needed in context of SILC.  If such VCard is
+ * received this implementation ignores the unsupported fields.
+ *
+ ***/
+
+#ifndef SILCVCARD_H
+#define SILCVCARD_H
+
+/****s* silcvcard/SilcVCard/SilcVCard
+ *
+ * NAME
+ * 
+ *    typedef struct { ... } SilcVCardStruct, *SilcVCard;
+ *
+ * DESCRIPTION
+ *
+ *    This structure is the VCard.  This holds the contents of the
+ *    card.  When a card is parsed it is parsed into this structure.
+ *    When creating a new card application fills this structure and
+ *    the library encodes the card from it.  Free the allocated
+ *    structure with silc_vcard_free function.
+ *
+ * SOURCE
+ */
+typedef struct {
+  char *full_name;         /* full name, X.520 common name */
+  char *family_name;       /* last name, string */
+  char *first_name;        /* first name, string */
+  char *middle_names;      /* other names, string (comma sep.) */
+  char *prefix;                    /* honorifix prefix (Mr., Mrs.), string */
+  char *suffix;                    /* honorifix suffix (MD), string (comma sep.) */
+  char *nickname;          /* string (comma sep. if more than one) */
+  char *bday;              /* birth day, UTC date string */
+  char *title;             /* job title X.520, string */
+  char *role;              /* job role X.520, string */
+  char *org_name;          /* organization name, string */
+  char *org_unit;          /* organization unit, string */
+  char *categories;        /* application category, string */
+  char *catclass;          /* class (public, private, confidental), string */
+  char *url;               /* home page, URI string */
+  char *label;             /* formatted address label, string (same
+                              format as for 'addr' but comma sep.) */
+
+  struct addr {
+    char *type;                    /* address type, string
+                              (intl, dom, home, work, pref, postal, parcel) */
+    char *pbox;                    /* post office box, string */
+    char *ext_addr;        /* extended address, string */
+    char *street_addr;     /* street address, string */
+    char *city;                    /* city, string */
+    char *state;           /* state/province, string */
+    char *code;                    /* postal code, string */
+    char *country;         /* country name, string */
+  } *addrs;
+  SilcUInt8 num_addrs;     /* number of addresses */
+
+  struct tel {
+    char *type;                    /* telephone number type, string
+                              (msg, voice, home, work, pref, bbs, modem, car,
+                              cell, video, pager, isdn, fax) */
+    char *telnum;          /* single telephone number, string */
+  } *tels;
+  SilcUInt8 num_tels;
+
+  struct email {
+    char *type;                    /* email type, string (internet, pref, x400) */
+    char *address;         /* single email address, string */
+  } *emails;
+  SilcUInt8 num_emails;
+
+  char *note;              /* a note, string */
+  char *rev;               /* revision of card, UTC date string */
+
+  SilcBool dynamic;                /* TRUE when dynamically allocated */
+} SilcVCardStruct, *SilcVCard;
+/***/
+
+/****f* silcvcard/SilcVCard/silc_vcard_encode
+ *
+ * SYNOPSIS
+ *
+ *    char *silc_vcard_encode(SilcVCard vcard, SilcUInt32 *vcard_len);
+ *
+ * DESCRIPTION
+ *
+ *    Encodes VCard from the SilcVCard structure indicated by `vcard'
+ *    which the caller must fill before calling this function.  This
+ *    function encodes the card and returns allocated buffer and
+ *    its length into `vcard_len'.  The caller must free the returned
+ *    buffer.  Returns NULL on error.
+ *
+ ***/
+unsigned char *silc_vcard_encode(SilcVCard vcard, SilcUInt32 *vcard_len);
+
+/****f* silcvcard/SilcVCard/silc_vcard_decode
+ *
+ * SYNOPSIS
+ *
+ *    SilcBool silc_vcard_decode(const unsigned char *data,
+ *                               SilcUInt32 data_len, SilcVCard vcard);
+ *
+ * DESCRIPTION
+ *
+ *    Decodes VCard from the buffer `vcard' of length of `vcard_len' bytes
+ *    and returns the parsed card into `vcard' structure.  The caller must
+ *    pre-allocate the structure.  Returns TRUE if the `vcard' is valid
+ *    vcard and was successfully parsed or FALSE on error.  The structure
+ *    is freed with silc_vcard_free function when it is not needed anymore.
+ *
+ ***/
+SilcBool silc_vcard_decode(const unsigned char *data, SilcUInt32 data_len,
+                          SilcVCard vcard);
+
+/****f* silcvcard/SilcVCard/silc_vcard_alloc
+ *
+ * SYNOPSIS
+ *
+ *    SilcVCard silc_vcard_alloc(void);
+ *
+ * DESCRIPTION
+ *
+ *    Allocate a SilcVCard context which must be freed with the
+ *    silc_vcard_free function.
+ *
+ ***/
+SilcVCard silc_vcard_alloc(void);
+
+/****f* silcvcard/SilcVCard/silc_vcard_free
+ *
+ * SYNOPSIS
+ *
+ *    void silc_vcard_free(SilcVCard vcard);
+ *
+ * DESCRIPTION
+ *
+ *    Free VCard structure and all data in it.
+ *
+ ***/
+void silc_vcard_free(SilcVCard vcard);
+
+/****f* silcvcard/SilcVCard/silc_vcard_fprintf
+ *
+ * SYNOPSIS
+ *
+ *    void silc_vcard_fprintf(SilcVCard vcard, FILE *stream);
+ *
+ * DESCRIPTION
+ *
+ *    Prints the contents of the `vcard' into file stream `stream' in
+ *    the correct VCard format.
+ *
+ ***/
+void silc_vcard_fprintf(SilcVCard vcard, FILE *stream);
+
+#endif /* SILCVCARD_H */