* Added some rudimentary support for displaying vCards as card-looking things
authorArt Cancro <ajc@citadel.org>
Wed, 13 Feb 2002 22:47:51 +0000 (22:47 +0000)
committerArt Cancro <ajc@citadel.org>
Wed, 13 Feb 2002 22:47:51 +0000 (22:47 +0000)
webcit/ChangeLog
webcit/Makefile.in
webcit/messages.c
webcit/tools.c
webcit/vcard.c [new file with mode: 0644]
webcit/vcard.h [new file with mode: 0644]
webcit/webcit.h

index 5a780b3da6d5b100e3c0fa0580601af8fcdddb47..53ef7e1571c680ec28df63c6a6cc8741e41f6788 100644 (file)
@@ -1,4 +1,7 @@
 $Log$
+Revision 323.3  2002/02/13 22:47:51  ajc
+* Added some rudimentary support for displaying vCards as card-looking things
+
 Revision 323.2  2002/02/13 15:04:25  ajc
 * Began some hacks for vCard processing
 
@@ -716,4 +719,3 @@ Sun Dec  6 19:50:55 EST 1998 Art Cancro <ajc@uncnsrd.mt-kisco.ny.us>
 
 1998-12-03 Nathan Bryant <bryant@cs.usm.maine.edu>
        * webserver.c: warning fix
-
index 5c5195f958658e47059c3fe75f7ece2cb232fd66..277dd55906567e1ea8d1370611dbc01000fa398b 100644 (file)
@@ -25,12 +25,12 @@ distclean: clean
 webserver: webserver.o context_loop.o tools.o \
        cookie_conversion.o locate_host.o \
        webcit.o auth.o tcp_sockets.o mainmenu.o serv_func.o who.o \
-       roomops.o messages.o userlist.o paging.o sysmsgs.o \
+       roomops.o messages.o userlist.o paging.o sysmsgs.o vcard.o \
        mime_parser.o graphics.o netconf.o siteconfig.o subst.o $(LIBOBJS)
        $(CC) webserver.o context_loop.o tools.o cookie_conversion.o \
        webcit.o auth.o tcp_sockets.o mainmenu.o serv_func.o who.o \
        roomops.o messages.o userlist.o paging.o sysmsgs.o \
-       locate_host.o siteconfig.o subst.o \
+       locate_host.o siteconfig.o subst.o vcard.o \
        mime_parser.o graphics.o netconf.o \
        $(LIBOBJS) $(LIBS) -o webserver
        strip webserver
index da0e2b6be266d14e5944089226a589087ff33932..09b031c39e0c68860cb4ae715e777b310efde520 100644 (file)
@@ -24,6 +24,7 @@
 #include <pthread.h>
 #include <signal.h>
 #include "webcit.h"
