X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=webcit%2Fvcard_edit.c;h=81efa290fe6c8f8d3c2d7d16d0d493cca4990b70;hb=HEAD;hp=47c04c724a5863fa2610caa84e7ff94e14bb40eb;hpb=9571de81331e169c042c630800bff1bde499c8a9;p=citadel.git diff --git a/webcit/vcard_edit.c b/webcit/vcard_edit.c index 47c04c724..e08a227fe 100644 --- a/webcit/vcard_edit.c +++ b/webcit/vcard_edit.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996-2012 by the citadel.org team + * Copyright (c) 1996-2021 by the citadel.org team * * This program is open source software. You can redistribute it and/or * modify it under the terms of the GNU General Public License, version 3. @@ -11,10 +11,12 @@ */ #include "webcit.h" -#include "webserver.h" + #include "calendar.h" CtxType CTX_VCARD = CTX_NONE; +CtxType CTX_VCARD_LIST = CTX_NONE; +CtxType CTX_VCARD_TYPE = CTX_NONE; long VCEnumCounter = 0; typedef enum _VCStrEnum { @@ -22,10 +24,12 @@ typedef enum _VCStrEnum { StringCluster, PhoneNumber, EmailAddr, + Address, Street, Number, AliasFor, Base64BinaryAttachment, + UnKnown, TerminateList }VCStrEnum; typedef struct vcField vcField; @@ -34,48 +38,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 [] = { @@ -97,16 +103,42 @@ ConstStr VCStr [] = { {HKEY("uid")} }; +/* + * Address book entry (keep it short and sweet, it's just a quickie lookup + * which we can use to get to the real meat and bones later) + */ +typedef struct _addrbookent { + StrBuf *name; + HashList *VC; + long ab_msgnum; /* message number of address book entry */ + StrBuf *msgNoStr; +} addrbookent; + +void deleteAbEnt(void *v) { + addrbookent *vc = (addrbookent*)v; + DeleteHash(&vc->VC); + FreeStrBuf(&vc->name); + FreeStrBuf(&vc->msgNoStr); + free(vc); +} HashList *DefineToToken = NULL; HashList *VCTokenToDefine = NULL; HashList *vcNames = NULL; /* todo: fill with the name strings */ +vcField* vcfUnknown = NULL; +/****************************************************************************** + * initialize vcard structure * + ******************************************************************************/ 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 +147,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 +168,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,12 +185,21 @@ 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); } +/****************************************************************************** + * VCard template functions * + ******************************************************************************/ + int preeval_vcard_item(WCTemplateToken *Token) { WCTemplputParams TPP; @@ -171,8 +212,7 @@ int preeval_vcard_item(WCTemplateToken *Token) TP->Tokens = Token; searchFieldNo = GetTemplateTokenNumber(Target, TP, 0, 0); if (searchFieldNo >= VCEnumCounter) { - LogTemplateError(NULL, "VCardItem", ERR_PARM1, TP, - "Invalid define"); + LogTemplateError(NULL, "VCardItem", ERR_PARM1, TP, "Invalid define"); return 0; } return 1; @@ -182,12 +222,31 @@ void tmpl_vcard_item(StrBuf *Target, WCTemplputParams *TP) { void *vItem; long searchFieldNo = GetTemplateTokenNumber(Target, TP, 0, 0); - HashList *vc = (HashList*) CTX(CTX_VCARD); - if (GetHash(vc, LKEY(searchFieldNo), &vItem) && (vItem != NULL)) { + addrbookent *ab = (addrbookent*) CTX(CTX_VCARD); + if (GetHash(ab->VC, LKEY(searchFieldNo), &vItem) && (vItem != NULL)) { StrBufAppendTemplate(Target, TP, (StrBuf*) vItem, 1); } } +void tmpl_vcard_context_item(StrBuf *Target, WCTemplputParams *TP) +{ + void *vItem; + vcField *t = (vcField*) CTX(CTX_VCARD_TYPE); + addrbookent *ab = (addrbookent*) CTX(CTX_VCARD); + + if (t == NULL) { + LogTemplateError(NULL, "VCard item", ERR_NAME, TP, "Missing context"); + return; + } + + if (GetHash(ab->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,39 +274,102 @@ 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_msgno(StrBuf *Target, WCTemplputParams *TP) +{ + addrbookent *ab = (addrbookent*) CTX(CTX_VCARD); + if (ab->msgNoStr == NULL) { + ab->msgNoStr = NewStrBufPlain(NULL, 64); + } + StrBufPrintf(ab->msgNoStr, "%ld", ab->ab_msgnum); + StrBufAppendTemplate(Target, TP, ab->msgNoStr, 0); +} +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; + vcField *vf = (vcField*) Context; int rc = 0; - 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) { + addrbookent *ab = (addrbookent*) CTX(CTX_VCARD); + if (GetHash(ab->VC, LKEY(vf->cval), &v) && v != NULL) { + return 1; } } return rc; } +HashList *getContextVcard(StrBuf *Target, WCTemplputParams *TP) +{ + vcField *vf = (vcField*) CTX(CTX_VCARD_TYPE); + addrbookent *ab = (addrbookent*) CTX(CTX_VCARD); + + if ((vf == NULL) || (ab == NULL)) { + LogTemplateError(NULL, "VCard item type", ERR_NAME, TP, + "Need VCard and Vcard type in context"); + + return NULL; + } + return ab->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); + addrbookent *ab = (addrbookent*) CTX(CTX_VCARD); long HaveFieldType = GetTemplateTokenNumber(Target, TP, 2, 0); int rc = 0; void *vVCitem; const char *Key; long len; - HashPos *it = GetNewHashPos(vc, 0); - while (GetNextHashPos(vc, it, &len, &Key, &vVCitem) && + HashPos *it = GetNewHashPos(ab->VC, 0); + while (GetNextHashPos(ab->VC, it, &len, &Key, &vVCitem) && (vVCitem != NULL)) { void *vvcField; @@ -267,533 +389,45 @@ int conditional_VC_Havetype(StrBuf *Target, WCTemplputParams *TP) return rc; } -/* - * Record compare function for sorting address book indices - */ -int abcmp(const void *ab1, const void *ab2) { - return(strcasecmp( - (((const addrbookent *)ab1)->ab_name), - (((const addrbookent *)ab2)->ab_name) - )); -} - - -/* - * Helper function for do_addrbook_view() - * Converts a name into a three-letter tab label - */ -void nametab(char *tabbuf, long len, char *name) { - stresc(tabbuf, len, name, 0, 0); - tabbuf[0] = toupper(tabbuf[0]); - tabbuf[1] = tolower(tabbuf[1]); - tabbuf[2] = tolower(tabbuf[2]); - tabbuf[3] = 0; -} - - -/* - * If it's an old "Firstname Lastname" style record, try to convert it. - */ -void lastfirst_firstlast(char *namebuf) { - char firstname[SIZ]; - char lastname[SIZ]; - int i; - - if (namebuf == NULL) return; - if (strchr(namebuf, ';') != NULL) return; - - i = num_tokens(namebuf, ' '); - if (i < 2) return; - - extract_token(lastname, namebuf, i-1, ' ', sizeof lastname); - remove_token(namebuf, i-1, ' '); - strcpy(firstname, namebuf); - sprintf(namebuf, "%s; %s", lastname, firstname); -} - - - -wc_mime_attachment *load_vcard(message_summary *Msg) -{ - HashPos *it; - StrBuf *FoundCharset = NewStrBuf(); - StrBuf *Error; - void *vMime; - const char *Key; - long len; - wc_mime_attachment *Mime; - wc_mime_attachment *VCMime = NULL; - - Msg->MsgBody = (wc_mime_attachment*) malloc(sizeof(wc_mime_attachment)); - memset(Msg->MsgBody, 0, sizeof(wc_mime_attachment)); - Msg->MsgBody->msgnum = Msg->msgnum; - - load_message(Msg, FoundCharset, &Error); - - FreeStrBuf(&FoundCharset); - /* look up the vcard... */ - it = GetNewHashPos(Msg->AllAttach, 0); - while (GetNextHashPos(Msg->AllAttach, it, &len, &Key, &vMime) && - (vMime != NULL)) - { - Mime = (wc_mime_attachment*) vMime; - if ((strcmp(ChrPtr(Mime->ContentType), - "text/x-vcard") == 0) || - (strcmp(ChrPtr(Mime->ContentType), - "text/vcard") == 0)) - { - VCMime = Mime; - break; - } - } - DeleteHashPos(&it); - if (VCMime == NULL) - return NULL; - - if (VCMime->Data == NULL) - MimeLoadData(VCMime); - return VCMime; -} - -/* - * fetch the display name off a vCard - */ -void fetch_ab_name(message_summary *Msg, char **namebuf) { - long len; - int i; - wc_mime_attachment *VCMime = NULL; - - if (namebuf == NULL) return; - - VCMime = load_vcard(Msg); - if (VCMime == NULL) - return; - - /* Grab the name off the card */ - display_vcard(WC->WBuf, VCMime, 0, 0, namebuf, Msg->msgnum); - - if (*namebuf != NULL) { - lastfirst_firstlast(*namebuf); - striplt(*namebuf); - len = strlen(*namebuf); - for (i=0; i 0) { - if (original_name[len-1] == ' ') { - original_name[--len] = 0; - } - if (original_name[len-1] == ';') { - original_name[--len] = 0; - } - } - } - strcpy(name, ""); - j=0; - for (i=0; i"); - 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, " "); - } - StrBufAppendPrintf(Target, ""); - return; - } - - StrBufAppendPrintf(Target, "
" - ""); - 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; jprop[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, "
"); - strcat(mailto, - ""); - - strcat(mailto, "\">"); - len = strlen(mailto); - stresc(mailto+len, SIZ - len, thisvalue, 1, 1); - strcat(mailto, ""); - } - else if (!strcasecmp(firsttoken, "tel")) { - if (!IsEmptyStr(phone)) strcat(phone, "
"); - strcat(phone, thisvalue); - for (j=0; j
\n"); - } - } - /* else if (!strcasecmp(firsttoken, "photo") && full && pass == 2) { - // Only output on second pass - StrBufAppendPrintf(Target, "\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, "\n"); - } - ***/ - } - - free(thisname); - free(thisvalue); - } - - if (pass == 1) { - StrBufAppendPrintf(Target, "" - "\n"); - - if (!IsEmptyStr(phone)) { - StrBufAppendPrintf(Target, "\n", phone); - } - if (!IsEmptyStr(mailto)) { - StrBufAppendPrintf(Target, "\n", mailto); - } - } - - } - - StrBufAppendPrintf(Target, "
"); - StrBufAppendPrintf(Target, _("Address:")); - StrBufAppendPrintf(Target, ""); - for (j=0; j"); - else StrBufAppendPrintf(Target, " "); - } - } - StrBufAppendPrintf(Target, "
"); - StrBufAppendPrintf(Target, _("Photo:")); - StrBufAppendPrintf(Target, ""); - StrBufAppendPrintf(Target, "\"Contact",msgnum); - StrBufAppendPrintf(Target, "
"); - StrEscAppend(Target, NULL, thisname, 0, 0); - StrBufAppendPrintf(Target, ""); - StrEscAppend(Target, NULL, thisvalue, 0, 0); - StrBufAppendPrintf(Target, "
" - "" - ""); - StrEscAppend(Target, NULL, fullname, 0, 0); - StrBufAppendPrintf(Target, ""); - if (!IsEmptyStr(title)) { - StrBufAppendPrintf(Target, "
\""); - StrEscAppend(Target, NULL, title, 0, 0); - StrBufAppendPrintf(Target, "
"); - } - if (!IsEmptyStr(org)) { - StrBufAppendPrintf(Target, "
"); - StrEscAppend(Target, NULL, org, 0, 0); - StrBufAppendPrintf(Target, "
"); - } - StrBufAppendPrintf(Target, "
"); - StrBufAppendPrintf(Target, _("Telephone:")); - StrBufAppendPrintf(Target, "%s
"); - StrBufAppendPrintf(Target, _("E-mail:")); - StrBufAppendPrintf(Target, "%s
\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)){ - StrBuf *b; + FlushStrBuf(Swap); StrBuf_RFC822_to_Utf8(Swap, ThisFieldStr, NULL, NULL); /* default charset, current charset */ - b = ThisFieldStr; - ThisFieldStr = Swap; - Swap = b; + SwapBuffers(Swap, ThisFieldStr); FlushStrBuf(Swap); } Put(thisVC, LKEY(thisField->cval), ThisFieldStr, HFreeStrBuf); } -/* - * 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 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); @@ -801,41 +435,25 @@ void parse_vcard(StrBuf *Target, struct vCard *v, HashList *VC, int full, wc_mim FlushStrBuf(thisVCToken); is_qp = 0; is_b64 = 0; - syslog(LOG_DEBUG, "i: %d oneprop: %s - value: %s", i, v->prop[i].name, v->prop[i].value); + // syslog(LOG_DEBUG, "i: %d oneprop: %s - value: %s", i, v->prop[i].name, v->prop[i].value); StrBufPlain(thisname, v->prop[i].name, -1); StrBufLowerCase(thisname); - /*len = */extract_token(firsttoken, ChrPtr(thisname), 0, ';', sizeof firsttoken); + 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]; - len = extract_token(buf, ChrPtr(thisname), j, ';', sizeof buf); if (!strcasecmp(buf, "encoding=quoted-printable")) { is_qp = 1; -/* remove_token(thisname, j, ';');*/ } else if (!strcasecmp(buf, "encoding=base64")) { is_b64 = 1; -/* remove_token(thisname, j, ';');*/ } - else{ + else { if (StrLength(thisVCToken) > 0) { StrBufAppendBufPlain(thisVCToken, HKEY(";"), 0); } StrBufAppendBufPlain(thisVCToken, buf, len, 0); - /* - if (GetHash(VCToEnum, buf, len, &V)) - { - evc[k] = (int) V; - - Put(VC, IKEY(evc), Val, HFreeStrBuf); - - syslog(LOG_DEBUG, "[%ul] -> k: %d %s - %s", evc, k, buf, VCStr[evc[k]].Key); - k++; - } -*/ - } } @@ -845,7 +463,7 @@ void parse_vcard(StrBuf *Target, struct vCard *v, HashList *VC, int full, wc_mim (vField != NULL)) { vcField *thisField = (vcField *)vField; StrBuf *ThisFieldStr = NULL; - syslog(LOG_DEBUG, "got this token: %s, found: %s", ChrPtr(thisVCToken), thisField->STR.Key); + // syslog(LOG_DEBUG, "got this token: %s, found: %s", ChrPtr(thisVCToken), thisField->STR.Key); switch (thisField->Type) { case StringCluster: { int j = 0; @@ -855,12 +473,14 @@ void parse_vcard(StrBuf *Target, struct vCard *v, HashList *VC, int full, wc_mim while (thisField->Sub[j].STR.len > 0) { 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,308 +489,130 @@ 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: + ThisFieldStr = NewStrBufPlain(v->prop[i].value, -1); + StrBufDecodeBase64(ThisFieldStr); + PutVcardItem(VC, thisField, ThisFieldStr, is_qp, Swap); + break; case TerminateList: + case UnKnown: break; } } - /* copy over the payload into a StrBuf */ - Val = NewStrBufPlain(v->prop[i].value, -1); - - /* if we have some untagged QP, detect it here. */ - if (is_qp || (strstr(v->prop[i].value, "=?")!=NULL)){ - StrBuf *b; - StrBuf_RFC822_to_Utf8(Swap, Val, NULL, NULL); /* default charset, current charset */ - b = Val; - Val = Swap; - Swap = b; - FlushStrBuf(Swap); - } - else if (is_b64) { - StrBufDecodeBase64(Val); - - } -#if 0 - syslog(LOG_DEBUG, "-> firsttoken: %s thisname: %s Value: [%s][%s]", - firsttoken, - ChrPtr(thisname), - ChrPtr(Val), - v->prop[i].value); - if (GetHash(VCToEnum, firsttoken, strlen(firsttoken), &V)) - { - eVC evc = (eVC) V; - Put(VC, IKEY(evc), Val, HFreeStrBuf); - syslog(LOG_DEBUG, "[%ul]\n", evc); - Val = NULL; - } - else - syslog(LOG_DEBUG, "[]\n"); -/* -TODO: check for layer II - else - { - long max = num_tokens(thisname, ';'); - firsttoken[len] = '_'; - - for (j = 0; j < max; j++) { -// firsttoken[len] - - 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 (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; } -*/ -#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) -{ - HashList *VC = CTX(CTX_VCARD); - int evc; - void *vStr; - - evc = GetTemplateTokenNumber(Target, TP, 0, -1); - if (evc != -1) - { - if (GetHash(VC, IKEY(evc), &vStr)) - { - StrBufAppendTemplate(Target, TP, - (StrBuf*) vStr, - 1); - } - } - } -void new_vcard (StrBuf *Target, struct vCard *v, int full, wc_mime_attachment *Mime) +HashList *CtxGetVcardList(StrBuf *Target, WCTemplputParams *TP) { - HashList *VC; - WCTemplputParams SubTP; - - memset(&SubTP, 0, sizeof(WCTemplputParams)); - - - VC = NewHash(0, Flathash); - parse_vcard(Target, v, VC, full, Mime); - - SubTP.Filter.ContextType = CTX_VCARD; - SubTP.Context = VC; - - DoTemplate(HKEY("test_vcard"), Target, &SubTP); - DeleteHash(&VC); + HashList *pb = CTX(CTX_VCARD_LIST); + return pb; } +/****************************************************************************** + * Extract an embedded photo from a vCard for display on the client * + ******************************************************************************/ - -/* - * Display a textual vCard - * (Converts to a vCard object and then calls the actual display function) - * Set 'full' to nonzero to display the whole card instead of a one-liner. - * Or, if "storename" is non-NULL, just store the person's name in that - * buffer instead of displaying the card at all. - * - * vcard_source the buffer containing the vcard text - * alpha Display only if name begins with this letter of the alphabet - * full Display the full vCard (otherwise just the display name) - * storename If not NULL, also store the display name here - * msgnum Citadel message pointer - */ -void display_vcard(StrBuf *Target, - wc_mime_attachment *Mime, - char alpha, - int full, - char **storename, - long msgnum) +void display_vcard_photo_img(void) { + long msgnum = 0L; + StrBuf *vcard; struct vCard *v; - char *name; - StrBuf *Buf; - StrBuf *Buf2; - char this_alpha = 0; - - v = VCardLoad(Mime->Data); - - if (v == NULL) return; - - name = vcard_get_prop(v, "n", 1, 0, 0); - if (name != NULL) { - Buf = NewStrBufPlain(name, -1); - Buf2 = NewStrBufPlain(NULL, StrLength(Buf)); - StrBuf_RFC822_to_Utf8(Buf2, Buf, WC->DefaultCharset, NULL); - this_alpha = ChrPtr(Buf)[0]; - FreeStrBuf(&Buf); - FreeStrBuf(&Buf2); - } - - if (storename != NULL) { - fetchname_parsed_vcard(v, storename); - } - else if ((alpha == 0) || - ((isalpha(alpha)) && (tolower(alpha) == tolower(this_alpha))) || - ((!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 - } - - vcard_free(v); -} - - - -/* - * Render the address book using info we gathered during the scan - * - * addrbook the addressbook to render - * num_ab the number of the addressbook - */ -void do_addrbook_view(addrbookent *addrbook, int num_ab) { - int i = 0; - int displayed = 0; - int bg = 0; - static int NAMESPERPAGE = 60; - int num_pages = 0; - int tabfirst = 0; - char tabfirst_label[64]; - int tablast = 0; - char tablast_label[64]; - char this_tablabel[64]; - int page = 0; - char **tablabels; - - if (num_ab == 0) { - wc_printf("


"); - wc_printf(_("This address book is empty.")); - wc_printf("
\n"); - return; - } - - if (num_ab > 1) { - qsort(addrbook, num_ab, sizeof(addrbookent), abcmp); - } - - num_pages = (num_ab / NAMESPERPAGE) + 1; + char *photosrc; + const char *contentType; - tablabels = malloc(num_pages * sizeof (char *)); - if (tablabels == NULL) { - wc_printf("


"); - wc_printf(_("An internal error has occurred.")); - wc_printf("
\n"); + msgnum = StrBufExtract_long(WC->Hdr->HR.ReqLine, 0, '/'); + + vcard = load_mimepart(msgnum,"1"); + v = VCardLoad(vcard); + + photosrc = vcard_get_prop(v, "PHOTO", 1,0,0); + FlushStrBuf(WC->WBuf); + StrBufAppendBufPlain(WC->WBuf, photosrc, -1, 0); + if (StrBufDecodeBase64(WC->WBuf) <= 0) { + FlushStrBuf(WC->WBuf); + + hprintf("HTTP/1.1 500 %s\n","Unable to get photo"); + output_headers(0, 0, 0, 0, 0, 0); + hprintf("Content-Type: text/plain\r\n"); + begin_burst(); + wc_printf(_("Could Not decode vcard photo\n")); + end_burst(); return; } + contentType = GuessMimeType(ChrPtr(WC->WBuf), StrLength(WC->WBuf)); + http_transmit_thing(contentType, 0); + free(v); + free(photosrc); +} - for (i=0; i (num_ab - 1)) tablast = (num_ab - 1); - nametab(tabfirst_label, 64, addrbook[tabfirst].ab_name); - nametab(tablast_label, 64, addrbook[tablast].ab_name); - sprintf(this_tablabel, "%s - %s", tabfirst_label, tablast_label); - tablabels[i] = strdup(this_tablabel); - } - - tabbed_dialog(num_pages, tablabels); - page = (-1); - - for (i=0; i 0) { - wc_printf("\n"); - end_tab(page-1, num_pages); - } - begin_tab(page, num_pages); - wc_printf("\n"); - displayed = 0; - } + Msg->MsgBody = (wc_mime_attachment*) malloc(sizeof(wc_mime_attachment)); + memset(Msg->MsgBody, 0, sizeof(wc_mime_attachment)); + Msg->MsgBody->msgnum = Msg->msgnum; - if ((displayed % 4) == 0) { - if (displayed > 0) { - wc_printf("\n"); - } - bg = 1 - bg; - wc_printf("", - (bg ? "dddddd" : "ffffff") - ); - } - - wc_printf("\n"); - ++displayed; - } + load_message(Msg, FoundCharset, &Error); - /* Placeholders for empty columns at end */ - if ((num_ab % 4) != 0) { - for (i=0; i<(4-(num_ab % 4)); ++i) { - wc_printf(""); + FreeStrBuf(&FoundCharset); + /* look up the vcard... */ + it = GetNewHashPos(Msg->AllAttach, 0); + while (GetNextHashPos(Msg->AllAttach, it, &len, &Key, &vMime) && + (vMime != NULL)) + { + Mime = (wc_mime_attachment*) vMime; + if ((strcmp(ChrPtr(Mime->ContentType), + "text/x-vcard") == 0) || + (strcmp(ChrPtr(Mime->ContentType), + "text/vcard") == 0)) + { + VCMime = Mime; + break; } } + DeleteHashPos(&it); + if (VCMime == NULL) + return NULL; - wc_printf("
"); - - wc_printf("", bstr("alpha")); - vcard_n_prettyize(addrbook[i].ab_name); - escputs(addrbook[i].ab_name); - wc_printf(" 
\n"); - end_tab((num_pages-1), num_pages); - - begin_tab(num_pages, num_pages); - /* FIXME there ought to be something here */ - end_tab(num_pages, num_pages); - - for (i=0; iData == NULL) + MimeLoadData(VCMime); + return VCMime; } - - - /* * Edit the vCard component of a MIME message. * Supply the message number @@ -1182,59 +624,17 @@ void do_edit_vcard(long msgnum, char *partnum, wc_mime_attachment *VCAtt, const char *return_to, const char *force_room) { - wcsession *WCC = WC; + WCTemplputParams SubTP; message_summary *Msg = NULL; wc_mime_attachment *VCMime = NULL; struct vCard *v; - int i; - char *key, *value; char whatuser[256]; + addrbookent ab; - 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; + memset(&ab, 0, sizeof(addrbookent)); + ab.VC = NewHash(0, lFlathash); + /* Display the form */ + output_headers(1, 1, 1, 0, 0, 0); safestrncpy(whatuser, "", sizeof whatuser); @@ -1248,9 +648,10 @@ void do_edit_vcard(long msgnum, char *partnum, Msg->msgnum = msgnum; VCMime = load_vcard(Msg); if (VCMime == NULL) { - convenience_page("770000", _("Error"), "");///TODO: important message + convenience_page("770000", _("Error"), "");/*TODO: important message*/ DestroyMessageSummary(Msg); return; + DeleteHash(&ab.VC); } v = VCardLoad(VCMime->Data); @@ -1258,279 +659,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); - } - } - - 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"); - } + parse_vcard(WC->WBuf, v, ab.VC, NULL); - } 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("
\n"); - wc_printf("\n", WC->nonce); - - if (force_room != NULL) { - wc_printf("\n"); - } - else + memset(&SubTP, 0, sizeof(WCTemplputParams)); { - wc_printf("WBuf, WCC->CurRoom.name, NULL, 0, 0); - wc_printf("\">\n"); - } - - wc_printf("
\n"); + WCTemplputParams *TP = NULL; + WCTemplputParams SubTP; - wc_printf("" - "" - "" - "" - "" - "\n", - _("Prefix"), _("First Name"), _("Middle Name"), _("Last Name"), _("Suffix") - ); - wc_printf("", - prefix); - wc_printf("", - firstname); - wc_printf("", - middlename); - wc_printf("", - lastname); - wc_printf("
%s%s%s%s%s
\n", - suffix); - - wc_printf(""); - wc_printf("
"); - - wc_printf(_("Display name:")); - wc_printf("
" - "

\n", - fullname - ); + StackContext(TP, &SubTP, &ab, CTX_VCARD, 0, NULL); - wc_printf(_("Title:")); - wc_printf("
" - "

\n", - title - ); + DoTemplate(HKEY("vcard_edit"), WC->WBuf, &SubTP); + UnStackContext(&SubTP); + } + DeleteHash(&ab.VC); - wc_printf(_("Organization:")); - wc_printf("
" - "

\n", - org - ); - wc_printf("
"); - - wc_printf(""); - wc_printf("\n", - pobox); - wc_printf("\n", - extadr); - wc_printf("\n", - street); - wc_printf("\n", - city); - wc_printf("\n", - state); - wc_printf("\n", - zipcode); - wc_printf("\n", - country); - wc_printf("
"); - wc_printf(_("PO box:")); - wc_printf("" - "
"); - wc_printf(_("Address:")); - wc_printf("" - "
" - "
"); - wc_printf(_("City:")); - wc_printf("" - "
"); - wc_printf(_("State:")); - wc_printf("" - "
"); - wc_printf(_("ZIP code:")); - wc_printf("" - "
"); - wc_printf(_("Country:")); - wc_printf("" - "
\n"); - - wc_printf("
\n"); - - wc_printf("" - "\n", - hometel); - wc_printf("" - "\n", - worktel); - wc_printf("" - "\n", - mobiletel); - wc_printf("" - "
"); - wc_printf(_("Home telephone:")); - wc_printf(""); - wc_printf(_("Work telephone:")); - wc_printf("
"); - wc_printf(_("Mobile telephone:")); - wc_printf(""); - wc_printf(_("Fax number:")); - wc_printf("
\n", - faxtel); - - wc_printf(""); - wc_printf("
"); - - wc_printf("" - "
"); - wc_printf(_("Primary Internet e-mail address")); - wc_printf("
" - "
" - "
"); - wc_printf(_("Internet e-mail aliases")); - wc_printf("
" - "
\n"); - - wc_printf("
\n"); - - wc_printf("\n"); - - wc_printf("\n"); - - wc_printf("
\n" - "" - " " - "" - "
\n", - _("Save changes"), - _("Cancel") - ); - - wc_printf("
\n"); - do_template("box_end"); wDumpContent(1); if (Msg != NULL) { DestroyMessageSummary(Msg); @@ -1550,18 +698,22 @@ void edit_vcard(void) { do_edit_vcard(msgnum, partnum, NULL, NULL, "", NULL); } - - /* * parse edited vcard from the browser */ 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 +745,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 +759,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,40 +772,66 @@ 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; iSub != 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)); + } } } + 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); @@ -1657,6 +842,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); @@ -1678,49 +864,13 @@ void submit_vcard(void) { FreeStrBuf(&Buf); } - - -/* - * Extract an embedded photo from a vCard for display on the client - */ -void display_vcard_photo_img(void) -{ - long msgnum = 0L; - StrBuf *vcard; - struct vCard *v; - char *photosrc; - const char *contentType; - wcsession *WCC = WC; - - msgnum = StrBufExtract_long(WCC->Hdr->HR.ReqLine, 0, '/'); - - vcard = load_mimepart(msgnum,"1"); - v = VCardLoad(vcard); - - photosrc = vcard_get_prop(v, "PHOTO", 1,0,0); - FlushStrBuf(WCC->WBuf); - StrBufAppendBufPlain(WCC->WBuf, photosrc, -1, 0); - if (StrBufDecodeBase64(WCC->WBuf) <= 0) { - FlushStrBuf(WCC->WBuf); - - hprintf("HTTP/1.1 500 %s\n","Unable to get photo"); - output_headers(0, 0, 0, 0, 0, 0); - hprintf("Content-Type: text/plain\r\n"); - begin_burst(); - wc_printf(_("Could Not decode vcard photo\n")); - end_burst(); - return; - } - contentType = GuessMimeType(ChrPtr(WCC->WBuf), StrLength(WCC->WBuf)); - http_transmit_thing(contentType, 0); - free(v); - free(photosrc); -} +/****************************************************************************** + * Render Addressbooks * + ******************************************************************************/ typedef struct _vcardview_struct { long is_singlecard; - addrbookent *addrbook; - long num_ab; + HashList *addrbook; } vcardview_struct; @@ -1740,6 +890,7 @@ int vcard_GetParamsGetServerCall(SharedMessageStatus *Stat, VS->is_singlecard = ibstr("is_singlecard"); if (VS->is_singlecard != 1) { + VS->addrbook = NewHash(0, NULL); if (oper == do_search) { snprintf(cmd, len, "MSGS SEARCH|%s", bstr("query")); } @@ -1757,36 +908,141 @@ int vcard_LoadMsgFromServer(SharedMessageStatus *Stat, int is_new, int i) { + WCTemplputParams *TP = NULL; + WCTemplputParams SubTP; vcardview_struct *VS; - char *ab_name; + wc_mime_attachment *VCMime = NULL; + struct vCard *v; + addrbookent* abEntry; VS = (vcardview_struct*) *ViewSpecific; - ab_name = NULL; - fetch_ab_name(Msg, &ab_name); - if (ab_name == NULL) + VCMime = load_vcard(Msg); + if (VCMime == NULL) return 0; - ++VS->num_ab; - VS->addrbook = realloc(VS->addrbook, - (sizeof(addrbookent) * VS->num_ab) ); - safestrncpy(VS->addrbook[VS->num_ab-1].ab_name, ab_name, - sizeof(VS->addrbook[VS->num_ab-1].ab_name)); - VS->addrbook[VS->num_ab-1].ab_msgnum = Msg->msgnum; - free(ab_name); + + v = VCardLoad(VCMime->Data); + + if (v == NULL) return 0; + + abEntry = (addrbookent*) malloc(sizeof(addrbookent)); + memset(abEntry, 0, sizeof(addrbookent)); + abEntry->name = NewStrBuf(); + abEntry->VC = NewHash(0, lFlathash); + abEntry->ab_msgnum = Msg->msgnum; + + parse_vcard(WC->WBuf, v, abEntry->VC, VCMime); + + memset(&SubTP, 0, sizeof(WCTemplputParams)); + StackContext(TP, &SubTP, abEntry, CTX_VCARD, 0, NULL); + + // No, don't display the name, it just shits all over the screen + // DoTemplate(HKEY("vcard_list_name"), WC->WBuf, &SubTP); + + UnStackContext(&SubTP); + + if (StrLength(abEntry->name) == 0) { + StrBufPlain(abEntry->name, _("(no name)"), -1); + } + + syslog(LOG_DEBUG, "abEntry->name : %s", ChrPtr(abEntry->name)); + + vcard_free(v); + + Put(VS->addrbook, SKEY(abEntry->name), abEntry, deleteAbEnt); return 0; } +/* + * Render the address book using info we gathered during the scan + * + * addrbook the addressbook to render + * num_ab the number of the addressbook + */ +static int NAMESPERPAGE = 60; +void do_addrbook_view(vcardview_struct* VS) { + long i = 0; + int num_pages = 0; + int tabfirst = 0; + int tablast = 0; + StrBuf **tablabels; + int num_ab = GetCount(VS->addrbook); + HashList *headlines; + + WCTemplputParams *TP = NULL; + WCTemplputParams SubTP; + + memset(&SubTP, 0, sizeof(WCTemplputParams)); + + if (num_ab == 0) { + do_template("vcard_list_empty"); + return; + } + + if (num_ab > 1) { + SortByHashKey(VS->addrbook, 1); + } + + num_pages = (GetCount(VS->addrbook) / NAMESPERPAGE) + 1; + + tablabels = malloc(num_pages * sizeof (StrBuf *)); + if (tablabels == NULL) { + return; + } + + headlines = NewHash(0, lFlathash); + for (i=0; i (num_ab - 1)) tablast = (num_ab - 1); + + headline = NewStrBufPlain(NULL, StrLength(v1) + StrLength(v2) + 10); + if (GetHashAt(VS->addrbook, tabfirst, &hklen1, &c1, &v1)) { + a1 = (addrbookent*) v1; + StrBufAppendBuf(headline, a1->name, 0); + StrBuf_Utf8StrCut(headline, 3); + if (GetHashAt(VS->addrbook, tablast, &hklen2, &c2, &v2)) { + + a2 = (addrbookent*) v2; + StrBufAppendBufPlain(headline, HKEY(" - "), 0); + StrBufAppendBuf(headline, a2->name, 0); + StrBuf_Utf8StrCut(headline, 9); + } + } + tablabels[i] = headline; + Put(headlines, LKEY(i), headline, HFreeStrBuf); + } + StrTabbedDialog(WC->WBuf, num_pages, tablabels); + StackContext(TP, &SubTP, VS->addrbook, CTX_VCARD_LIST, 0, NULL); + + DoTemplate(HKEY("vcard_list"), WC->WBuf, &SubTP); + UnStackContext(&SubTP); + DeleteHash(&headlines); + free(tablabels); +} + + + int vcard_RenderView_or_Tail(SharedMessageStatus *Stat, void **ViewSpecific, long oper) { const StrBuf *Mime; vcardview_struct *VS; VS = (vcardview_struct*) *ViewSpecific; - if (VS->is_singlecard) - read_message(WC->WBuf, HKEY("view_message"), lbstr("startmsg"), NULL, &Mime); - else - do_addrbook_view(VS->addrbook, VS->num_ab); /* Render the address book */ + if (VS->is_singlecard) { + read_message(WC->WBuf, HKEY("view_message"), lbstr("startmsg"), NULL, &Mime, NULL); + } + else { + do_addrbook_view(VS); /* Render the address book */ + } return 0; } @@ -1796,34 +1052,104 @@ int vcard_Cleanup(void **ViewSpecific) VS = (vcardview_struct*) *ViewSpecific; wDumpContent(1); - if ((VS != NULL) && - (VS->addrbook != NULL)) - free(VS->addrbook); - if (VS != NULL) + if ((VS != NULL) && (VS->addrbook != NULL)) { + DeleteHash(&VS->addrbook); + } + if (VS != NULL) { free(VS); + } + return 0; } +void render_MIME_VCard(StrBuf *Target, WCTemplputParams *TP, StrBuf *FoundCharset) +{ + wc_mime_attachment *Mime = (wc_mime_attachment *) CTX(CTX_MIME_ATACH); + if (StrLength(Mime->Data) == 0) { + MimeLoadData(Mime); + } + if (StrLength(Mime->Data) > 0) { + struct vCard *v; + StrBuf *Buf; + + Buf = NewStrBuf(); + /** If it's my vCard I can edit it */ + if ( (!strcasecmp(ChrPtr(WC->CurRoom.name), USERCONFIGROOM)) + || ((StrLength(WC->CurRoom.name) > 11) && + (!strcasecmp(&(ChrPtr(WC->CurRoom.name)[11]), USERCONFIGROOM))) + || (WC->CurRoom.view == VIEW_ADDRESSBOOK) + ) { + StrBufAppendPrintf(Buf, "", + Mime->msgnum, ChrPtr(Mime->PartNum)); + StrBufAppendPrintf(Buf, "[%s]", _("edit")); + } + + /* In all cases, display the full card */ + + v = VCardLoad(Mime->Data); + + if (v != NULL) { + WCTemplputParams *TP = NULL; + WCTemplputParams SubTP; + addrbookent ab; + memset(&ab, 0, sizeof(addrbookent)); + + ab.VC = NewHash(0, lFlathash); + ab.ab_msgnum = Mime->msgnum; + + parse_vcard(Target, v, ab.VC, Mime); + + memset(&SubTP, 0, sizeof(WCTemplputParams)); + StackContext(TP, &SubTP, &ab, CTX_VCARD, 0, NULL); + + DoTemplate(HKEY("vcard_msg_display"), Target, &SubTP); + UnStackContext(&SubTP); + DeleteHash(&ab.VC); + vcard_free(v); + + } + else { + StrBufPlain(Buf, _("failed to load vcard"), -1); + } + FreeStrBuf(&Mime->Data); + Mime->Data = Buf; + } + +} + void ServerStartModule_VCARD (void) { - ///VCToEnum = NewHash(0, NULL); - } void ServerShutdownModule_VCARD (void) { - /// DeleteHash(&VCToEnum); + DeleteHash(&DefineToToken); + DeleteHash(&vcNames); + DeleteHash(&VCTokenToDefine); } void InitModule_VCARD (void) { + StrBuf *Prefix = NewStrBufPlain(HKEY("VC:")); + DefineToToken = NewHash(1, lFlathash); + vcNames = NewHash(1, lFlathash); + VCTokenToDefine = NewHash(1, NULL); + autoRegisterTokens(&VCEnumCounter, VCStrE, Prefix, 0, 0); + FreeStrBuf(&Prefix); + + REGISTERTokenParamDefine(NAMESPERPAGE); + + RegisterCTX(CTX_VCARD); + RegisterCTX(CTX_VCARD_LIST); + RegisterCTX(CTX_VCARD_TYPE); + RegisterReadLoopHandlerset( VIEW_ADDRESSBOOK, vcard_GetParamsGetServerCall, @@ -1832,55 +1158,21 @@ InitModule_VCARD NULL, vcard_LoadMsgFromServer, vcard_RenderView_or_Tail, - vcard_Cleanup); + vcard_Cleanup, + NULL); + + RegisterIterator("MAIL:VCARDS", 0, NULL, CtxGetVcardList, NULL, NULL, CTX_VCARD, CTX_VCARD_LIST, IT_NOFLAG); + + WebcitAddUrlHandler(HKEY("edit_vcard"), "", 0, edit_vcard, 0); WebcitAddUrlHandler(HKEY("submit_vcard"), "", 0, submit_vcard, 0); WebcitAddUrlHandler(HKEY("vcardphoto"), "", 0, display_vcard_photo_img, NEED_URL); -/* - Put(VCToEnum, HKEY("n"), (void*)VC_n, reference_free_handler); - Put(VCToEnum, HKEY("fn"), (void*)VC_fn, reference_free_handler); - Put(VCToEnum, HKEY("title"), (void*)VC_title, reference_free_handler); - Put(VCToEnum, HKEY("org"), (void*)VC_org, reference_free_handler); - Put(VCToEnum, HKEY("email"), (void*)VC_email, reference_free_handler); - Put(VCToEnum, HKEY("tel"), (void*)VC_tel, reference_free_handler); - Put(VCToEnum, HKEY("work"), (void*)VC_work, reference_free_handler); - Put(VCToEnum, HKEY("home"), (void*)VC_home, reference_free_handler); - Put(VCToEnum, HKEY("cell"), (void*)VC_cell, reference_free_handler); - Put(VCToEnum, HKEY("adr"), (void*)VC_adr, reference_free_handler); - Put(VCToEnum, HKEY("photo"), (void*)VC_photo, reference_free_handler); - Put(VCToEnum, HKEY("version"), (void*)VC_version, reference_free_handler); - Put(VCToEnum, HKEY("rev"), (void*)VC_rev, reference_free_handler); - Put(VCToEnum, HKEY("label"), (void*)VC_label, reference_free_handler); -*/ -/* - RegisterNamespace("VC", 1, 2, tmplput_VCARD_ITEM, NULL, CTX_VCARD); - - REGISTERTokenParamDefine(VC_n); - REGISTERTokenParamDefine(VC_fn); - REGISTERTokenParamDefine(VC_title); - REGISTERTokenParamDefine(VC_org); - REGISTERTokenParamDefine(VC_email); - REGISTERTokenParamDefine(VC_tel); - REGISTERTokenParamDefine(VC_work); - REGISTERTokenParamDefine(VC_home); - REGISTERTokenParamDefine(VC_cell); - REGISTERTokenParamDefine(VC_adr); - REGISTERTokenParamDefine(VC_photo); - REGISTERTokenParamDefine(VC_version); - REGISTERTokenParamDefine(VC_rev); - REGISTERTokenParamDefine(VC_label); -*/ - { - StrBuf *Prefix = NewStrBufPlain(HKEY("VC:")); - DefineToToken = NewHash(1, lFlathash); - VCTokenToDefine = NewHash(1, NULL); - autoRegisterTokens(&VCEnumCounter, VCStrE, Prefix, 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:MSGNO", 0, 1, tmpl_vcard_msgno, NULL, CTX_VCARD); + RegisterNamespace("VC:CTXNAME", 1, 1, tmpl_vcard_context_name_str, NULL, CTX_VCARD_TYPE); REGISTERTokenParamDefine(FlatString); REGISTERTokenParamDefine(StringCluster); REGISTERTokenParamDefine(PhoneNumber); @@ -1890,8 +1182,14 @@ 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); -} + RegisterConditional("VC:HAVE:TYPE", 1, conditional_VC_Havetype, CTX_VCARD); + RegisterConditional("COND:VC:SUPPRESS_EMAIL_FIELDS", 1, conditional_VC_SuppressEmailFields, CTX_VCARD); + 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); + + RegisterMimeRenderer(HKEY("text/x-vcard"), render_MIME_VCard, 1, 201); + RegisterMimeRenderer(HKEY("text/vcard"), render_MIME_VCard, 1, 200); +}