Finalize vcard editing:
[citadel.git] / webcit / vcard_edit.c
index 47c04c724a5863fa2610caa84e7ff94e14bb40eb..27ba6495b61327e0f61cd5465533d9cf30bef4e2 100644 (file)
@@ -15,6 +15,7 @@
 #include "calendar.h"
 
 CtxType CTX_VCARD = CTX_NONE;
+CtxType CTX_VCARD_TYPE = CTX_NONE;
 long VCEnumCounter = 0;
 
 typedef enum _VCStrEnum {
@@ -22,10 +23,12 @@ typedef enum _VCStrEnum {
        StringCluster,
        PhoneNumber,
        EmailAddr,
+       Address,
        Street,
        Number,
        AliasFor,
        Base64BinaryAttachment,
+       UnKnown,
        TerminateList
 }VCStrEnum;
 typedef struct vcField vcField;
@@ -34,48 +37,50 @@ struct vcField {
        VCStrEnum Type;
        vcField *Sub;
        long cval;
-       const char *Str;
+       long parentCVal;
+       ConstStr Name;
 };
 
 vcField VCStr_Ns [] = {
-       {{HKEY("last")},   FlatString,    NULL, 0, "Last Name"},
-       {{HKEY("first")},  FlatString,    NULL, 0, "First Name"},
-       {{HKEY("middle")}, FlatString,    NULL, 0, "Middle Name"},
-       {{HKEY("prefix")}, FlatString,    NULL, 0, "Prefix"},
-       {{HKEY("suffix")}, FlatString,    NULL, 0, "Suffix"},
-       {{HKEY("")},       TerminateList, NULL, 0, ""}
+       {{HKEY("last")},   FlatString,    NULL, 0, 0, {HKEY("Last Name")}},
+       {{HKEY("first")},  FlatString,    NULL, 0, 0, {HKEY("First Name")}},
+       {{HKEY("middle")}, FlatString,    NULL, 0, 0, {HKEY("Middle Name")}},
+       {{HKEY("prefix")}, FlatString,    NULL, 0, 0, {HKEY("Prefix")}},
+       {{HKEY("suffix")}, FlatString,    NULL, 0, 0, {HKEY("Suffix")}},
+       {{HKEY("")},       TerminateList, NULL, 0, 0, {HKEY("")}}
 };
 
 vcField VCStr_Addrs [] = {
-       {{HKEY("POBox")},    FlatString,    NULL, 0, "PO box"},
-       {{HKEY("address")},  FlatString,    NULL, 0, "Address"},
-       {{HKEY("address2")}, FlatString,    NULL, 0, ""},
-       {{HKEY("city")},     FlatString,    NULL, 0, "City"},
-       {{HKEY("state")},    FlatString,    NULL, 0, "State"},
-       {{HKEY("zip")},      FlatString,    NULL, 0, "ZIP code"},
-       {{HKEY("country")},  FlatString,    NULL, 0, "Country"},
-       {{HKEY("")},         TerminateList, NULL, 0, ""}
+       {{HKEY("POBox")},    Address,       NULL, 0, 0, {HKEY("PO box")}},
+       {{HKEY("extadr")},   Address,       NULL, 0, 0, {HKEY("Address")}},
+       {{HKEY("street")},   Address,       NULL, 0, 0, {HKEY("")}},
+       {{HKEY("city")},     Address,       NULL, 0, 0, {HKEY("City")}},
+       {{HKEY("state")},    Address,       NULL, 0, 0, {HKEY("State")}},
+       {{HKEY("zip")},      Address,       NULL, 0, 0, {HKEY("ZIP code")}},
+       {{HKEY("country")},  Address,       NULL, 0, 0, {HKEY("Country")}},
+       {{HKEY("")},         TerminateList, NULL, 0, 0, {HKEY("")}}
 };
 
 vcField VCStrE [] = {
-       {{HKEY("version")},         Number,                 NULL,        0, ""},
-       {{HKEY("rev")},             Number,                 NULL,        0, ""},
-       {{HKEY("label")},           FlatString,             NULL,        0, ""},
-       {{HKEY("uid")},             FlatString,             NULL,        0, ""},
-       {{HKEY("n")},               StringCluster,          VCStr_Ns,    0, ""}, /* N is name, but only if there's no FN already there */
-       {{HKEY("fn")},              FlatString,             NULL,        0, ""}, /* FN (full name) is a true 'display name' field */
-       {{HKEY("title")},           FlatString,             NULL,        0, "Title:"},
-       {{HKEY("org")},             FlatString,             NULL,        0, "Organization:"},/* organization */
-       {{HKEY("email")},           EmailAddr,              NULL,        0, "E-mail:"},
-       {{HKEY("tel")},             PhoneNumber,            NULL,        0, "Telephone:"},
-       {{HKEY("adr")},             StringCluster,          VCStr_Addrs, 0, "Address:"},
-       {{HKEY("photo")},           Base64BinaryAttachment, NULL,        0, "Photo:"},
-       {{HKEY("tel;home")},        PhoneNumber,            NULL,        0, " (home)"},
-       {{HKEY("tel;work")},        PhoneNumber,            NULL,        0, " (work)"},
-       {{HKEY("tel;fax")},         PhoneNumber,            NULL,        0, " (fax)"},
-       {{HKEY("tel;cell")},        PhoneNumber,            NULL,        0, " (cell)"},
-       {{HKEY("email;internet")},  EmailAddr,              NULL,        0, "E-mail:"},
-       {{HKEY("")},                TerminateList,          NULL,        0, ""}
+       {{HKEY("version")},         Number,                 NULL,        0, 0, {HKEY("")}},
+       {{HKEY("rev")},             Number,                 NULL,        0, 0, {HKEY("")}},
+       {{HKEY("label")},           FlatString,             NULL,        0, 0, {HKEY("")}},
+       {{HKEY("uid")},             FlatString,             NULL,        0, 0, {HKEY("")}},
+       {{HKEY("n")},               StringCluster,          VCStr_Ns,    0, 0, {HKEY("")}}, /* N is name, but only if there's no FN already there */
+       {{HKEY("fn")},              FlatString,             NULL,        0, 0, {HKEY("")}}, /* FN (full name) is a true 'display name' field */
+       {{HKEY("title")},           FlatString,             NULL,        0, 0, {HKEY("Title:")}},
+       {{HKEY("org")},             FlatString,             NULL,        0, 0, {HKEY("Organization:")}},/* organization */
+       {{HKEY("email")},           EmailAddr,              NULL,        0, 0, {HKEY("E-mail:")}},
+       {{HKEY("tel")},             PhoneNumber,            NULL,        0, 0, {HKEY("Telephone:")}},
+       {{HKEY("adr")},             StringCluster,          VCStr_Addrs, 0, 0, {HKEY("Address:")}},
+       {{HKEY("photo")},           Base64BinaryAttachment, NULL,        0, 0, {HKEY("Photo:")}},
+       {{HKEY("tel;home")},        PhoneNumber,            NULL,        0, 0, {HKEY(" (home)")}},
+       {{HKEY("tel;work")},        PhoneNumber,            NULL,        0, 0, {HKEY(" (work)")}},
+       {{HKEY("tel;fax")},         PhoneNumber,            NULL,        0, 0, {HKEY(" (fax)")}},
+       {{HKEY("tel;cell")},        PhoneNumber,            NULL,        0, 0, {HKEY(" (cell)")}},
+       {{HKEY("email;internet")},  EmailAddr,              NULL,        0, 0, {HKEY("E-mail:")}},
+       {{HKEY("UNKNOWN")},         UnKnown,                NULL,        0, 0, {HKEY("")}},
+       {{HKEY("")},                TerminateList,          NULL,        0, 0, {HKEY("")}}
 };
 
 ConstStr VCStr [] = {
@@ -101,12 +106,16 @@ ConstStr VCStr [] = {
 HashList *DefineToToken = NULL;
 HashList *VCTokenToDefine = NULL;
 HashList *vcNames = NULL; /* todo: fill with the name strings */
-
+vcField* vcfUnknown = NULL;
 
 void RegisterVCardToken(vcField* vf, StrBuf *name, int inTokenCount)
 {
+       if (vf->Type == UnKnown) {
+               vcfUnknown = vf;
+       }
        RegisterTokenParamDefine(SKEY(name), vf->cval);
        Put(DefineToToken, LKEY(vf->cval), vf, reference_free_handler);
+       Put(vcNames, LKEY(vf->cval), NewStrBufPlain(CKEY(vf->Name)), HFreeStrBuf);
 
        syslog(LOG_DEBUG, "Token: %s -> %ld, %d", 
               ChrPtr(name),
@@ -115,12 +124,14 @@ void RegisterVCardToken(vcField* vf, StrBuf *name, int inTokenCount)
 
 }
 
-void autoRegisterTokens(long *enumCounter, vcField* vf, StrBuf *BaseStr, int layer)
+void autoRegisterTokens(long *enumCounter, vcField* vf, StrBuf *BaseStr, int layer, long parentCVal)
 {
        int i = 0;
+       StrBuf *subStr = NewStrBuf();
        while (vf[i].STR.len > 0) {
-               StrBuf *subStr = NewStrBuf();
+               FlushStrBuf(subStr);
                vf[i].cval = (*enumCounter) ++;
+               vf[i].parentCVal = parentCVal;
                StrBufAppendBuf(subStr, BaseStr, 0);
                if (StrLength(subStr) > 0) {
                        StrBufAppendBufPlain(subStr, HKEY("."), 0);
@@ -134,9 +145,7 @@ void autoRegisterTokens(long *enumCounter, vcField* vf, StrBuf *BaseStr, int lay
                        break;
                case StringCluster:
                {
-                       autoRegisterTokens(enumCounter, vf[i].Sub, subStr, 1);
-                       i++;
-                       continue;
+                       autoRegisterTokens(enumCounter, vf[i].Sub, subStr, 1, vf[i].cval);
                }
                break;
                case PhoneNumber:
@@ -153,10 +162,15 @@ void autoRegisterTokens(long *enumCounter, vcField* vf, StrBuf *BaseStr, int lay
                        break;
                case TerminateList:
                        break;
+               case Address:
+                       break;
+               case UnKnown:
+                       break;
                }
                RegisterVCardToken(&vf[i], subStr, i);
                i++;
        }
+       FreeStrBuf(&subStr);
 }
 
 int preeval_vcard_item(WCTemplateToken *Token)
@@ -188,6 +202,26 @@ void tmpl_vcard_item(StrBuf *Target, WCTemplputParams *TP)
        }
 }
 
+void tmpl_vcard_context_item(StrBuf *Target, WCTemplputParams *TP)
+{
+       void *vItem;
+       vcField *t = (vcField*) CTX(CTX_VCARD_TYPE);
+       HashList *vc = (HashList*) CTX(CTX_VCARD);
+
+       if (t == NULL) {
+               LogTemplateError(NULL, "VCard item", ERR_NAME, TP,
+                                "Missing context");
+               return;
+       }
+
+       if (GetHash(vc, LKEY(t->cval), &vItem) && (vItem != NULL)) {
+               StrBufAppendTemplate(Target, TP, (StrBuf*) vItem, 0);
+       }
+       else {
+               LogTemplateError(NULL, "VCard item", ERR_NAME, TP,
+                                "Doesn't have that key - did you miss to filter in advance?");
+       }
+}
 int preeval_vcard_name_str(WCTemplateToken *Token)
 {
        WCTemplputParams TPP;
@@ -215,29 +249,86 @@ void tmpl_vcard_name_str(StrBuf *Target, WCTemplputParams *TP)
        if (GetHash(vcNames, LKEY(searchFieldNo), &vItem) && (vItem != NULL)) {
                StrBufAppendTemplate(Target, TP, (StrBuf*) vItem, 1);
        }
+       else {
+               LogTemplateError(NULL, "VCard item type", ERR_NAME, TP,
+                                "No i18n string for this.");
+               return;
+       }
+}
+
+void tmpl_vcard_context_name_str(StrBuf *Target, WCTemplputParams *TP)
+{
+       void *vItem;
+       vcField *t = (vcField*) CTX(CTX_VCARD_TYPE);
+
+       if (t == NULL) {
+               LogTemplateError(NULL, "VCard item type", ERR_NAME, TP,
+                                "Missing context");
+               return;
+       }
+       
+       if (GetHash(vcNames, LKEY(t->cval), &vItem) && (vItem != NULL)) {
+               StrBufAppendTemplate(Target, TP, (StrBuf*) vItem, 1);
+       }
+       else {
+               LogTemplateError(NULL, "VCard item type", ERR_NAME, TP,
+                                "No i18n string for this.");
+               return;
+       }
 }
 
 int filter_VC_ByType(const char* key, long len, void *Context, StrBuf *Target, WCTemplputParams *TP)
 {
        long searchType;
        long type = 0;
-       void *vvcField;
+       void *v;
        int rc = 0;
+       vcField *vf = (vcField*) Context;
 
-       memcpy(type, key, sizeof(long));
-       searchType = GetTemplateTokenNumber(Target, TP, 3, 0);/// todo: which?
+       memcpy(&type, key, sizeof(long));
+       searchType = GetTemplateTokenNumber(Target, TP, IT_ADDT_PARAM(0), 0);
        
-       if (GetHash(DefineToToken, LKEY(type), &vvcField) &&
-           (vvcField != NULL))
-       {
-               vcField *t = (vcField*) vvcField;
-               if (t && t->Type == searchType) {
-                       rc = 1; 
-               }
+       if (vf->Type == searchType) {
+               HashList *vc = (HashList*) CTX(CTX_VCARD);
+               if (GetHash(vc, LKEY(vf->cval), &v) && v != NULL)
+                       return 1;
        }
        return rc;
 }
 
+
+
+
+HashList *getContextVcard(StrBuf *Target, WCTemplputParams *TP)
+{
+       vcField *vf = (vcField*) CTX(CTX_VCARD_TYPE);
+       HashList *vc = (HashList*) CTX(CTX_VCARD);
+
+       if ((vf == NULL) || (vc == NULL)) {
+               LogTemplateError(NULL, "VCard item type", ERR_NAME, TP,
+                                "Need VCard and Vcard type in context");
+               
+               return NULL;
+       }
+       return vc;
+}
+
+int filter_VC_ByContextType(const char* key, long len, void *Context, StrBuf *Target, WCTemplputParams *TP)
+{
+       long searchType;
+       vcField *vf = (vcField*) CTX(CTX_VCARD_TYPE);
+
+       memcpy(&searchType, key, sizeof(long));
+       
+       if (vf->cval == searchType) {
+               return 1;
+       }
+       else {
+               return 0;
+       }
+}
+
+
 int conditional_VC_Havetype(StrBuf *Target, WCTemplputParams *TP)
 {
        HashList *vc = (HashList*) CTX(CTX_VCARD);
@@ -489,265 +580,8 @@ void fetchname_parsed_vcard(struct vCard *v, char **storename) {
 
 
 
-/*
- * html print a vcard
- * display_vcard() calls this after parsing the textual vCard into
- * our 'struct vCard' data object.
- *
- * Set 'full' to nonzero to display the full card, otherwise it will only
- * show a summary line.
- *
- * This code is a bit ugly, so perhaps an explanation is due: we do this
- * in two passes through the vCard fields.  On the first pass, we process
- * fields we understand, and then render them in a pretty fashion at the
- * end.  Then we make a second pass, outputting all the fields we don't
- * understand in a simple two-column name/value format.
- * v           the vCard to display
- * full                display all items of the vcard?
- * msgnum      Citadel message pointer
- */
-void display_parsed_vcard(StrBuf *Target, struct vCard *v, int full, wc_mime_attachment *Mime)
-{
-       int i, j;
-       char buf[SIZ];
-       char *name;
-       int is_qp = 0;
-       int is_b64 = 0;
-       char *thisname, *thisvalue;
-       char firsttoken[SIZ];
-       int pass;
-
-       char fullname[SIZ];
-       char title[SIZ];
-       char org[SIZ];
-       char phone[SIZ];
-       char mailto[SIZ];
-
-       strcpy(fullname, "");
-       strcpy(phone, "");
-       strcpy(mailto, "");
-       strcpy(title, "");
-       strcpy(org, "");
-
-       if (!full) {
-               StrBufAppendPrintf(Target, "<td>");
-               name = vcard_get_prop(v, "fn", 1, 0, 0);
-               if (name != NULL) {
-                       StrEscAppend(Target, NULL, name, 0, 0);
-               }
-               else if (name = vcard_get_prop(v, "n", 1, 0, 0), name != NULL) {
-                       strcpy(fullname, name);
-                       vcard_n_prettyize(fullname);
-                       StrEscAppend(Target, NULL, fullname, 0, 0);
-               }
-               else {
-                       StrBufAppendPrintf(Target, "&nbsp;");
-               }
-               StrBufAppendPrintf(Target, "</td>");
-               return;
-       }
-
-       StrBufAppendPrintf(Target, "<div align=\"center\">"
-               "<table bgcolor=\"#aaaaaa\" width=\"50%%\">");
-       for (pass=1; pass<=2; ++pass) {
-
-               if (v->numprops) for (i=0; i<(v->numprops); ++i) {
-                       int len;
-                       thisname = strdup(v->prop[i].name);
-                       extract_token(firsttoken, thisname, 0, ';', sizeof firsttoken);
-       
-                       for (j=0; j<num_tokens(thisname, ';'); ++j) {
-                               extract_token(buf, thisname, j, ';', sizeof buf);
-                               if (!strcasecmp(buf, "encoding=quoted-printable")) {
-                                       is_qp = 1;
-                                       remove_token(thisname, j, ';');
-                               }
-                               if (!strcasecmp(buf, "encoding=base64")) {
-                                       is_b64 = 1;
-                                       remove_token(thisname, j, ';');
-                               }
-                       }
-                       
-                       len = strlen(v->prop[i].value);
-                       /* if we have some untagged QP, detect it here. */
-                       if (!is_qp && (strstr(v->prop[i].value, "=?")!=NULL))
-                               utf8ify_rfc822_string(&v->prop[i].value);
-
-                       if (is_qp) {
-                               /* %ff can become 6 bytes in utf8 */
-                               thisvalue = malloc(len * 2 + 3); 
-                               j = CtdlDecodeQuotedPrintable(
-                                       thisvalue, v->prop[i].value,
-                                       len);
-                               thisvalue[j] = 0;
-                       }
-                       else if (is_b64) {
-                               /* ff will become one byte.. */
-                               thisvalue = malloc(len + 50);
-                               CtdlDecodeBase64(
-                                       thisvalue, v->prop[i].value,
-                                       strlen(v->prop[i].value) );
-                       }
-                       else {
-                               thisvalue = strdup(v->prop[i].value);
-                       }
-       
-                       /* Various fields we may encounter ***/
-       
-                       /* N is name, but only if there's no FN already there */
-                       if (!strcasecmp(firsttoken, "n")) {
-                               if (IsEmptyStr(fullname)) {
-                                       strcpy(fullname, thisvalue);
-                                       vcard_n_prettyize(fullname);
-                               }
-                       }
-       
-                       /* FN (full name) is a true 'display name' field */
-                       else if (!strcasecmp(firsttoken, "fn")) {
-                               strcpy(fullname, thisvalue);
-                       }
-
-                       /* title */
-                       else if (!strcasecmp(firsttoken, "title")) {
-                               strcpy(title, thisvalue);
-                       }
-       
-                       /* organization */
-                       else if (!strcasecmp(firsttoken, "org")) {
-                               strcpy(org, thisvalue);
-                       }
-       
-                       else if (!strcasecmp(firsttoken, "email")) {
-                               size_t len;
-                               if (!IsEmptyStr(mailto)) strcat(mailto, "<br>");
-                               strcat(mailto,
-                                       "<a href=\"display_enter"
-                                       "?force_room=_MAIL_?recp=");
-
-                               len = strlen(mailto);
-                               urlesc(&mailto[len], SIZ - len, "\"");
-                               len = strlen(mailto);
-                               urlesc(&mailto[len], SIZ - len,  fullname);
-                               len = strlen(mailto);
-                               urlesc(&mailto[len], SIZ - len, "\" <");
-                               len = strlen(mailto);
-                               urlesc(&mailto[len], SIZ - len, thisvalue);
-                               len = strlen(mailto);
-                               urlesc(&mailto[len], SIZ - len, ">");
-
-                               strcat(mailto, "\">");
-                               len = strlen(mailto);
-                               stresc(mailto+len, SIZ - len, thisvalue, 1, 1);
-                               strcat(mailto, "</A>");
-                       }
-                       else if (!strcasecmp(firsttoken, "tel")) {
-                               if (!IsEmptyStr(phone)) strcat(phone, "<br>");
-                               strcat(phone, thisvalue);
-                               for (j=0; j<num_tokens(thisname, ';'); ++j) {
-                                       extract_token(buf, thisname, j, ';', sizeof buf);
-                                       if (!strcasecmp(buf, "tel"))
-                                               strcat(phone, "");
-                                       else if (!strcasecmp(buf, "work"))
-                                               strcat(phone, _(" (work)"));
-                                       else if (!strcasecmp(buf, "home"))
-                                               strcat(phone, _(" (home)"));
-                                       else if (!strcasecmp(buf, "cell"))
-                                               strcat(phone, _(" (cell)"));
-                                       else {
-                                               strcat(phone, " (");
-                                               strcat(phone, buf);
-                                               strcat(phone, ")");
-                                       }
-                               }
-                       }
-                       else if (!strcasecmp(firsttoken, "adr")) {
-                               if (pass == 2) {
-                                       StrBufAppendPrintf(Target, "<tr><td>");
-                                       StrBufAppendPrintf(Target, _("Address:"));
-                                       StrBufAppendPrintf(Target, "</td><td>");
-                                       for (j=0; j<num_tokens(thisvalue, ';'); ++j) {
-                                               extract_token(buf, thisvalue, j, ';', sizeof buf);
-                                               if (!IsEmptyStr(buf)) {
-                                                       StrEscAppend(Target, NULL, buf, 0, 0);
-                                                       if (j<3) StrBufAppendPrintf(Target, "<br>");
-                                                       else StrBufAppendPrintf(Target, " ");
-                                               }
-                                       }
-                                       StrBufAppendPrintf(Target, "</td></tr>\n");
-                               }
-                       }
-                       /* else if (!strcasecmp(firsttoken, "photo") && full && pass == 2) { 
-                               // Only output on second pass
-                               StrBufAppendPrintf(Target, "<tr><td>");
-                               StrBufAppendPrintf(Target, _("Photo:"));
-                               StrBufAppendPrintf(Target, "</td><td>");
-                               StrBufAppendPrintf(Target, "<img src=\"/vcardphoto/%ld/\" alt=\"Contact photo\"/>",msgnum);
-                               StrBufAppendPrintf(Target, "</td></tr>\n");
-                       } */
-                       else if (!strcasecmp(firsttoken, "version")) {
-                               /* ignore */
-                       }
-                       else if (!strcasecmp(firsttoken, "rev")) {
-                               /* ignore */
-                       }
-                       else if (!strcasecmp(firsttoken, "label")) {
-                               /* ignore */
-                       }
-                       else {
 
-                               /*** Don't show extra fields.  They're ugly.
-                               if (pass == 2) {
-                                       StrBufAppendPrintf(Target, "<TR><TD>");
-                                       StrEscAppend(Target, NULL, thisname, 0, 0);
-                                       StrBufAppendPrintf(Target, "</TD><TD>");
-                                       StrEscAppend(Target, NULL, thisvalue, 0, 0);
-                                       StrBufAppendPrintf(Target, "</TD></TR>\n");
-                               }
-                               ***/
-                       }
-       
-                       free(thisname);
-                       free(thisvalue);
-               }
-       
-               if (pass == 1) {
-                       StrBufAppendPrintf(Target, "<tr bgcolor=\"#aaaaaa\">"
-      "<td colspan=2 bgcolor=\"#ffffff\">"
-      "<img align=\"center\" src=\"static/webcit_icons/essen/32x32/contact.png\">"
-      "<font size=\"+1\"><b>");
-                       StrEscAppend(Target, NULL, fullname, 0, 0);
-                       StrBufAppendPrintf(Target, "</b></font>");
-                       if (!IsEmptyStr(title)) {
-                               StrBufAppendPrintf(Target, "<div align=\"right>\"");
-                               StrEscAppend(Target, NULL, title, 0, 0);
-                               StrBufAppendPrintf(Target, "</div>");
-                       }
-                       if (!IsEmptyStr(org)) {
-                               StrBufAppendPrintf(Target, "<div align=\"right\">");
-                               StrEscAppend(Target, NULL, org, 0, 0);
-                               StrBufAppendPrintf(Target, "</div>");
-                       }
-                       StrBufAppendPrintf(Target, "</td></tr>\n");
-               
-                       if (!IsEmptyStr(phone)) {
-                               StrBufAppendPrintf(Target, "<tr><td>");
-                               StrBufAppendPrintf(Target, _("Telephone:"));
-                               StrBufAppendPrintf(Target, "</td><td>%s</td></tr>\n", phone);
-                       }
-                       if (!IsEmptyStr(mailto)) {
-                               StrBufAppendPrintf(Target, "<tr><td>");
-                               StrBufAppendPrintf(Target, _("E-mail:"));
-                               StrBufAppendPrintf(Target, "</td><td>%s</td></tr>\n", mailto);
-                       }
-               }
-
-       }
-
-       StrBufAppendPrintf(Target, "</table></div>\n");
-}
-
-
-void PutVcardItem(vcField *thisField, HashList *thisVC, StrBuf *ThisFieldStr, int is_qp, StrBuf *Swap)
+void PutVcardItem(HashList *thisVC, vcField *thisField, StrBuf *ThisFieldStr, int is_qp, StrBuf *Swap)
 {
        /* if we have some untagged QP, detect it here. */
        if (is_qp || (strstr(ChrPtr(ThisFieldStr), "=?")!=NULL)){
@@ -773,27 +607,23 @@ void PutVcardItem(vcField *thisField, HashList *thisVC, StrBuf *ThisFieldStr, in
  * fields we understand, and then render them in a pretty fashion at the
  * end.  Then we make a second pass, outputting all the fields we don't
  * understand in a simple two-column name/value format.
- * v           the vCard to display
- * full                display all items of the vcard?
+ * v           the vCard to parse
  * msgnum      Citadel message pointer
  */
-void parse_vcard(StrBuf *Target, struct vCard *v, HashList *VC, int full, wc_mime_attachment *Mime)
+void parse_vcard(StrBuf *Target, struct vCard *v, HashList *VC, wc_mime_attachment *Mime)
 {
        StrBuf *Val = NULL;
        StrBuf *Swap = NULL;
        int i, j, k;
-       char buf[20]; //SIZ];
+       char buf[SIZ];
        int is_qp = 0;
        int is_b64 = 0;
        int ntokens, len;
        StrBuf *thisname = NULL;
-       char firsttoken[20]; ///SIZ];
-       void *V;
-       HashList *thisVC;
+       char firsttoken[SIZ];
        StrBuf *thisVCToken;
        void *vField = NULL;
 
-       thisVC = NewHash(1, lFlathash);
        Swap = NewStrBuf ();
        thisname = NewStrBuf();
        thisVCToken = NewStrBufPlain(NULL, 63);
@@ -808,7 +638,7 @@ void parse_vcard(StrBuf *Target, struct vCard *v, HashList *VC, int full, wc_mim
                /*len = */extract_token(firsttoken, ChrPtr(thisname), 0, ';', sizeof firsttoken);
                ntokens = num_tokens(ChrPtr(thisname), ';');
                for (j=0, k=0; j < ntokens && k < 10; ++j) {
-                       int evc[10];
+                       ///int evc[10];
                        
                        len = extract_token(buf, ChrPtr(thisname), j, ';', sizeof buf);
                        if (!strcasecmp(buf, "encoding=quoted-printable")) {
@@ -856,11 +686,14 @@ void parse_vcard(StrBuf *Target, struct vCard *v, HashList *VC, int full, wc_mim
                                        StrBufExtract_NextToken(Buf, thisArray, &Pos, ';');
                                        ThisFieldStr = NewStrBufDup(Buf);
                                        
-                                       PutVcardItem(&thisField->Sub[j], thisVC, ThisFieldStr, is_qp, Swap);
+                                       PutVcardItem(VC, &thisField->Sub[j], ThisFieldStr, is_qp, Swap);
                                        j++;
                                }
+                               FreeStrBuf(&thisArray);
+                               FreeStrBuf(&Buf);
                        }
                                break;
+                       case Address:
                        case FlatString:
                        case PhoneNumber:
                        case EmailAddr:
@@ -869,15 +702,36 @@ void parse_vcard(StrBuf *Target, struct vCard *v, HashList *VC, int full, wc_mim
                        case AliasFor:
                                /* copy over the payload into a StrBuf */
                                ThisFieldStr = NewStrBufPlain(v->prop[i].value, -1);
-                               PutVcardItem(thisField, thisVC, ThisFieldStr, is_qp, Swap);
+                               PutVcardItem(VC, thisField, ThisFieldStr, is_qp, Swap);
 
                                break;
                        case Base64BinaryAttachment:
                        case TerminateList:
+                       case UnKnown:
                                break;
                        }
 
                }
+               else if (StrLength(thisVCToken) > 0) {
+                       /* Add it to the UNKNOWN field... */
+                       void *pv = NULL;
+                       StrBuf *oldVal;
+                       GetHash(VC, IKEY(vcfUnknown->cval), &pv);
+                       oldVal = (StrBuf*) pv;
+                       if (oldVal == NULL) {
+                               oldVal = NewStrBuf();
+                               Put(VC, IKEY(vcfUnknown->cval), oldVal, HFreeStrBuf);
+                       }
+                       else {
+                               StrBufAppendBufPlain(oldVal, HKEY("\n"), 0);
+                       }
+
+                       StrBufAppendBuf(oldVal, thisVCToken, 0);
+                       StrBufAppendBufPlain(oldVal, HKEY(":"), 0);
+                       StrBufAppendBufPlain(oldVal, v->prop[i].value, -1, 0);
+                       continue;
+               }
+
                /* copy over the payload into a StrBuf */
                Val = NewStrBufPlain(v->prop[i].value, -1);
                        
@@ -892,7 +746,6 @@ void parse_vcard(StrBuf *Target, struct vCard *v, HashList *VC, int full, wc_mim
                }
                else if (is_b64) {
                        StrBufDecodeBase64(Val);
-
                }
 #if 0
                syslog(LOG_DEBUG, "-> firsttoken: %s thisname: %s Value: [%s][%s]",
@@ -940,24 +793,10 @@ TODO: check for layer II
 */
 #endif 
                FreeStrBuf(&Val);
-               ////free(thisname);
-               /// thisname = NULL;
        }
-
-
-       {
-               WCTemplputParams *TP = NULL;
-               WCTemplputParams SubTP;
-               FlushStrBuf(Target);
-               StackContext(TP, &SubTP, thisVC, CTX_VCARD, 0, NULL);
-               {
-                       DoTemplate(HKEY("test_vcard"), Target, &SubTP);
-               }
-               UnStackContext(&SubTP);
-       }
-       printf("%s\n", ChrPtr(Target));
+       FreeStrBuf(&thisname);
+       FreeStrBuf(&Swap);
        FreeStrBuf(&thisVCToken);
-       DeleteHash(&thisVC);/// todo
 }
 
 void tmplput_VCARD_ITEM(StrBuf *Target, WCTemplputParams *TP)
@@ -979,21 +818,24 @@ void tmplput_VCARD_ITEM(StrBuf *Target, WCTemplputParams *TP)
        
 }
 
-void new_vcard (StrBuf *Target, struct vCard *v, int full, wc_mime_attachment *Mime)
+void display_one_vcard (StrBuf *Target, struct vCard *v, int full, wc_mime_attachment *Mime)
 {
-       HashList *VC;
-       WCTemplputParams SubTP;
+       HashList *VC;   WCTemplputParams SubTP;
 
         memset(&SubTP, 0, sizeof(WCTemplputParams));    
 
 
-       VC = NewHash(0, Flathash);
-       parse_vcard(Target, v, VC, full, Mime);
+       VC = NewHash(0, lFlathash);
+       parse_vcard(Target, v, VC, Mime);
 
-       SubTP.Filter.ContextType = CTX_VCARD;
-       SubTP.Context = VC;
+       {
+               WCTemplputParams *TP = NULL;
+               WCTemplputParams SubTP;
+               StackContext(TP, &SubTP, VC, CTX_VCARD, 0, NULL);
 
-       DoTemplate(HKEY("test_vcard"), Target, &SubTP);
+               DoTemplate(HKEY("vcard_msg_display"), Target, &SubTP);
+               UnStackContext(&SubTP);
+       }
        DeleteHash(&VC);
 }
 
@@ -1047,12 +889,7 @@ void display_vcard(StrBuf *Target,
                 ((!isalpha(alpha)) && (!isalpha(this_alpha)))
                ) 
        {
-#define XXX_XXX 1
-#ifdef XXX_XXX
-               new_vcard (Target, v, full, Mime);
-#else
-               display_parsed_vcard(Target, v, full, Mime);
-#endif         
+               display_one_vcard (Target, v, full, Mime);
        }
 
        vcard_free(v);
@@ -1182,59 +1019,16 @@ void do_edit_vcard(long msgnum, char *partnum,
                   wc_mime_attachment *VCAtt,
                   const char *return_to, 
                   const char *force_room) {
+       HashList *VC;   WCTemplputParams SubTP;
        wcsession *WCC = WC;
        message_summary *Msg = NULL;
        wc_mime_attachment *VCMime = NULL;
        struct vCard *v;
-       int i;
-       char *key, *value;
        char whatuser[256];
+       VC = NewHash(0, lFlathash);
 
-       char lastname[256];
-       char firstname[256];
-       char middlename[256];
-       char prefix[256];
-       char suffix[256];
-       char pobox[256];
-       char extadr[256];
-       char street[256];
-       char city[256];
-       char state[256];
-       char zipcode[256];
-       char country[256];
-       char hometel[256];
-       char worktel[256];
-       char faxtel[256];
-       char mobiletel[256];
-       char primary_inetemail[256];
-       char other_inetemail[SIZ];
-       char extrafields[SIZ];
-       char fullname[256];
-       char title[256];
-       char org[256];
-
-       lastname[0] = 0;
-       firstname[0] = 0;
-       middlename[0] = 0;
-       prefix[0] = 0;
-       suffix[0] = 0;
-       pobox[0] = 0;
-       extadr[0] = 0;
-       street[0] = 0;
-       city[0] = 0;
-       state[0] = 0;
-       zipcode[0] = 0;
-       country[0] = 0;
-       hometel[0] = 0;
-       worktel[0] = 0;
-       faxtel[0] = 0;
-       mobiletel[0] = 0;
-       primary_inetemail[0] = 0;
-       other_inetemail[0] = 0;
-       title[0] = 0;
-       org[0] = 0;
-       extrafields[0] = 0;
-       fullname[0] = 0;
+       /* Display the form */
+       output_headers(1, 1, 1, 0, 0, 0);
 
        safestrncpy(whatuser, "", sizeof whatuser);
 
@@ -1258,279 +1052,26 @@ void do_edit_vcard(long msgnum, char *partnum,
                else {
                        v = VCardLoad(VCAtt->Data);
                }
-       
-               /* Populate the variables for our form */
-               i = 0;
-               while (key = vcard_get_prop(v, "", 0, i, 1), key != NULL) {
-                       char prp[256];  /* property name */
-                       char prm[256];  /* parameters */
 
-                       value = vcard_get_prop(v, "", 0, i++, 0);
-
-
-                       extract_token(prp, key, 0, ';', sizeof prp);
-                       safestrncpy(prm, key, sizeof prm);
-                       remove_token(prm, 0, ';');
-
-                       if (!strcasecmp(prp, "n")) {
-                               extract_token(lastname, value, 0, ';', sizeof lastname);
-                               extract_token(firstname, value, 1, ';', sizeof firstname);
-                               extract_token(middlename, value, 2, ';', sizeof middlename);
-                               extract_token(prefix, value, 3, ';', sizeof prefix);
-                               extract_token(suffix, value, 4, ';', sizeof suffix);
-                       }
-
-                       else if (!strcasecmp(prp, "fn")) {
-                               safestrncpy(fullname, value, sizeof fullname);
-                       }
-
-                       else if (!strcasecmp(prp, "title")) {
-                               safestrncpy(title, value, sizeof title);
-                       }
-       
-                       else if (!strcasecmp(prp, "org")) {
-                               safestrncpy(org, value, sizeof org);
-                       }
-       
-                       else if (!strcasecmp(prp, "adr")) {
-                               extract_token(pobox, value, 0, ';', sizeof pobox);
-                               extract_token(extadr, value, 1, ';', sizeof extadr);
-                               extract_token(street, value, 2, ';', sizeof street);
-                               extract_token(city, value, 3, ';', sizeof city);
-                               extract_token(state, value, 4, ';', sizeof state);
-                               extract_token(zipcode, value, 5, ';', sizeof zipcode);
-                               extract_token(country, value, 6, ';', sizeof country);
-                       }
-
-                       else if (!strcasecmp(prp, "tel")) {
-
-                               if (bmstrcasestr(prm, "home")) {
-                                       extract_token(hometel, value, 0, ';', sizeof hometel);
-                               }
-                               else if (bmstrcasestr(prm, "work")) {
-                                       extract_token(worktel, value, 0, ';', sizeof worktel);
-                               }
-                               else if (bmstrcasestr(prm, "fax")) {
-                                       extract_token(faxtel, value, 0, ';', sizeof faxtel);
-                               }
-                               else if (bmstrcasestr(prm, "cell")) {
-                                       extract_token(mobiletel, value, 0, ';', sizeof mobiletel);
-                               }
-                               else {  /* Missing or unknown type; put it in the home phone */
-                                       extract_token(hometel, value, 0, ';', sizeof hometel);
-                               }
-                       }
+               parse_vcard(WCC->WBuf, v, VC, NULL);
        
-                       else if ( (!strcasecmp(prp, "email")) && (bmstrcasestr(prm, "internet")) ) {
-                               if (primary_inetemail[0] == 0) {
-                                       safestrncpy(primary_inetemail, value, sizeof primary_inetemail);
-                               }
-                               else {
-                                       if (other_inetemail[0] != 0) {
-                                               strcat(other_inetemail, "\n");
-                                       }
-                                       strcat(other_inetemail, value);
-                               }
-                       }
-
-                       /* Unrecognized properties are preserved here so we don't discard them
-                        * just because the vCard was edited with WebCit.
-                        */
-                       else {
-                               strcat(extrafields, key);
-                               strcat(extrafields, ":");
-                               strcat(extrafields, value);
-                               strcat(extrafields, "\n");
-                       }
-       
-               }
        
                vcard_free(v);
        }
 
-       /* Display the form */
-       output_headers(1, 1, 1, 0, 0, 0);
-
-       do_template("box_begin_1");
-       StrBufAppendBufPlain(WC->WBuf, _("Edit contact information"), -1, 0);
-       do_template("box_begin_2");
-
-       wc_printf("<form method=\"POST\" action=\"submit_vcard\">\n");
-       wc_printf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
+        memset(&SubTP, 0, sizeof(WCTemplputParams));    
 
-       if (force_room != NULL) {
-               wc_printf("<input type=\"hidden\" name=\"force_room\" value=\"");
-               escputs(force_room);
-               wc_printf("\">\n");
-       }
-       else
        {
-               wc_printf("<input type=\"hidden\" name=\"go\" value=\"");
-               StrEscAppend(WCC->WBuf, WCC->CurRoom.name, NULL, 0, 0);
-               wc_printf("\">\n");
-       }
-
-       wc_printf("<table class=\"vcard_edit_background\"><tr><td>\n");
-
-       wc_printf("<table border=\"0\"><tr>"
-               "<td>%s</td>"
-               "<td>%s</td>"
-               "<td>%s</td>"
-               "<td>%s</td>"
-               "<td>%s</td></tr>\n",
-               _("Prefix"), _("First Name"), _("Middle Name"), _("Last Name"), _("Suffix")
-       );
-       wc_printf("<tr><td><input type=\"text\" name=\"prefix\" "
-               "value=\"%s\" maxlength=\"5\" size=\"5\"></td>",
-               prefix);
-       wc_printf("<td><input type=\"text\" name=\"firstname\" "
-               "value=\"%s\" maxlength=\"29\"></td>",
-               firstname);
-       wc_printf("<td><input type=\"text\" name=\"middlename\" "
-               "value=\"%s\" maxlength=\"29\"></td>",
-               middlename);
-       wc_printf("<td><input type=\"text\" name=\"lastname\" "
-               "value=\"%s\" maxlength=\"29\"></td>",
-               lastname);
-       wc_printf("<td><input type=\"text\" name=\"suffix\" "
-               "value=\"%s\" maxlength=\"10\" size=\"10\"></td></tr></table>\n",
-               suffix);
-
-       wc_printf("<table  class=\"vcard_edit_background_alt\">");
-       wc_printf("<tr><td>");
-
-       wc_printf(_("Display name:"));
-       wc_printf("<br>"
-               "<input type=\"text\" name=\"fullname\" "
-               "value=\"%s\" maxlength=\"40\"><br><br>\n",
-               fullname
-       );
+               WCTemplputParams *TP = NULL;
+               WCTemplputParams SubTP;
+               StackContext(TP, &SubTP, VC, CTX_VCARD, 0, NULL);
 
-       wc_printf(_("Title:"));
-       wc_printf("<br>"
-               "<input type=\"text\" name=\"title\" "
-               "value=\"%s\" maxlength=\"40\"><br><br>\n",
-               title
-       );
+               DoTemplate(HKEY("vcard_edit"), WCC->WBuf, &SubTP);
+               UnStackContext(&SubTP);
+       }
+       DeleteHash(&VC);
 
-       wc_printf(_("Organization:"));
-       wc_printf("<br>"
-               "<input type=\"text\" name=\"org\" "
-               "value=\"%s\" maxlength=\"40\"><br><br>\n",
-               org
-       );
 
-       wc_printf("</td><td>");
-
-       wc_printf("<table border=\"0\">");
-       wc_printf("<tr><td>");
-       wc_printf(_("PO box:"));
-       wc_printf("</td><td>"
-               "<input type=\"text\" name=\"pobox\" "
-               "value=\"%s\" maxlength=\"29\"></td></tr>\n",
-               pobox);
-       wc_printf("<tr><td>");
-       wc_printf(_("Address:"));
-       wc_printf("</td><td>"
-               "<input type=\"text\" name=\"extadr\" "
-               "value=\"%s\" maxlength=\"29\"></td></tr>\n",
-               extadr);
-       wc_printf("<tr><td> </td><td>"
-               "<input type=\"text\" name=\"street\" "
-               "value=\"%s\" maxlength=\"29\"></td></tr>\n",
-               street);
-       wc_printf("<tr><td>");
-       wc_printf(_("City:"));
-       wc_printf("</td><td>"
-               "<input type=\"text\" name=\"city\" "
-               "value=\"%s\" maxlength=\"29\"></td></tr>\n",
-               city);
-       wc_printf("<tr><td>");
-       wc_printf(_("State:"));
-       wc_printf("</td><td>"
-               "<input type=\"text\" name=\"state\" "
-               "value=\"%s\" maxlength=\"29\"></td></tr>\n",
-               state);
-       wc_printf("<tr><td>");
-       wc_printf(_("ZIP code:"));
-       wc_printf("</td><td>"
-               "<input type=\"text\" name=\"zipcode\" "
-               "value=\"%s\" maxlength=\"10\"></td></tr>\n",
-               zipcode);
-       wc_printf("<tr><td>");
-       wc_printf(_("Country:"));
-       wc_printf("</td><td>"
-               "<input type=\"text\" name=\"country\" "
-               "value=\"%s\" maxlength=\"29\" width=\"5\"></td></tr>\n",
-               country);
-       wc_printf("</table>\n");
-
-       wc_printf("</table>\n");
-
-       wc_printf("<table border=0><tr><td>");
-       wc_printf(_("Home telephone:"));
-       wc_printf("</td>"
-               "<td><input type=\"text\" name=\"hometel\" "
-               "value=\"%s\" maxlength=\"29\"></td>\n",
-               hometel);
-       wc_printf("<td>");
-       wc_printf(_("Work telephone:"));
-       wc_printf("</td>"
-               "<td><input type=\"text\" name=\"worktel\" "
-               "value=\"%s\" maxlength=\"29\"></td></tr>\n",
-               worktel);
-       wc_printf("<tr><td>");
-       wc_printf(_("Mobile telephone:"));
-       wc_printf("</td>"
-               "<td><input type=\"text\" name=\"mobiletel\" "
-               "value=\"%s\" maxlength=\"29\"></td>\n",
-               mobiletel);
-       wc_printf("<td>");
-       wc_printf(_("Fax number:"));
-       wc_printf("</td>"
-               "<td><input type=\"text\" name=\"faxtel\" "
-               "value=\"%s\" maxlength=\"29\"></td></tr></table>\n",
-               faxtel);
-
-       wc_printf("<table class=\"vcard_edit_background_alt\">");
-       wc_printf("<tr><td>");
-
-       wc_printf("<table border=0><TR>"
-               "<td valign=top>");
-       wc_printf(_("Primary Internet e-mail address"));
-       wc_printf("<br>"
-               "<input type=\"text\" name=\"primary_inetemail\" "
-               "size=40 maxlength=60 value=\"");
-       escputs(primary_inetemail);
-       wc_printf("\"><br>"
-               "</td><td valign=top>");
-       wc_printf(_("Internet e-mail aliases"));
-       wc_printf("<br>"
-               "<textarea name=\"other_inetemail\" rows=5 cols=40 width=40>");
-       escputs(other_inetemail);
-       wc_printf("</textarea></td></tr></table>\n");
-
-       wc_printf("</td></tr></table>\n");
-
-       wc_printf("<input type=\"hidden\" name=\"extrafields\" value=\"");
-       escputs(extrafields);
-       wc_printf("\">\n");
-
-       wc_printf("<input type=\"hidden\" name=\"return_to\" value=\"");
-       escputs(return_to);
-       wc_printf("\">\n");
-
-       wc_printf("<div class=\"buttons\">\n"
-               "<input type=\"submit\" name=\"ok_button\" value=\"%s\">"
-               "&nbsp;"
-               "<input type=\"submit\" name=\"cancel_button\" value=\"%s\">"
-               "</div></form>\n",
-               _("Save changes"),
-               _("Cancel")
-       );
-       
-       wc_printf("</td></tr></table>\n");
-       do_template("box_end");
        wDumpContent(1);
        if (Msg != NULL) {
                DestroyMessageSummary(Msg);
@@ -1558,10 +1099,16 @@ void edit_vcard(void) {
 void submit_vcard(void) {
        struct vCard *v;
        char *serialized_vcard;
-       char buf[SIZ];
        StrBuf *Buf;
        const StrBuf *ForceRoom;
-       int i;
+       HashList* postVcard;
+       HashPos *it, *itSub;
+       const char *Key;
+       long len;
+       void *pv;
+       StrBuf *SubStr;
+       const StrBuf *s;
+       const char *Pos = NULL;
 
        if (!havebstr("ok_button")) { 
                readloop(readnew, eUseDefault);
@@ -1593,6 +1140,13 @@ void submit_vcard(void) {
                }
        }
 
+       postVcard = getSubStruct(HKEY("VC"));
+       if (postVcard == NULL) {
+               AppendImportantMessage(_("An error has occurred."), -1);
+               edit_vcard();
+               return;//// more details
+       }
+       
        Buf = NewStrBuf();
        serv_write(HKEY("ENT0 1|||4\n"));
        if (!StrBuf_ServGetln(Buf) && (GetServerStatus(Buf, NULL) != 4))
@@ -1600,7 +1154,7 @@ void submit_vcard(void) {
                edit_vcard();
                return;
        }
-
+       
        /* Make a vCard structure out of the data supplied in the form */
        StrBufPrintf(Buf, "begin:vcard\r\n%s\r\nend:vcard\r\n",
                     bstr("extrafields")
@@ -1613,41 +1167,100 @@ void submit_vcard(void) {
                return;
        }
 
-       snprintf(buf, sizeof buf, "%s;%s;%s;%s;%s",
-               bstr("lastname"),
-               bstr("firstname"),
-               bstr("middlename"),
-               bstr("prefix"),
-               bstr("suffix") );
-       vcard_add_prop(v, "n", buf);
-       
-       vcard_add_prop(v, "title", bstr("title"));
-       vcard_add_prop(v, "fn", bstr("fullname"));
-       vcard_add_prop(v, "org", bstr("org"));
-
-       snprintf(buf, sizeof buf, "%s;%s;%s;%s;%s;%s;%s",
-               bstr("pobox"),
-               bstr("extadr"),
-               bstr("street"),
-               bstr("city"),
-               bstr("state"),
-               bstr("zipcode"),
-               bstr("country") );
-       vcard_add_prop(v, "adr", buf);
-
-       vcard_add_prop(v, "tel;home", bstr("hometel"));
-       vcard_add_prop(v, "tel;work", bstr("worktel"));
-       vcard_add_prop(v, "tel;fax", bstr("faxtel"));
-       vcard_add_prop(v, "tel;cell", bstr("mobiletel"));
-       vcard_add_prop(v, "email;internet", bstr("primary_inetemail"));
-
-       for (i=0; i<num_tokens(bstr("other_inetemail"), '\n'); ++i) {
-               extract_token(buf, bstr("other_inetemail"), i, '\n', sizeof buf);
-               if (!IsEmptyStr(buf)) {
-                       vcard_add_prop(v, "email;internet", buf);
+       SubStr = NewStrBuf();
+       it = GetNewHashPos(DefineToToken, 0);
+       while (GetNextHashPos(DefineToToken, it, &len, &Key, &pv) && 
+              (pv != NULL)) 
+       {
+               char buf[32];
+               long blen;
+               vcField *t = (vcField*) pv;
+
+               if (t->Sub != NULL){
+                       vcField *Sub;
+                       FlushStrBuf(SubStr);
+                       itSub = GetNewHashPos(DefineToToken, 0);
+                       while (GetNextHashPos(DefineToToken, itSub, &len, &Key, &pv) && 
+                              (pv != NULL)) 
+                       {
+                               Sub = (vcField*) pv;
+                               if (Sub->parentCVal == t->cval) {
+                                       if (StrLength(SubStr) > 0)
+                                               StrBufAppendBufPlain(SubStr, HKEY(";"), 0);
+
+
+
+                                       blen = snprintf(buf, sizeof(buf), "%ld", Sub->cval);
+                                       s = SSubBstr(postVcard, buf, blen);
+                       
+                                       if ((s != NULL) && (StrLength(s) > 0)) {
+                                               /// todo: utf8 qp
+                                               StrBufAppendBuf(SubStr, s, 0);
+                                       }
+                               }
+                       }
+                       if (StrLength(SubStr) > 0) {
+                               vcard_add_prop(v, t->STR.Key, ChrPtr(SubStr));
+                       }
+                       DeleteHashPos(&itSub);
+               }
+               else if (t->parentCVal == 0) {
+                       blen = snprintf(buf, sizeof(buf), "%ld", t->cval);
+                       s = SSubBstr(postVcard, buf, blen);
+                       
+                       if ((s != NULL) && (StrLength(s) > 0)) {
+                               vcard_add_prop(v, t->STR.Key, ChrPtr(s));
+                       }
+                       /*
+                   (vvcField != NULL))
+               {
+                       vcField *t = (vcField*) vvcField;
+                       if (t->layer == 0) switch (t->Type) {
+                               break;
+                       case StringCluster:
+                       {
+                               
+                               i++;
+                               continue;
+                       }
+                       break;
+                               break;
+                       case EmailAddr:
+                               break;
+                       case Street:
+                               break;
+                       case FlatString:
+                       case PhoneNumber:
+                       case Number:
+                               break;
+                       case AliasFor:
+                               break;
+                       case Base64BinaryAttachment:
+                               break;
+                       case TerminateList:
+                               break;
+                       case Address:
+                               break;
+
+                       }
+*/
+               }
+       }
+       DeleteHashPos(&it);
+
+       s = sbstr("other_inetemail");
+       if (StrLength(s) > 0) {
+               FlushStrBuf(SubStr);
+               while (StrBufSipLine(SubStr, s, &Pos), ((Pos!=StrBufNOTNULL) && (Pos!=NULL)) ) {
+                       if (StrLength(SubStr) > 0) {
+                               vcard_add_prop(v, "email;internet", ChrPtr(SubStr));
+                       }
                }
        }
 
+       FreeStrBuf(&SubStr);
+
+
        serialized_vcard = vcard_serialize(v);
        vcard_free(v);
        if (serialized_vcard == NULL) {
@@ -1657,6 +1270,7 @@ void submit_vcard(void) {
                return;
        }
 
+       printf("%s", serialized_vcard);
        serv_write(HKEY("Content-type: text/x-vcard; charset=UTF-8\n"));
        serv_write(HKEY("\n"));
        serv_printf("%s\r\n", serialized_vcard);
@@ -1816,6 +1430,9 @@ void
 ServerShutdownModule_VCARD
 (void)
 {
+       DeleteHash(&DefineToToken);
+       DeleteHash(&vcNames);
+       DeleteHash(&VCTokenToDefine);
        /// DeleteHash(&VCToEnum);
 }
 
@@ -1824,6 +1441,7 @@ InitModule_VCARD
 (void)
 {
        RegisterCTX(CTX_VCARD);
+       RegisterCTX(CTX_VCARD_TYPE);
        RegisterReadLoopHandlerset(
                VIEW_ADDRESSBOOK,
                vcard_GetParamsGetServerCall,
@@ -1874,13 +1492,16 @@ InitModule_VCARD
        {
                StrBuf *Prefix  = NewStrBufPlain(HKEY("VC:"));
                DefineToToken   = NewHash(1, lFlathash);
+               vcNames         = NewHash(1, lFlathash);
                VCTokenToDefine = NewHash(1, NULL);
-               autoRegisterTokens(&VCEnumCounter, VCStrE, Prefix, 0);
+               autoRegisterTokens(&VCEnumCounter, VCStrE, Prefix, 0, 0);
                FreeStrBuf(&Prefix);
        }
        RegisterCTX(CTX_VCARD);
        RegisterNamespace("VC:ITEM", 2, 2, tmpl_vcard_item, preeval_vcard_item, CTX_VCARD);
+       RegisterNamespace("VC:CTXITEM", 1, 1, tmpl_vcard_context_item, NULL, CTX_VCARD_TYPE);
        RegisterNamespace("VC:NAME", 1, 1, tmpl_vcard_name_str, preeval_vcard_name_str, CTX_VCARD);
+       RegisterNamespace("VC:CTXNAME", 1, 1, tmpl_vcard_context_name_str, NULL, CTX_VCARD_TYPE);
        REGISTERTokenParamDefine(FlatString);
        REGISTERTokenParamDefine(StringCluster);
        REGISTERTokenParamDefine(PhoneNumber);
@@ -1890,8 +1511,10 @@ InitModule_VCARD
        REGISTERTokenParamDefine(AliasFor);
        REGISTERTokenParamDefine(Base64BinaryAttachment);
        REGISTERTokenParamDefine(TerminateList);
+       REGISTERTokenParamDefine(Address);
 
        RegisterConditional("VC:HAVE:TYPE",      1, conditional_VC_Havetype, CTX_VCARD);
-       RegisterFilteredIterator("VC:TYPE", 1, NULL, NULL, NULL, NULL, filter_VC_ByType, CTX_STRBUF, CTX_VCARD, IT_NOFLAG);
+       RegisterFilteredIterator("VC:TYPE", 1, DefineToToken, NULL, NULL, NULL, filter_VC_ByType, CTX_VCARD_TYPE, CTX_VCARD, IT_NOFLAG);
+       RegisterFilteredIterator("VC:TYPE:ITEMS", 0, NULL, getContextVcard, NULL, NULL, filter_VC_ByContextType, CTX_STRBUF, CTX_VCARD_TYPE, IT_NOFLAG);
 }