+#include "vcard.h"
 
 
 /*
@@ -81,6 +82,76 @@ char buf[];
 }
 
 
+
+
+/*
+ * Experimental output type of thing
+ */
+void display_vcard(char *vcard_source) {
+       int i, j;
+       struct vCard *v;
+       char buf[SIZ];
+
+       v = vcard_load(vcard_source);
+       if (v == NULL) return;
+
+       wprintf("<TABLE bgcolor=#888888>");
+       if (v->numprops) for (i=0; i<(v->numprops); ++i) {
+               if (!strcasecmp(v->prop[i].name, "n")) {
+                       wprintf("<TR BGCOLOR=#AAAAAA><TD><FONT SIZE=+1><B>");
+                       escputs(v->prop[i].value);
+                       wprintf("</B></FONT></TD></TR>\n");
+               }
+               else if (!strcasecmp(v->prop[i].name, "email;internet")) {
+                       wprintf("<TR><TD>Internet e-mail:</TD>"
+                               "<TD><A HREF=\"mailto:");
+                       urlescputs(v->prop[i].value);
+                       wprintf("\">");
+                       escputs(v->prop[i].value);
+                       wprintf("</A></TD></TR>\n");
+               }
+               else if (!strcasecmp(v->prop[i].name, "adr")) {
+                       wprintf("<TR><TD>Address:</TD><TD>");
+                       for (j=0; j<num_tokens(v->prop[i].value, ';'); ++j) {
+                               extract_token(buf, v->prop[i].value, j, ';');
+                               if (strlen(buf) > 0) {
+                                       escputs(buf);
+                                       wprintf("<BR>");
+                               }
+                       }
+                       wprintf("</TD></TR>\n");
+               }
+               else if (!strncasecmp(v->prop[i].name, "tel;", 4)) {
+                       wprintf("<TR><TD>%s telephone:</TD><TD>",
+                               &v->prop[i].name[4]);
+                       for (j=0; j<num_tokens(v->prop[i].value, ';'); ++j) {
+                               extract_token(buf, v->prop[i].value, j, ';');
+                               if (strlen(buf) > 0) {
+                                       escputs(buf);
+                                       wprintf("<BR>");
+                               }
+                       }
+                       wprintf("</TD></TR>\n");
+               }
+               else {
+                       wprintf("<TR><TD>");
+                       escputs(v->prop[i].name);
+                       wprintf("</TD><TD>");
+                       escputs(v->prop[i].value);
+                       wprintf("</TD></TR>\n");
+               }
+       }
+
+       wprintf("</TABLE>\n");
+
+       vcard_free(v);
+}
+
+
+
+
+
+
 void read_message(long msgnum, int is_summary) {
        char buf[SIZ];
        char mime_partnum[SIZ];
@@ -320,8 +391,7 @@ void read_message(long msgnum, int is_summary) {
        if (strlen(vcard_partnum) > 0) {
                vcard_source = load_mimepart(msgnum, vcard_partnum);
                if (vcard_source != NULL) {
-                       wprintf("vcard object length = %d<BR>\n",
-                               strlen(vcard_source));
+                       display_vcard(vcard_source);
                        free(vcard_source);
                }
        }
index 8bcccaed682a696b5d1703abd6ebec47cc741bdf..adc84061850cb6e1c1bb2c6e3af17ddbf955e468 100644 (file)
@@ -262,4 +262,16 @@ char *memreadline(char *start, char *buf, int maxlen)
 
 
 
+/*
+ * pattern2()  -  searches for patn within search string, returns pos
+ */
+int pattern2(char *search, char *patn)
+{
+        int a;
+        for (a=0; a<strlen(search); ++a) {
+                if (!strncasecmp(&search[a],patn,strlen(patn))) return(a);
+                }
+        return(-1);
+        }
+
 
diff --git a/webcit/vcard.c b/webcit/vcard.c
new file mode 100644 (file)
index 0000000..d5ff0b6
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * $Id$
+ *
+ * vCard implementation for Citadel/UX
+ *
+ * Copyright (C) 1999 by Art Cancro
+ * This code is freely redistributable under the terms of the GNU General
+ * Public License.  All other rights reserved.
+ */
+
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <syslog.h>
+
+#include "webcit.h"
+#include "vcard.h"
+
+/* 
+ * Constructor (empty vCard)
+ */
+struct vCard *vcard_new() {
+       struct vCard *v;
+
+       v = (struct vCard *) malloc(sizeof(struct vCard));
+       if (v == NULL) return v;
+
+       v->magic = CTDL_VCARD_MAGIC;
+       v->numprops = 0;
+       v->prop = NULL;
+
+       return v;
+}
+
+
+/*
+ * Constructor (supply serialized vCard)
+ */
+struct vCard *vcard_load(char *vtext) {
+       struct vCard *v;
+       int valid = 0;
+       char *mycopy, *ptr;
+       char *namebuf, *valuebuf;
+       int i;
+       int colonpos, nlpos;
+
+       mycopy = strdup(vtext);
+       if (mycopy == NULL) return NULL;
+
+       /* First, fix this big pile o' vCard to make it more parseable.
+        * To make it easier to parse, we convert CRLF to LF, and unfold any
+        * multi-line fields into single lines.
+        */
+       for (i=0; i<strlen(mycopy); ++i) {
+               if (!strncmp(&mycopy[i], "\r\n", 2)) {
+                       strcpy(&mycopy[i], &mycopy[i+1]);
+               }
+               if ( (mycopy[i]=='\n') && (isspace(mycopy[i+1])) ) {
+                       strcpy(&mycopy[i], &mycopy[i+1]);
+               }
+       }
+
+       v = vcard_new();
+       if (v == NULL) return v;
+
+       ptr = mycopy;
+       while (strlen(ptr)>0) {
+               colonpos = (-1);
+               nlpos = (-1);
+               colonpos = pattern2(ptr, ":");
+               nlpos = pattern2(ptr, "\n");
+
+               if (nlpos > colonpos > 0) {
+                       namebuf = malloc(colonpos + 1);
+                       valuebuf = malloc(nlpos - colonpos + 1);
+                       strncpy(namebuf, ptr, colonpos);
+                       namebuf[colonpos] = 0;
+                       strncpy(valuebuf, &ptr[colonpos+1], nlpos-colonpos-1);
+                       valuebuf[nlpos-colonpos-1] = 0;
+
+                       if ( (!strcasecmp(namebuf, "end"))
+                          && (!strcasecmp(valuebuf, "vcard")) )  valid = 0;
+                       if ( (!strcasecmp(namebuf, "begin"))
+                          && (!strcasecmp(valuebuf, "vcard")) )  valid = 1;
+
+                       if ( (valid) && (strcasecmp(namebuf, "begin")) ) {
+                               ++v->numprops;
+                               v->prop = realloc(v->prop,
+                                       (v->numprops * sizeof(char *) * 2) );
+                               v->prop[v->numprops-1].name = namebuf;
+                               v->prop[v->numprops-1].value = valuebuf;
+                       } 
+                       else {
+                               free(namebuf);
+                               free(valuebuf);
+                       }
+
+               }
+
+               while ( (*ptr != '\n') && (strlen(ptr)>0) ) {
+                       ++ptr;
+               }
+               if (*ptr == '\n') ++ptr;
+       }
+
+       free(mycopy);
+       return v;
+}
+
+
+/*
+ * Fetch the value of a particular key
+ * If is_partial is set to 1, a partial match is ok (for example,
+ * a key of "tel;home" will satisfy a search for "tel")
+ * Set "instance" to a value higher than 0 to return subsequent instances
+ * of the same key
+ */
+char *vcard_get_prop(struct vCard *v, char *propname,
+                       int is_partial, int instance) {
+       int i;
+       int found_instance = 0;
+
+       if (v->numprops) for (i=0; i<(v->numprops); ++i) {
+               if ( (!strcasecmp(v->prop[i].name, propname))
+                  || (  (!strncasecmp(v->prop[i].name,
+                                       propname, strlen(propname)))
+                        && (v->prop[i].name[strlen(propname)] == ';')
+                        && (is_partial) ) ) {
+                       if (instance == found_instance++) {
+                               return(v->prop[i].value);
+                       }
+               }
+       }
+
+       return NULL;
+}
+
+
+
+
+/*
+ * Destructor
+ */
+void vcard_free(struct vCard *v) {
+       int i;
+       
+       if (v->magic != CTDL_VCARD_MAGIC) return;       /* Self-check */
+       
+       if (v->numprops) for (i=0; i<(v->numprops); ++i) {
+               free(v->prop[i].name);
+               free(v->prop[i].value);
+       }
+
+       if (v->prop != NULL) free(v->prop);
+       
+       memset(v, 0, sizeof(struct vCard));
+       free(v);
+}
+
+
+
+
+/*
+ * Set a name/value pair in the card
+ */
+void vcard_set_prop(struct vCard *v, char *name, char *value, int append) {
+       int i;
+
+       if (v->magic != CTDL_VCARD_MAGIC) return;       /* Self-check */
+
+       /* If this key is already present, replace it */
+       if (!append) if (v->numprops) for (i=0; i<(v->numprops); ++i) {
+               if (!strcasecmp(v->prop[i].name, name)) {
+                       free(v->prop[i].name);
+                       free(v->prop[i].value);
+                       v->prop[i].name = strdup(name);
+                       v->prop[i].value = strdup(value);
+                       return;
+               }
+       }
+
+       /* Otherwise, append it */
+       ++v->numprops;
+       v->prop = realloc(v->prop,
+               (v->numprops * sizeof(char *) * 2) );
+       v->prop[v->numprops-1].name = strdup(name);
+       v->prop[v->numprops-1].value = strdup(value);
+}
+
+
+
+
+/*
+ * Serialize a struct vcard into a standard text/x-vcard MIME type.
+ *
+ */
+char *vcard_serialize(struct vCard *v)
+{
+       char *ser;
+       int i;
+       size_t len;
+
+       if (v->magic != CTDL_VCARD_MAGIC) return NULL;  /* self check */
+
+       /* Figure out how big a buffer we need to allocate */
+       len = 64;       /* for begin, end, and a little padding for safety */
+       if (v->numprops) for (i=0; i<(v->numprops); ++i) {
+               len = len +
+                       strlen(v->prop[i].name) +
+                       strlen(v->prop[i].value) + 4;
+       }
+
+       ser = malloc(len);
+       if (ser == NULL) return NULL;
+
+       strcpy(ser, "begin:vcard\r\n");
+       if (v->numprops) for (i=0; i<(v->numprops); ++i) {
+               strcat(ser, v->prop[i].name);
+               strcat(ser, ":");
+               strcat(ser, v->prop[i].value);
+               strcat(ser, "\r\n");
+       }
+       strcat(ser, "end:vcard\r\n");
+
+       return ser;
+}
diff --git a/webcit/vcard.h b/webcit/vcard.h
new file mode 100644 (file)
index 0000000..743efa9
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * $Id$
+ *
+ * vCard implementation for Citadel/UX
+ *
+ * Copyright (C) 1999 by Art Cancro
+ * This code is freely redistributable under the terms of the GNU General
+ * Public License.  All other rights reserved.
+ */
+
+
+#define CTDL_VCARD_MAGIC       0xa1f9
+
+/*
+ * This data structure represents a vCard object currently in memory.
+ */
+struct vCard {
+       int magic;
+       int numprops;
+       struct vCardProp {
+               char *name;
+               char *value;
+       } *prop;
+};
+
+
+struct vCard *vcard_new(void);
+struct vCard *vcard_load(char *);
+void vcard_free(struct vCard *);
+void vcard_set_prop(struct vCard *v, char *name, char *value, int append);
+char *vcard_get_prop(struct vCard *v, char *propname, int is_partial,
+                       int instance);
+char *vcard_serialize(struct vCard *);
index ab70de2f0cc4f2212be8c21058fea5887a53f94e..e54372d6171566a4c8fc22520461f11f5231d32f 100644 (file)
@@ -286,3 +286,4 @@ void extract_token(char *dest, char *source, int parmnum, char separator);
 void remove_token(char *source, int parmnum, char separator);
 int decode_base64(char *dest, char *source);
 char *load_mimepart(long msgnum, char *partnum);
+int pattern2(char *search, char *patn);