X-Git-Url: https://code.citadel.org/?p=citadel.git;a=blobdiff_plain;f=webcit%2Fvcard_edit.c;h=27ba6495b61327e0f61cd5465533d9cf30bef4e2;hp=4b3940fb247bbf7d8a470ae8fdd1e273cc042b08;hb=b98d9f087b3a24a9549470ab066c2aea187ecfba;hpb=90b4c2ce98cdd0990718f84a25fd907310b34b69 diff --git a/webcit/vcard_edit.c b/webcit/vcard_edit.c index 4b3940fb2..27ba6495b 100644 --- a/webcit/vcard_edit.c +++ b/webcit/vcard_edit.c @@ -1,9 +1,362 @@ /* - * $Id$ + * Copyright (c) 1996-2012 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #include "webcit.h" +#include "webserver.h" +#include "calendar.h" + +CtxType CTX_VCARD = CTX_NONE; +CtxType CTX_VCARD_TYPE = CTX_NONE; +long VCEnumCounter = 0; + +typedef enum _VCStrEnum { + FlatString, + StringCluster, + PhoneNumber, + EmailAddr, + Address, + Street, + Number, + AliasFor, + Base64BinaryAttachment, + UnKnown, + TerminateList +}VCStrEnum; +typedef struct vcField vcField; +struct vcField { + ConstStr STR; + VCStrEnum Type; + vcField *Sub; + long cval; + long parentCVal; + ConstStr Name; +}; + +vcField VCStr_Ns [] = { + {{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")}, 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, 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 [] = { + {HKEY("")}, + {HKEY("n")}, /* N is name, but only if there's no FN already there */ + {HKEY("fn")}, /* FN (full name) is a true 'display name' field */ + {HKEY("title")}, /* title */ + {HKEY("org")}, /* organization */ + {HKEY("email")}, + {HKEY("tel")}, + {HKEY("work")}, + {HKEY("home")}, + {HKEY("cell")}, + {HKEY("adr")}, + {HKEY("photo")}, + {HKEY("version")}, + {HKEY("rev")}, + {HKEY("label")}, + {HKEY("uid")} +}; + + +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), + vf->cval, + inTokenCount); +} + +void autoRegisterTokens(long *enumCounter, vcField* vf, StrBuf *BaseStr, int layer, long parentCVal) +{ + int i = 0; + StrBuf *subStr = NewStrBuf(); + while (vf[i].STR.len > 0) { + FlushStrBuf(subStr); + vf[i].cval = (*enumCounter) ++; + vf[i].parentCVal = parentCVal; + StrBufAppendBuf(subStr, BaseStr, 0); + if (StrLength(subStr) > 0) { + StrBufAppendBufPlain(subStr, HKEY("."), 0); + } + StrBufAppendBufPlain(subStr, CKEY(vf[i].STR), 0); + if (layer == 0) { + Put(VCTokenToDefine, CKEY(vf[i].STR), &vf[i], reference_free_handler); + } + switch (vf[i].Type) { + case FlatString: + break; + case StringCluster: + { + autoRegisterTokens(enumCounter, vf[i].Sub, subStr, 1, vf[i].cval); + } + break; + case PhoneNumber: + break; + case EmailAddr: + break; + case Street: + break; + case Number: + break; + case AliasFor: + break; + case Base64BinaryAttachment: + break; + case TerminateList: + break; + case Address: + break; + case UnKnown: + break; + } + RegisterVCardToken(&vf[i], subStr, i); + i++; + } + FreeStrBuf(&subStr); +} + +int preeval_vcard_item(WCTemplateToken *Token) +{ + WCTemplputParams TPP; + WCTemplputParams *TP; + int searchFieldNo; + StrBuf *Target = NULL; + + memset(&TPP, 0, sizeof(WCTemplputParams)); + TP = &TPP; + TP->Tokens = Token; + searchFieldNo = GetTemplateTokenNumber(Target, TP, 0, 0); + if (searchFieldNo >= VCEnumCounter) { + LogTemplateError(NULL, "VCardItem", ERR_PARM1, TP, + "Invalid define"); + return 0; + } + return 1; +} + +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)) { + StrBufAppendTemplate(Target, TP, (StrBuf*) vItem, 1); + } +} + +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; + WCTemplputParams *TP; + int searchFieldNo; + StrBuf *Target = NULL; + + memset(&TPP, 0, sizeof(WCTemplputParams)); + TP = &TPP; + TP->Tokens = Token; + searchFieldNo = GetTemplateTokenNumber(Target, TP, 0, 0); + if (searchFieldNo >= VCEnumCounter) { + LogTemplateError(NULL, "VCardName", ERR_PARM1, TP, + "Invalid define"); + return 0; + } + return 1; +} + +void tmpl_vcard_name_str(StrBuf *Target, WCTemplputParams *TP) +{ + void *vItem; + long searchFieldNo = GetTemplateTokenNumber(Target, TP, 0, 0); + /* todo: get descriptive string for this vcard type */ + 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 *v; + int rc = 0; + vcField *vf = (vcField*) Context; + + memcpy(&type, key, sizeof(long)); + searchType = GetTemplateTokenNumber(Target, TP, IT_ADDT_PARAM(0), 0); + + 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); + 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) && + (vVCitem != NULL)) + { + void *vvcField; + long type = 0; + memcpy(&type, Key, sizeof(long)); + if (GetHash(DefineToToken, LKEY(type), &vvcField) && + (vvcField != NULL)) + { + vcField *t = (vcField*) vvcField; + if (t && t->Type == HaveFieldType) { + rc = 1; + break; + } + } + } + DeleteHashPos(&it); + return rc; +} /* * Record compare function for sorting address book indices @@ -29,47 +382,6 @@ void nametab(char *tabbuf, long len, char *name) { } -/* - * display the adressbook overview - */ -void display_addressbook(long msgnum, char alpha) { - //char buf[SIZ]; - /* char mime_partnum[SIZ]; */ - ///char mime_disposition[SIZ]; - //int mime_length; - char vcard_partnum[SIZ]; - StrBuf *vcard_source = NULL; - message_summary summ;////TODO: this will leak - - memset(&summ, 0, sizeof(summ)); - // safestrncpy(summ.subj, _("(no subject)"), sizeof summ.subj); - // Load Message headers - if (!IsEmptyStr(vcard_partnum)) { - vcard_source = load_mimepart(msgnum, vcard_partnum); - if (vcard_source != NULL) { - - /* Display the summary line */ - display_vcard(WC->WBuf, vcard_source, alpha, 0, NULL, msgnum); - - /* If it's my vCard I can edit it */ - if ( (!strcasecmp(ChrPtr(WC->wc_roomname), USERCONFIGROOM)) - || (!strcasecmp(&(ChrPtr(WC->wc_roomname)[11]), USERCONFIGROOM)) - || (WC->wc_view == VIEW_ADDRESSBOOK) - ) { - wprintf("", - msgnum, vcard_partnum); - wprintf("[%s]", _("edit")); - } - - FreeStrBuf(&vcard_source); - } - } - -} - - - /* * If it's an old "Firstname Lastname" style record, try to convert it. */ @@ -129,7 +441,8 @@ wc_mime_attachment *load_vcard(message_summary *Msg) if (VCMime == NULL) return NULL; - MimeLoadData(VCMime); + if (VCMime->Data == NULL) + MimeLoadData(VCMime); return VCMime; } @@ -148,7 +461,7 @@ void fetch_ab_name(message_summary *Msg, char **namebuf) { return; /* Grab the name off the card */ - display_vcard(WC->WBuf, VCMime->Data, 0, 0, namebuf, Msg->msgnum); + display_vcard(WC->WBuf, VCMime, 0, 0, namebuf, Msg->msgnum); if (*namebuf != NULL) { lastfirst_firstlast(*namebuf); @@ -238,7 +551,7 @@ void fetchname_parsed_vcard(struct vCard *v, char **storename) { } } if (is_qp) { - // %ff can become 6 bytes in utf8 + /* %ff can become 6 bytes in utf8 */ *storename = malloc(len * 2 + 3); j = CtdlDecodeQuotedPrintable( *storename, name, @@ -246,14 +559,19 @@ void fetchname_parsed_vcard(struct vCard *v, char **storename) { (*storename)[j] = 0; } else if (is_b64) { - // ff will become one byte.. + /* ff will become one byte.. */ *storename = malloc(len + 50); CtdlDecodeBase64( *storename, name, len); } else { - *storename = strdup(name); + size_t len; + + len = strlen (name); + + *storename = malloc(len + 3); /* \0 + eventualy missing ', '*/ + memcpy(*storename, name, len + 1); } /* vcard_n_prettyize(storename); */ } @@ -262,6 +580,20 @@ void fetchname_parsed_vcard(struct vCard *v, char **storename) { + +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; + StrBuf_RFC822_to_Utf8(Swap, ThisFieldStr, NULL, NULL); /* default charset, current charset */ + b = ThisFieldStr; + ThisFieldStr = Swap; + Swap = b; + FlushStrBuf(Swap); + } + Put(thisVC, LKEY(thisField->cval), ThisFieldStr, HFreeStrBuf); +} /* * html print a vcard * display_vcard() calls this after parsing the textual vCard into @@ -275,148 +607,172 @@ void fetchname_parsed_vcard(struct vCard *v, char **storename) { * 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 display_parsed_vcard(StrBuf *Target, struct vCard *v, int full, long msgnum) { - int i, j; +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[SIZ]; - char *name; int is_qp = 0; int is_b64 = 0; - char *thisname, *thisvalue; + int ntokens, len; + StrBuf *thisname = NULL; 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, "
"); - StrBufAppendPrintf(Target, _("Address:")); - StrBufAppendPrintf(Target, " | ");
- for (j=0; j |
"); - StrBufAppendPrintf(Target, _("Photo:")); - StrBufAppendPrintf(Target, " | "); - StrBufAppendPrintf(Target, "",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 |
"); + wc_printf(" | "); - wprintf("", bstr("alpha")); + wc_printf("?maxmsgs=1?is_summary=0?alpha=%s\">", bstr("alpha")); vcard_n_prettyize(addrbook[i].ab_name); escputs(addrbook[i].ab_name); - wprintf(" | \n"); + wc_printf("\n"); ++displayed; } /* Placeholders for empty columns at end */ if ((num_ab % 4) != 0) { for (i=0; i<(4-(num_ab % 4)); ++i) { - wprintf(""); + wc_printf(" | "); } } - wprintf(" |