2 * Copyright (c) 1996-2012 by the citadel.org team
4 * This program is open source software. You can redistribute it and/or
5 * modify it under the terms of the GNU General Public License, version 3.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
14 #include "webserver.h"
17 CtxType CTX_VCARD = CTX_NONE;
18 CtxType CTX_VCARD_TYPE = CTX_NONE;
19 long VCEnumCounter = 0;
21 typedef enum _VCStrEnum {
29 Base64BinaryAttachment,
32 typedef struct vcField vcField;
41 vcField VCStr_Ns [] = {
42 {{HKEY("last")}, FlatString, NULL, 0, {HKEY("Last Name")}},
43 {{HKEY("first")}, FlatString, NULL, 0, {HKEY("First Name")}},
44 {{HKEY("middle")}, FlatString, NULL, 0, {HKEY("Middle Name")}},
45 {{HKEY("prefix")}, FlatString, NULL, 0, {HKEY("Prefix")}},
46 {{HKEY("suffix")}, FlatString, NULL, 0, {HKEY("Suffix")}},
47 {{HKEY("")}, TerminateList, NULL, 0, {HKEY("")}}
50 vcField VCStr_Addrs [] = {
51 {{HKEY("POBox")}, FlatString, NULL, 0, {HKEY("PO box")}},
52 {{HKEY("address")}, FlatString, NULL, 0, {HKEY("Address")}},
53 {{HKEY("address2")}, FlatString, NULL, 0, {HKEY("")}},
54 {{HKEY("city")}, FlatString, NULL, 0, {HKEY("City")}},
55 {{HKEY("state")}, FlatString, NULL, 0, {HKEY("State")}},
56 {{HKEY("zip")}, FlatString, NULL, 0, {HKEY("ZIP code")}},
57 {{HKEY("country")}, FlatString, NULL, 0, {HKEY("Country")}},
58 {{HKEY("")}, TerminateList, NULL, 0, {HKEY("")}}
62 {{HKEY("version")}, Number, NULL, 0, {HKEY("")}},
63 {{HKEY("rev")}, Number, NULL, 0, {HKEY("")}},
64 {{HKEY("label")}, FlatString, NULL, 0, {HKEY("")}},
65 {{HKEY("uid")}, FlatString, NULL, 0, {HKEY("")}},
66 {{HKEY("n")}, StringCluster, VCStr_Ns, 0, {HKEY("")}}, /* N is name, but only if there's no FN already there */
67 {{HKEY("fn")}, FlatString, NULL, 0, {HKEY("")}}, /* FN (full name) is a true 'display name' field */
68 {{HKEY("title")}, FlatString, NULL, 0, {HKEY("Title:")}},
69 {{HKEY("org")}, FlatString, NULL, 0, {HKEY("Organization:")}},/* organization */
70 {{HKEY("email")}, EmailAddr, NULL, 0, {HKEY("E-mail:")}},
71 {{HKEY("tel")}, PhoneNumber, NULL, 0, {HKEY("Telephone:")}},
72 {{HKEY("adr")}, StringCluster, VCStr_Addrs, 0, {HKEY("Address:")}},
73 {{HKEY("photo")}, Base64BinaryAttachment, NULL, 0, {HKEY("Photo:")}},
74 {{HKEY("tel;home")}, PhoneNumber, NULL, 0, {HKEY(" (home)")}},
75 {{HKEY("tel;work")}, PhoneNumber, NULL, 0, {HKEY(" (work)")}},
76 {{HKEY("tel;fax")}, PhoneNumber, NULL, 0, {HKEY(" (fax)")}},
77 {{HKEY("tel;cell")}, PhoneNumber, NULL, 0, {HKEY(" (cell)")}},
78 {{HKEY("email;internet")}, EmailAddr, NULL, 0, {HKEY("E-mail:")}},
79 {{HKEY("")}, TerminateList, NULL, 0, {HKEY("")}}
84 {HKEY("n")}, /* N is name, but only if there's no FN already there */
85 {HKEY("fn")}, /* FN (full name) is a true 'display name' field */
86 {HKEY("title")}, /* title */
87 {HKEY("org")}, /* organization */
102 HashList *DefineToToken = NULL;
103 HashList *VCTokenToDefine = NULL;
104 HashList *vcNames = NULL; /* todo: fill with the name strings */
107 void RegisterVCardToken(vcField* vf, StrBuf *name, int inTokenCount)
109 RegisterTokenParamDefine(SKEY(name), vf->cval);
110 Put(DefineToToken, LKEY(vf->cval), vf, reference_free_handler);
111 Put(vcNames, LKEY(vf->cval), NewStrBufPlain(CKEY(vf->Name)), HFreeStrBuf);
113 syslog(LOG_DEBUG, "Token: %s -> %ld, %d",
120 void autoRegisterTokens(long *enumCounter, vcField* vf, StrBuf *BaseStr, int layer)
123 while (vf[i].STR.len > 0) {
124 StrBuf *subStr = NewStrBuf();
125 vf[i].cval = (*enumCounter) ++;
126 StrBufAppendBuf(subStr, BaseStr, 0);
127 if (StrLength(subStr) > 0) {
128 StrBufAppendBufPlain(subStr, HKEY("."), 0);
130 StrBufAppendBufPlain(subStr, CKEY(vf[i].STR), 0);
132 Put(VCTokenToDefine, CKEY(vf[i].STR), &vf[i], reference_free_handler);
134 switch (vf[i].Type) {
139 autoRegisterTokens(enumCounter, vf[i].Sub, subStr, 1);
154 case Base64BinaryAttachment:
159 RegisterVCardToken(&vf[i], subStr, i);
164 int preeval_vcard_item(WCTemplateToken *Token)
166 WCTemplputParams TPP;
167 WCTemplputParams *TP;
169 StrBuf *Target = NULL;
171 memset(&TPP, 0, sizeof(WCTemplputParams));
174 searchFieldNo = GetTemplateTokenNumber(Target, TP, 0, 0);
175 if (searchFieldNo >= VCEnumCounter) {
176 LogTemplateError(NULL, "VCardItem", ERR_PARM1, TP,
183 void tmpl_vcard_item(StrBuf *Target, WCTemplputParams *TP)
186 long searchFieldNo = GetTemplateTokenNumber(Target, TP, 0, 0);
187 HashList *vc = (HashList*) CTX(CTX_VCARD);
188 if (GetHash(vc, LKEY(searchFieldNo), &vItem) && (vItem != NULL)) {
189 StrBufAppendTemplate(Target, TP, (StrBuf*) vItem, 1);
193 void tmpl_vcard_context_item(StrBuf *Target, WCTemplputParams *TP)
196 vcField *t = (vcField*) CTX(CTX_VCARD_TYPE);
197 HashList *vc = (HashList*) CTX(CTX_VCARD);
200 LogTemplateError(NULL, "VCard item", ERR_NAME, TP,
205 if (GetHash(vc, LKEY(t->cval), &vItem) && (vItem != NULL)) {
206 StrBufAppendTemplate(Target, TP, (StrBuf*) vItem, 0);
209 LogTemplateError(NULL, "VCard item", ERR_NAME, TP,
210 "Doesn't have that key - did you miss to filter in advance?");
213 int preeval_vcard_name_str(WCTemplateToken *Token)
215 WCTemplputParams TPP;
216 WCTemplputParams *TP;
218 StrBuf *Target = NULL;
220 memset(&TPP, 0, sizeof(WCTemplputParams));
223 searchFieldNo = GetTemplateTokenNumber(Target, TP, 0, 0);
224 if (searchFieldNo >= VCEnumCounter) {
225 LogTemplateError(NULL, "VCardName", ERR_PARM1, TP,
232 void tmpl_vcard_name_str(StrBuf *Target, WCTemplputParams *TP)
235 long searchFieldNo = GetTemplateTokenNumber(Target, TP, 0, 0);
236 /* todo: get descriptive string for this vcard type */
237 if (GetHash(vcNames, LKEY(searchFieldNo), &vItem) && (vItem != NULL)) {
238 StrBufAppendTemplate(Target, TP, (StrBuf*) vItem, 1);
241 LogTemplateError(NULL, "VCard item type", ERR_NAME, TP,
242 "No i18n string for this.");
247 void tmpl_vcard_context_name_str(StrBuf *Target, WCTemplputParams *TP)
250 vcField *t = (vcField*) CTX(CTX_VCARD_TYPE);
253 LogTemplateError(NULL, "VCard item type", ERR_NAME, TP,
258 if (GetHash(vcNames, LKEY(t->cval), &vItem) && (vItem != NULL)) {
259 StrBufAppendTemplate(Target, TP, (StrBuf*) vItem, 1);
262 LogTemplateError(NULL, "VCard item type", ERR_NAME, TP,
263 "No i18n string for this.");
268 int filter_VC_ByType(const char* key, long len, void *Context, StrBuf *Target, WCTemplputParams *TP)
274 vcField *vf = (vcField*) Context;
276 memcpy(&type, key, sizeof(long));
277 searchType = GetTemplateTokenNumber(Target, TP, IT_ADDT_PARAM(0), 0);
279 if (vf->Type == searchType) {
280 HashList *vc = (HashList*) CTX(CTX_VCARD);
281 if (GetHash(vc, LKEY(vf->cval), &v) && v != NULL)
290 HashList *getContextVcard(StrBuf *Target, WCTemplputParams *TP)
292 vcField *vf = (vcField*) CTX(CTX_VCARD_TYPE);
293 HashList *vc = (HashList*) CTX(CTX_VCARD);
295 if ((vf == NULL) || (vc == NULL)) {
296 LogTemplateError(NULL, "VCard item type", ERR_NAME, TP,
297 "Need VCard and Vcard type in context");
304 int filter_VC_ByContextType(const char* key, long len, void *Context, StrBuf *Target, WCTemplputParams *TP)
307 vcField *vf = (vcField*) CTX(CTX_VCARD_TYPE);
309 memcpy(&searchType, key, sizeof(long));
311 if (vf->cval == searchType) {
320 int conditional_VC_Havetype(StrBuf *Target, WCTemplputParams *TP)
322 HashList *vc = (HashList*) CTX(CTX_VCARD);
323 long HaveFieldType = GetTemplateTokenNumber(Target, TP, 2, 0);
328 HashPos *it = GetNewHashPos(vc, 0);
329 while (GetNextHashPos(vc, it, &len, &Key, &vVCitem) &&
334 memcpy(&type, Key, sizeof(long));
335 if (GetHash(DefineToToken, LKEY(type), &vvcField) &&
338 vcField *t = (vcField*) vvcField;
339 if (t && t->Type == HaveFieldType) {
350 * Record compare function for sorting address book indices
352 int abcmp(const void *ab1, const void *ab2) {
354 (((const addrbookent *)ab1)->ab_name),
355 (((const addrbookent *)ab2)->ab_name)
361 * Helper function for do_addrbook_view()
362 * Converts a name into a three-letter tab label
364 void nametab(char *tabbuf, long len, char *name) {
365 stresc(tabbuf, len, name, 0, 0);
366 tabbuf[0] = toupper(tabbuf[0]);
367 tabbuf[1] = tolower(tabbuf[1]);
368 tabbuf[2] = tolower(tabbuf[2]);
374 * If it's an old "Firstname Lastname" style record, try to convert it.
376 void lastfirst_firstlast(char *namebuf) {
381 if (namebuf == NULL) return;
382 if (strchr(namebuf, ';') != NULL) return;
384 i = num_tokens(namebuf, ' ');
387 extract_token(lastname, namebuf, i-1, ' ', sizeof lastname);
388 remove_token(namebuf, i-1, ' ');
389 strcpy(firstname, namebuf);
390 sprintf(namebuf, "%s; %s", lastname, firstname);
395 wc_mime_attachment *load_vcard(message_summary *Msg)
398 StrBuf *FoundCharset = NewStrBuf();
403 wc_mime_attachment *Mime;
404 wc_mime_attachment *VCMime = NULL;
406 Msg->MsgBody = (wc_mime_attachment*) malloc(sizeof(wc_mime_attachment));
407 memset(Msg->MsgBody, 0, sizeof(wc_mime_attachment));
408 Msg->MsgBody->msgnum = Msg->msgnum;
410 load_message(Msg, FoundCharset, &Error);
412 FreeStrBuf(&FoundCharset);
413 /* look up the vcard... */
414 it = GetNewHashPos(Msg->AllAttach, 0);
415 while (GetNextHashPos(Msg->AllAttach, it, &len, &Key, &vMime) &&
418 Mime = (wc_mime_attachment*) vMime;
419 if ((strcmp(ChrPtr(Mime->ContentType),
420 "text/x-vcard") == 0) ||
421 (strcmp(ChrPtr(Mime->ContentType),
432 if (VCMime->Data == NULL)
433 MimeLoadData(VCMime);
438 * fetch the display name off a vCard
440 void fetch_ab_name(message_summary *Msg, char **namebuf) {
443 wc_mime_attachment *VCMime = NULL;
445 if (namebuf == NULL) return;
447 VCMime = load_vcard(Msg);
451 /* Grab the name off the card */
452 display_vcard(WC->WBuf, VCMime, 0, 0, namebuf, Msg->msgnum);
454 if (*namebuf != NULL) {
455 lastfirst_firstlast(*namebuf);
457 len = strlen(*namebuf);
458 for (i=0; i<len; ++i) {
459 if ((*namebuf)[i] != ';') return;
462 (*namebuf) = strdup(_("(no name)"));
465 (*namebuf) = strdup(_("(no name)"));
472 * Turn a vCard "n" (name) field into something displayable.
474 void vcard_n_prettyize(char *name)
479 original_name = strdup(name);
480 len = strlen(original_name);
481 for (i=0; i<5; ++i) {
483 if (original_name[len-1] == ' ') {
484 original_name[--len] = 0;
486 if (original_name[len-1] == ';') {
487 original_name[--len] = 0;
493 for (i=0; i<len; ++i) {
494 if (original_name[i] == ';') {
499 name[j++] = original_name[i];
510 * preparse a vcard name
511 * display_vcard() calls this after parsing the textual vCard into
512 * our 'struct vCard' data object.
513 * This gets called instead of display_parsed_vcard() if we are only looking
514 * to extract the person's name instead of displaying the card.
516 void fetchname_parsed_vcard(struct vCard *v, char **storename) {
526 name = vcard_get_prop(v, "n", 1, 0, 0);
529 prop = vcard_get_prop(v, "n", 1, 0, 1);
530 n = num_tokens(prop, ';');
532 for (j=0; j<n; ++j) {
533 extract_token(buf, prop, j, ';', sizeof buf);
534 if (!strcasecmp(buf, "encoding=quoted-printable")) {
537 if (!strcasecmp(buf, "encoding=base64")) {
542 /* %ff can become 6 bytes in utf8 */
543 *storename = malloc(len * 2 + 3);
544 j = CtdlDecodeQuotedPrintable(
550 /* ff will become one byte.. */
551 *storename = malloc(len + 50);
561 *storename = malloc(len + 3); /* \0 + eventualy missing ', '*/
562 memcpy(*storename, name, len + 1);
564 /* vcard_n_prettyize(storename); */
573 * display_vcard() calls this after parsing the textual vCard into
574 * our 'struct vCard' data object.
576 * Set 'full' to nonzero to display the full card, otherwise it will only
577 * show a summary line.
579 * This code is a bit ugly, so perhaps an explanation is due: we do this
580 * in two passes through the vCard fields. On the first pass, we process
581 * fields we understand, and then render them in a pretty fashion at the
582 * end. Then we make a second pass, outputting all the fields we don't
583 * understand in a simple two-column name/value format.
584 * v the vCard to display
585 * full display all items of the vcard?
586 * msgnum Citadel message pointer
588 void display_parsed_vcard(StrBuf *Target, struct vCard *v, int full, wc_mime_attachment *Mime)
595 char *thisname, *thisvalue;
596 char firsttoken[SIZ];
605 strcpy(fullname, "");
612 StrBufAppendPrintf(Target, "<td>");
613 name = vcard_get_prop(v, "fn", 1, 0, 0);
615 StrEscAppend(Target, NULL, name, 0, 0);
617 else if (name = vcard_get_prop(v, "n", 1, 0, 0), name != NULL) {
618 strcpy(fullname, name);
619 vcard_n_prettyize(fullname);
620 StrEscAppend(Target, NULL, fullname, 0, 0);
623 StrBufAppendPrintf(Target, " ");
625 StrBufAppendPrintf(Target, "</td>");
629 StrBufAppendPrintf(Target, "<div align=\"center\">"
630 "<table bgcolor=\"#aaaaaa\" width=\"50%%\">");
631 for (pass=1; pass<=2; ++pass) {
633 if (v->numprops) for (i=0; i<(v->numprops); ++i) {
635 thisname = strdup(v->prop[i].name);
636 extract_token(firsttoken, thisname, 0, ';', sizeof firsttoken);
638 for (j=0; j<num_tokens(thisname, ';'); ++j) {
639 extract_token(buf, thisname, j, ';', sizeof buf);
640 if (!strcasecmp(buf, "encoding=quoted-printable")) {
642 remove_token(thisname, j, ';');
644 if (!strcasecmp(buf, "encoding=base64")) {
646 remove_token(thisname, j, ';');
650 len = strlen(v->prop[i].value);
651 /* if we have some untagged QP, detect it here. */
652 if (!is_qp && (strstr(v->prop[i].value, "=?")!=NULL))
653 utf8ify_rfc822_string(&v->prop[i].value);
656 /* %ff can become 6 bytes in utf8 */
657 thisvalue = malloc(len * 2 + 3);
658 j = CtdlDecodeQuotedPrintable(
659 thisvalue, v->prop[i].value,
664 /* ff will become one byte.. */
665 thisvalue = malloc(len + 50);
667 thisvalue, v->prop[i].value,
668 strlen(v->prop[i].value) );
671 thisvalue = strdup(v->prop[i].value);
674 /* Various fields we may encounter ***/
676 /* N is name, but only if there's no FN already there */
677 if (!strcasecmp(firsttoken, "n")) {
678 if (IsEmptyStr(fullname)) {
679 strcpy(fullname, thisvalue);
680 vcard_n_prettyize(fullname);
684 /* FN (full name) is a true 'display name' field */
685 else if (!strcasecmp(firsttoken, "fn")) {
686 strcpy(fullname, thisvalue);
690 else if (!strcasecmp(firsttoken, "title")) {
691 strcpy(title, thisvalue);
695 else if (!strcasecmp(firsttoken, "org")) {
696 strcpy(org, thisvalue);
699 else if (!strcasecmp(firsttoken, "email")) {
701 if (!IsEmptyStr(mailto)) strcat(mailto, "<br>");
703 "<a href=\"display_enter"
704 "?force_room=_MAIL_?recp=");
706 len = strlen(mailto);
707 urlesc(&mailto[len], SIZ - len, "\"");
708 len = strlen(mailto);
709 urlesc(&mailto[len], SIZ - len, fullname);
710 len = strlen(mailto);
711 urlesc(&mailto[len], SIZ - len, "\" <");
712 len = strlen(mailto);
713 urlesc(&mailto[len], SIZ - len, thisvalue);
714 len = strlen(mailto);
715 urlesc(&mailto[len], SIZ - len, ">");
717 strcat(mailto, "\">");
718 len = strlen(mailto);
719 stresc(mailto+len, SIZ - len, thisvalue, 1, 1);
720 strcat(mailto, "</A>");
722 else if (!strcasecmp(firsttoken, "tel")) {
723 if (!IsEmptyStr(phone)) strcat(phone, "<br>");
724 strcat(phone, thisvalue);
725 for (j=0; j<num_tokens(thisname, ';'); ++j) {
726 extract_token(buf, thisname, j, ';', sizeof buf);
727 if (!strcasecmp(buf, "tel"))
729 else if (!strcasecmp(buf, "work"))
730 strcat(phone, _(" (work)"));
731 else if (!strcasecmp(buf, "home"))
732 strcat(phone, _(" (home)"));
733 else if (!strcasecmp(buf, "cell"))
734 strcat(phone, _(" (cell)"));
742 else if (!strcasecmp(firsttoken, "adr")) {
744 StrBufAppendPrintf(Target, "<tr><td>");
745 StrBufAppendPrintf(Target, _("Address:"));
746 StrBufAppendPrintf(Target, "</td><td>");
747 for (j=0; j<num_tokens(thisvalue, ';'); ++j) {
748 extract_token(buf, thisvalue, j, ';', sizeof buf);
749 if (!IsEmptyStr(buf)) {
750 StrEscAppend(Target, NULL, buf, 0, 0);
751 if (j<3) StrBufAppendPrintf(Target, "<br>");
752 else StrBufAppendPrintf(Target, " ");
755 StrBufAppendPrintf(Target, "</td></tr>\n");
758 /* else if (!strcasecmp(firsttoken, "photo") && full && pass == 2) {
759 // Only output on second pass
760 StrBufAppendPrintf(Target, "<tr><td>");
761 StrBufAppendPrintf(Target, _("Photo:"));
762 StrBufAppendPrintf(Target, "</td><td>");
763 StrBufAppendPrintf(Target, "<img src=\"/vcardphoto/%ld/\" alt=\"Contact photo\"/>",msgnum);
764 StrBufAppendPrintf(Target, "</td></tr>\n");
766 else if (!strcasecmp(firsttoken, "version")) {
769 else if (!strcasecmp(firsttoken, "rev")) {
772 else if (!strcasecmp(firsttoken, "label")) {
777 /*** Don't show extra fields. They're ugly.
779 StrBufAppendPrintf(Target, "<TR><TD>");
780 StrEscAppend(Target, NULL, thisname, 0, 0);
781 StrBufAppendPrintf(Target, "</TD><TD>");
782 StrEscAppend(Target, NULL, thisvalue, 0, 0);
783 StrBufAppendPrintf(Target, "</TD></TR>\n");
793 StrBufAppendPrintf(Target, "<tr bgcolor=\"#aaaaaa\">"
794 "<td colspan=2 bgcolor=\"#ffffff\">"
795 "<img align=\"center\" src=\"static/webcit_icons/essen/32x32/contact.png\">"
796 "<font size=\"+1\"><b>");
797 StrEscAppend(Target, NULL, fullname, 0, 0);
798 StrBufAppendPrintf(Target, "</b></font>");
799 if (!IsEmptyStr(title)) {
800 StrBufAppendPrintf(Target, "<div align=\"right>\"");
801 StrEscAppend(Target, NULL, title, 0, 0);
802 StrBufAppendPrintf(Target, "</div>");
804 if (!IsEmptyStr(org)) {
805 StrBufAppendPrintf(Target, "<div align=\"right\">");
806 StrEscAppend(Target, NULL, org, 0, 0);
807 StrBufAppendPrintf(Target, "</div>");
809 StrBufAppendPrintf(Target, "</td></tr>\n");
811 if (!IsEmptyStr(phone)) {
812 StrBufAppendPrintf(Target, "<tr><td>");
813 StrBufAppendPrintf(Target, _("Telephone:"));
814 StrBufAppendPrintf(Target, "</td><td>%s</td></tr>\n", phone);
816 if (!IsEmptyStr(mailto)) {
817 StrBufAppendPrintf(Target, "<tr><td>");
818 StrBufAppendPrintf(Target, _("E-mail:"));
819 StrBufAppendPrintf(Target, "</td><td>%s</td></tr>\n", mailto);
825 StrBufAppendPrintf(Target, "</table></div>\n");
829 void PutVcardItem(HashList *thisVC, vcField *thisField, StrBuf *ThisFieldStr, int is_qp, StrBuf *Swap)
831 /* if we have some untagged QP, detect it here. */
832 if (is_qp || (strstr(ChrPtr(ThisFieldStr), "=?")!=NULL)){
834 StrBuf_RFC822_to_Utf8(Swap, ThisFieldStr, NULL, NULL); /* default charset, current charset */
840 Put(thisVC, LKEY(thisField->cval), ThisFieldStr, HFreeStrBuf);
844 * display_vcard() calls this after parsing the textual vCard into
845 * our 'struct vCard' data object.
847 * Set 'full' to nonzero to display the full card, otherwise it will only
848 * show a summary line.
850 * This code is a bit ugly, so perhaps an explanation is due: we do this
851 * in two passes through the vCard fields. On the first pass, we process
852 * fields we understand, and then render them in a pretty fashion at the
853 * end. Then we make a second pass, outputting all the fields we don't
854 * understand in a simple two-column name/value format.
855 * v the vCard to display
856 * full display all items of the vcard?
857 * msgnum Citadel message pointer
859 void parse_vcard(StrBuf *Target, struct vCard *v, HashList *VC, int full, wc_mime_attachment *Mime)
864 char buf[20]; //SIZ];
868 StrBuf *thisname = NULL;
869 char firsttoken[20]; ///SIZ];
875 thisVC = NewHash(0, lFlathash);
877 thisname = NewStrBuf();
878 thisVCToken = NewStrBufPlain(NULL, 63);
879 for (i=0; i<(v->numprops); ++i) {
880 FlushStrBuf(thisVCToken);
883 syslog(LOG_DEBUG, "i: %d oneprop: %s - value: %s", i, v->prop[i].name, v->prop[i].value);
884 StrBufPlain(thisname, v->prop[i].name, -1);
885 StrBufLowerCase(thisname);
887 /*len = */extract_token(firsttoken, ChrPtr(thisname), 0, ';', sizeof firsttoken);
888 ntokens = num_tokens(ChrPtr(thisname), ';');
889 for (j=0, k=0; j < ntokens && k < 10; ++j) {
892 len = extract_token(buf, ChrPtr(thisname), j, ';', sizeof buf);
893 if (!strcasecmp(buf, "encoding=quoted-printable")) {
895 /* remove_token(thisname, j, ';');*/
897 else if (!strcasecmp(buf, "encoding=base64")) {
899 /* remove_token(thisname, j, ';');*/
902 if (StrLength(thisVCToken) > 0) {
903 StrBufAppendBufPlain(thisVCToken, HKEY(";"), 0);
905 StrBufAppendBufPlain(thisVCToken, buf, len, 0);
907 if (GetHash(VCToEnum, buf, len, &V))
911 Put(VC, IKEY(evc), Val, HFreeStrBuf);
913 syslog(LOG_DEBUG, "[%ul] -> k: %d %s - %s", evc, k, buf, VCStr[evc[k]].Key);
922 if ((StrLength(thisVCToken) > 0) &&
923 GetHash(VCTokenToDefine, SKEY(thisVCToken), &vField) &&
925 vcField *thisField = (vcField *)vField;
926 StrBuf *ThisFieldStr = NULL;
927 syslog(LOG_DEBUG, "got this token: %s, found: %s", ChrPtr(thisVCToken), thisField->STR.Key);
928 switch (thisField->Type) {
929 case StringCluster: {
931 const char *Pos = NULL;
932 StrBuf *thisArray = NewStrBufPlain(v->prop[i].value, -1);
933 StrBuf *Buf = NewStrBufPlain(NULL, StrLength(thisArray));
934 while (thisField->Sub[j].STR.len > 0) {
935 StrBufExtract_NextToken(Buf, thisArray, &Pos, ';');
936 ThisFieldStr = NewStrBufDup(Buf);
938 PutVcardItem(thisVC, &thisField->Sub[j], ThisFieldStr, is_qp, Swap);
949 /* copy over the payload into a StrBuf */
950 ThisFieldStr = NewStrBufPlain(v->prop[i].value, -1);
951 PutVcardItem(thisVC, thisField, ThisFieldStr, is_qp, Swap);
954 case Base64BinaryAttachment:
960 /* copy over the payload into a StrBuf */
961 Val = NewStrBufPlain(v->prop[i].value, -1);
963 /* if we have some untagged QP, detect it here. */
964 if (is_qp || (strstr(v->prop[i].value, "=?")!=NULL)){
966 StrBuf_RFC822_to_Utf8(Swap, Val, NULL, NULL); /* default charset, current charset */
973 StrBufDecodeBase64(Val);
977 syslog(LOG_DEBUG, "-> firsttoken: %s thisname: %s Value: [%s][%s]",
982 if (GetHash(VCToEnum, firsttoken, strlen(firsttoken), &V))
985 Put(VC, IKEY(evc), Val, HFreeStrBuf);
986 syslog(LOG_DEBUG, "[%ul]\n", evc);
990 syslog(LOG_DEBUG, "[]\n");
992 TODO: check for layer II
995 long max = num_tokens(thisname, ';');
996 firsttoken[len] = '_';
998 for (j = 0; j < max; j++) {
1001 extract_token(buf, thisname, j, ';', sizeof (buf));
1002 if (!strcasecmp(buf, "tel"))
1004 else if (!strcasecmp(buf, "work"))
1005 strcat(phone, _(" (work)"));
1006 else if (!strcasecmp(buf, "home"))
1007 strcat(phone, _(" (home)"));
1008 else if (!strcasecmp(buf, "cell"))
1009 strcat(phone, _(" (cell)"));
1011 strcat(phone, " (");
1023 /// thisname = NULL;
1028 WCTemplputParams *TP = NULL;
1029 WCTemplputParams SubTP;
1030 FlushStrBuf(Target);
1031 StackContext(TP, &SubTP, thisVC, CTX_VCARD, 0, NULL);
1033 DoTemplate(HKEY("vcard_msg_display"), Target, &SubTP);
1035 UnStackContext(&SubTP);
1037 printf("%s\n", ChrPtr(Target));
1038 FreeStrBuf(&thisVCToken);
1039 DeleteHash(&thisVC);/// todo
1042 void tmplput_VCARD_ITEM(StrBuf *Target, WCTemplputParams *TP)
1044 HashList *VC = CTX(CTX_VCARD);
1048 evc = GetTemplateTokenNumber(Target, TP, 0, -1);
1051 if (GetHash(VC, IKEY(evc), &vStr))
1053 StrBufAppendTemplate(Target, TP,
1061 void new_vcard (StrBuf *Target, struct vCard *v, int full, wc_mime_attachment *Mime)
1064 WCTemplputParams SubTP;
1066 memset(&SubTP, 0, sizeof(WCTemplputParams));
1069 VC = NewHash(0, Flathash);
1070 parse_vcard(Target, v, VC, full, Mime);
1072 SubTP.Filter.ContextType = CTX_VCARD;
1075 //DoTemplate(HKEY("vcard_msg_display"), Target, &SubTP);
1082 * Display a textual vCard
1083 * (Converts to a vCard object and then calls the actual display function)
1084 * Set 'full' to nonzero to display the whole card instead of a one-liner.
1085 * Or, if "storename" is non-NULL, just store the person's name in that
1086 * buffer instead of displaying the card at all.
1088 * vcard_source the buffer containing the vcard text
1089 * alpha Display only if name begins with this letter of the alphabet
1090 * full Display the full vCard (otherwise just the display name)
1091 * storename If not NULL, also store the display name here
1092 * msgnum Citadel message pointer
1094 void display_vcard(StrBuf *Target,
1095 wc_mime_attachment *Mime,
1105 char this_alpha = 0;
1107 v = VCardLoad(Mime->Data);
1109 if (v == NULL) return;
1111 name = vcard_get_prop(v, "n", 1, 0, 0);
1113 Buf = NewStrBufPlain(name, -1);
1114 Buf2 = NewStrBufPlain(NULL, StrLength(Buf));
1115 StrBuf_RFC822_to_Utf8(Buf2, Buf, WC->DefaultCharset, NULL);
1116 this_alpha = ChrPtr(Buf)[0];
1121 if (storename != NULL) {
1122 fetchname_parsed_vcard(v, storename);
1124 else if ((alpha == 0) ||
1125 ((isalpha(alpha)) && (tolower(alpha) == tolower(this_alpha))) ||
1126 ((!isalpha(alpha)) && (!isalpha(this_alpha)))
1129 if (ibstr("x") == 1) {
1130 new_vcard (Target, v, full, Mime);
1132 display_parsed_vcard(Target, v, full, Mime);
1142 * Render the address book using info we gathered during the scan
1144 * addrbook the addressbook to render
1145 * num_ab the number of the addressbook
1147 void do_addrbook_view(addrbookent *addrbook, int num_ab) {
1151 static int NAMESPERPAGE = 60;
1154 char tabfirst_label[64];
1156 char tablast_label[64];
1157 char this_tablabel[64];
1162 wc_printf("<br><br><br><div align=\"center\"><i>");
1163 wc_printf(_("This address book is empty."));
1164 wc_printf("</i></div>\n");
1169 qsort(addrbook, num_ab, sizeof(addrbookent), abcmp);
1172 num_pages = (num_ab / NAMESPERPAGE) + 1;
1174 tablabels = malloc(num_pages * sizeof (char *));
1175 if (tablabels == NULL) {
1176 wc_printf("<br><br><br><div align=\"center\"><i>");
1177 wc_printf(_("An internal error has occurred."));
1178 wc_printf("</i></div>\n");
1182 for (i=0; i<num_pages; ++i) {
1183 tabfirst = i * NAMESPERPAGE;
1184 tablast = tabfirst + NAMESPERPAGE - 1;
1185 if (tablast > (num_ab - 1)) tablast = (num_ab - 1);
1186 nametab(tabfirst_label, 64, addrbook[tabfirst].ab_name);
1187 nametab(tablast_label, 64, addrbook[tablast].ab_name);
1188 sprintf(this_tablabel, "%s - %s", tabfirst_label, tablast_label);
1189 tablabels[i] = strdup(this_tablabel);
1192 tabbed_dialog(num_pages, tablabels);
1195 for (i=0; i<num_ab; ++i) {
1197 if ((i / NAMESPERPAGE) != page) { /* New tab */
1198 page = (i / NAMESPERPAGE);
1200 wc_printf("</tr></table>\n");
1201 end_tab(page-1, num_pages);
1203 begin_tab(page, num_pages);
1204 wc_printf("<table border=\"0\" cellspacing=\"0\" cellpadding=\"3\" width=\"100%%\">\n");
1208 if ((displayed % 4) == 0) {
1209 if (displayed > 0) {
1210 wc_printf("</tr>\n");
1213 wc_printf("<tr bgcolor=\"#%s\">",
1214 (bg ? "dddddd" : "ffffff")
1220 wc_printf("<a href=\"readfwd?startmsg=%ld?is_singlecard=1",
1221 addrbook[i].ab_msgnum);
1222 wc_printf("?maxmsgs=1?is_summary=0?alpha=%s\">", bstr("alpha"));
1223 vcard_n_prettyize(addrbook[i].ab_name);
1224 escputs(addrbook[i].ab_name);
1225 wc_printf("</a></td>\n");
1229 /* Placeholders for empty columns at end */
1230 if ((num_ab % 4) != 0) {
1231 for (i=0; i<(4-(num_ab % 4)); ++i) {
1232 wc_printf("<td> </td>");
1236 wc_printf("</tr></table>\n");
1237 end_tab((num_pages-1), num_pages);
1239 begin_tab(num_pages, num_pages);
1240 /* FIXME there ought to be something here */
1241 end_tab(num_pages, num_pages);
1243 for (i=0; i<num_pages; ++i) {
1253 * Edit the vCard component of a MIME message.
1254 * Supply the message number
1255 * and MIME part number to fetch. Or, specify -1 for the message number
1256 * to start with a blank card.
1258 void do_edit_vcard(long msgnum, char *partnum,
1259 message_summary *VCMsg,
1260 wc_mime_attachment *VCAtt,
1261 const char *return_to,
1262 const char *force_room) {
1263 wcsession *WCC = WC;
1264 message_summary *Msg = NULL;
1265 wc_mime_attachment *VCMime = NULL;
1272 char firstname[256];
1273 char middlename[256];
1286 char mobiletel[256];
1287 char primary_inetemail[256];
1288 char other_inetemail[SIZ];
1289 char extrafields[SIZ];
1310 primary_inetemail[0] = 0;
1311 other_inetemail[0] = 0;
1317 safestrncpy(whatuser, "", sizeof whatuser);
1319 if ((msgnum >= 0) ||
1320 ((VCMsg != NULL) && (VCAtt != NULL)))
1322 if ((VCMsg == NULL) && (VCAtt == NULL)) {
1324 Msg = (message_summary *) malloc(sizeof(message_summary));
1325 memset(Msg, 0, sizeof(message_summary));
1326 Msg->msgnum = msgnum;
1327 VCMime = load_vcard(Msg);
1328 if (VCMime == NULL) {
1329 convenience_page("770000", _("Error"), "");///TODO: important message
1330 DestroyMessageSummary(Msg);
1334 v = VCardLoad(VCMime->Data);
1337 v = VCardLoad(VCAtt->Data);
1340 /* Populate the variables for our form */
1342 while (key = vcard_get_prop(v, "", 0, i, 1), key != NULL) {
1343 char prp[256]; /* property name */
1344 char prm[256]; /* parameters */
1346 value = vcard_get_prop(v, "", 0, i++, 0);
1349 extract_token(prp, key, 0, ';', sizeof prp);
1350 safestrncpy(prm, key, sizeof prm);
1351 remove_token(prm, 0, ';');
1353 if (!strcasecmp(prp, "n")) {
1354 extract_token(lastname, value, 0, ';', sizeof lastname);
1355 extract_token(firstname, value, 1, ';', sizeof firstname);
1356 extract_token(middlename, value, 2, ';', sizeof middlename);
1357 extract_token(prefix, value, 3, ';', sizeof prefix);
1358 extract_token(suffix, value, 4, ';', sizeof suffix);
1361 else if (!strcasecmp(prp, "fn")) {
1362 safestrncpy(fullname, value, sizeof fullname);
1365 else if (!strcasecmp(prp, "title")) {
1366 safestrncpy(title, value, sizeof title);
1369 else if (!strcasecmp(prp, "org")) {
1370 safestrncpy(org, value, sizeof org);
1373 else if (!strcasecmp(prp, "adr")) {
1374 extract_token(pobox, value, 0, ';', sizeof pobox);
1375 extract_token(extadr, value, 1, ';', sizeof extadr);
1376 extract_token(street, value, 2, ';', sizeof street);
1377 extract_token(city, value, 3, ';', sizeof city);
1378 extract_token(state, value, 4, ';', sizeof state);
1379 extract_token(zipcode, value, 5, ';', sizeof zipcode);
1380 extract_token(country, value, 6, ';', sizeof country);
1383 else if (!strcasecmp(prp, "tel")) {
1385 if (bmstrcasestr(prm, "home")) {
1386 extract_token(hometel, value, 0, ';', sizeof hometel);
1388 else if (bmstrcasestr(prm, "work")) {
1389 extract_token(worktel, value, 0, ';', sizeof worktel);
1391 else if (bmstrcasestr(prm, "fax")) {
1392 extract_token(faxtel, value, 0, ';', sizeof faxtel);
1394 else if (bmstrcasestr(prm, "cell")) {
1395 extract_token(mobiletel, value, 0, ';', sizeof mobiletel);
1397 else { /* Missing or unknown type; put it in the home phone */
1398 extract_token(hometel, value, 0, ';', sizeof hometel);
1402 else if ( (!strcasecmp(prp, "email")) && (bmstrcasestr(prm, "internet")) ) {
1403 if (primary_inetemail[0] == 0) {
1404 safestrncpy(primary_inetemail, value, sizeof primary_inetemail);
1407 if (other_inetemail[0] != 0) {
1408 strcat(other_inetemail, "\n");
1410 strcat(other_inetemail, value);
1414 /* Unrecognized properties are preserved here so we don't discard them
1415 * just because the vCard was edited with WebCit.
1418 strcat(extrafields, key);
1419 strcat(extrafields, ":");
1420 strcat(extrafields, value);
1421 strcat(extrafields, "\n");
1429 /* Display the form */
1430 output_headers(1, 1, 1, 0, 0, 0);
1432 do_template("box_begin_1");
1433 StrBufAppendBufPlain(WC->WBuf, _("Edit contact information"), -1, 0);
1434 do_template("box_begin_2");
1436 wc_printf("<form method=\"POST\" action=\"submit_vcard\">\n");
1437 wc_printf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
1439 if (force_room != NULL) {
1440 wc_printf("<input type=\"hidden\" name=\"force_room\" value=\"");
1441 escputs(force_room);
1446 wc_printf("<input type=\"hidden\" name=\"go\" value=\"");
1447 StrEscAppend(WCC->WBuf, WCC->CurRoom.name, NULL, 0, 0);
1451 wc_printf("<table class=\"vcard_edit_background\"><tr><td>\n");
1453 wc_printf("<table border=\"0\"><tr>"
1458 "<td>%s</td></tr>\n",
1459 _("Prefix"), _("First Name"), _("Middle Name"), _("Last Name"), _("Suffix")
1461 wc_printf("<tr><td><input type=\"text\" name=\"prefix\" "
1462 "value=\"%s\" maxlength=\"5\" size=\"5\"></td>",
1464 wc_printf("<td><input type=\"text\" name=\"firstname\" "
1465 "value=\"%s\" maxlength=\"29\"></td>",
1467 wc_printf("<td><input type=\"text\" name=\"middlename\" "
1468 "value=\"%s\" maxlength=\"29\"></td>",
1470 wc_printf("<td><input type=\"text\" name=\"lastname\" "
1471 "value=\"%s\" maxlength=\"29\"></td>",
1473 wc_printf("<td><input type=\"text\" name=\"suffix\" "
1474 "value=\"%s\" maxlength=\"10\" size=\"10\"></td></tr></table>\n",
1477 wc_printf("<table class=\"vcard_edit_background_alt\">");
1478 wc_printf("<tr><td>");
1480 wc_printf(_("Display name:"));
1482 "<input type=\"text\" name=\"fullname\" "
1483 "value=\"%s\" maxlength=\"40\"><br><br>\n",
1487 wc_printf(_("Title:"));
1489 "<input type=\"text\" name=\"title\" "
1490 "value=\"%s\" maxlength=\"40\"><br><br>\n",
1494 wc_printf(_("Organization:"));
1496 "<input type=\"text\" name=\"org\" "
1497 "value=\"%s\" maxlength=\"40\"><br><br>\n",
1501 wc_printf("</td><td>");
1503 wc_printf("<table border=\"0\">");
1504 wc_printf("<tr><td>");
1505 wc_printf(_("PO box:"));
1506 wc_printf("</td><td>"
1507 "<input type=\"text\" name=\"pobox\" "
1508 "value=\"%s\" maxlength=\"29\"></td></tr>\n",
1510 wc_printf("<tr><td>");
1511 wc_printf(_("Address:"));
1512 wc_printf("</td><td>"
1513 "<input type=\"text\" name=\"extadr\" "
1514 "value=\"%s\" maxlength=\"29\"></td></tr>\n",
1516 wc_printf("<tr><td> </td><td>"
1517 "<input type=\"text\" name=\"street\" "
1518 "value=\"%s\" maxlength=\"29\"></td></tr>\n",
1520 wc_printf("<tr><td>");
1521 wc_printf(_("City:"));
1522 wc_printf("</td><td>"
1523 "<input type=\"text\" name=\"city\" "
1524 "value=\"%s\" maxlength=\"29\"></td></tr>\n",
1526 wc_printf("<tr><td>");
1527 wc_printf(_("State:"));
1528 wc_printf("</td><td>"
1529 "<input type=\"text\" name=\"state\" "
1530 "value=\"%s\" maxlength=\"29\"></td></tr>\n",
1532 wc_printf("<tr><td>");
1533 wc_printf(_("ZIP code:"));
1534 wc_printf("</td><td>"
1535 "<input type=\"text\" name=\"zipcode\" "
1536 "value=\"%s\" maxlength=\"10\"></td></tr>\n",
1538 wc_printf("<tr><td>");
1539 wc_printf(_("Country:"));
1540 wc_printf("</td><td>"
1541 "<input type=\"text\" name=\"country\" "
1542 "value=\"%s\" maxlength=\"29\" width=\"5\"></td></tr>\n",
1544 wc_printf("</table>\n");
1546 wc_printf("</table>\n");
1548 wc_printf("<table border=0><tr><td>");
1549 wc_printf(_("Home telephone:"));
1551 "<td><input type=\"text\" name=\"hometel\" "
1552 "value=\"%s\" maxlength=\"29\"></td>\n",
1555 wc_printf(_("Work telephone:"));
1557 "<td><input type=\"text\" name=\"worktel\" "
1558 "value=\"%s\" maxlength=\"29\"></td></tr>\n",
1560 wc_printf("<tr><td>");
1561 wc_printf(_("Mobile telephone:"));
1563 "<td><input type=\"text\" name=\"mobiletel\" "
1564 "value=\"%s\" maxlength=\"29\"></td>\n",
1567 wc_printf(_("Fax number:"));
1569 "<td><input type=\"text\" name=\"faxtel\" "
1570 "value=\"%s\" maxlength=\"29\"></td></tr></table>\n",
1573 wc_printf("<table class=\"vcard_edit_background_alt\">");
1574 wc_printf("<tr><td>");
1576 wc_printf("<table border=0><TR>"
1578 wc_printf(_("Primary Internet e-mail address"));
1580 "<input type=\"text\" name=\"primary_inetemail\" "
1581 "size=40 maxlength=60 value=\"");
1582 escputs(primary_inetemail);
1584 "</td><td valign=top>");
1585 wc_printf(_("Internet e-mail aliases"));
1587 "<textarea name=\"other_inetemail\" rows=5 cols=40 width=40>");
1588 escputs(other_inetemail);
1589 wc_printf("</textarea></td></tr></table>\n");
1591 wc_printf("</td></tr></table>\n");
1593 wc_printf("<input type=\"hidden\" name=\"extrafields\" value=\"");
1594 escputs(extrafields);
1597 wc_printf("<input type=\"hidden\" name=\"return_to\" value=\"");
1601 wc_printf("<div class=\"buttons\">\n"
1602 "<input type=\"submit\" name=\"ok_button\" value=\"%s\">"
1604 "<input type=\"submit\" name=\"cancel_button\" value=\"%s\">"
1610 wc_printf("</td></tr></table>\n");
1611 do_template("box_end");
1614 DestroyMessageSummary(Msg);
1620 * commit the edits to the citadel server
1622 void edit_vcard(void) {
1626 msgnum = lbstr("msgnum");
1627 partnum = bstr("partnum");
1628 do_edit_vcard(msgnum, partnum, NULL, NULL, "", NULL);
1634 * parse edited vcard from the browser
1636 void submit_vcard(void) {
1638 char *serialized_vcard;
1641 const StrBuf *ForceRoom;
1644 if (!havebstr("ok_button")) {
1645 readloop(readnew, eUseDefault);
1649 if (havebstr("force_room")) {
1650 ForceRoom = sbstr("force_room");
1651 if (gotoroom(ForceRoom) != 200) {
1652 AppendImportantMessage(_("Unable to enter the room to save your message"), -1);
1653 AppendImportantMessage(HKEY(": "));
1654 AppendImportantMessage(SKEY(ForceRoom));
1655 AppendImportantMessage(HKEY("; "));
1656 AppendImportantMessage(_("Aborting."), -1);
1658 if (!strcmp(bstr("return_to"), "select_user_to_edit")) {
1659 select_user_to_edit(NULL);
1661 else if (!strcmp(bstr("return_to"), "do_welcome")) {
1664 else if (!IsEmptyStr(bstr("return_to"))) {
1665 http_redirect(bstr("return_to"));
1668 readloop(readnew, eUseDefault);
1675 serv_write(HKEY("ENT0 1|||4\n"));
1676 if (!StrBuf_ServGetln(Buf) && (GetServerStatus(Buf, NULL) != 4))
1682 /* Make a vCard structure out of the data supplied in the form */
1683 StrBufPrintf(Buf, "begin:vcard\r\n%s\r\nend:vcard\r\n",
1686 v = VCardLoad(Buf); /* Start with the extra fields */
1688 AppendImportantMessage(_("An error has occurred."), -1);
1694 snprintf(buf, sizeof buf, "%s;%s;%s;%s;%s",
1700 vcard_add_prop(v, "n", buf);
1702 vcard_add_prop(v, "title", bstr("title"));
1703 vcard_add_prop(v, "fn", bstr("fullname"));
1704 vcard_add_prop(v, "org", bstr("org"));
1706 snprintf(buf, sizeof buf, "%s;%s;%s;%s;%s;%s;%s",
1714 vcard_add_prop(v, "adr", buf);
1716 vcard_add_prop(v, "tel;home", bstr("hometel"));
1717 vcard_add_prop(v, "tel;work", bstr("worktel"));
1718 vcard_add_prop(v, "tel;fax", bstr("faxtel"));
1719 vcard_add_prop(v, "tel;cell", bstr("mobiletel"));
1720 vcard_add_prop(v, "email;internet", bstr("primary_inetemail"));
1722 for (i=0; i<num_tokens(bstr("other_inetemail"), '\n'); ++i) {
1723 extract_token(buf, bstr("other_inetemail"), i, '\n', sizeof buf);
1724 if (!IsEmptyStr(buf)) {
1725 vcard_add_prop(v, "email;internet", buf);
1729 serialized_vcard = vcard_serialize(v);
1731 if (serialized_vcard == NULL) {
1732 AppendImportantMessage(_("An error has occurred."), -1);
1738 serv_write(HKEY("Content-type: text/x-vcard; charset=UTF-8\n"));
1739 serv_write(HKEY("\n"));
1740 serv_printf("%s\r\n", serialized_vcard);
1741 serv_write(HKEY("000\n"));
1742 free(serialized_vcard);
1744 if (!strcmp(bstr("return_to"), "select_user_to_edit")) {
1745 select_user_to_edit(NULL);
1747 else if (!strcmp(bstr("return_to"), "do_welcome")) {
1750 else if (!IsEmptyStr(bstr("return_to"))) {
1751 http_redirect(bstr("return_to"));
1754 readloop(readnew, eUseDefault);
1762 * Extract an embedded photo from a vCard for display on the client
1764 void display_vcard_photo_img(void)
1770 const char *contentType;
1771 wcsession *WCC = WC;
1773 msgnum = StrBufExtract_long(WCC->Hdr->HR.ReqLine, 0, '/');
1775 vcard = load_mimepart(msgnum,"1");
1776 v = VCardLoad(vcard);
1778 photosrc = vcard_get_prop(v, "PHOTO", 1,0,0);
1779 FlushStrBuf(WCC->WBuf);
1780 StrBufAppendBufPlain(WCC->WBuf, photosrc, -1, 0);
1781 if (StrBufDecodeBase64(WCC->WBuf) <= 0) {
1782 FlushStrBuf(WCC->WBuf);
1784 hprintf("HTTP/1.1 500 %s\n","Unable to get photo");
1785 output_headers(0, 0, 0, 0, 0, 0);
1786 hprintf("Content-Type: text/plain\r\n");
1788 wc_printf(_("Could Not decode vcard photo\n"));
1792 contentType = GuessMimeType(ChrPtr(WCC->WBuf), StrLength(WCC->WBuf));
1793 http_transmit_thing(contentType, 0);
1798 typedef struct _vcardview_struct {
1800 addrbookent *addrbook;
1805 int vcard_GetParamsGetServerCall(SharedMessageStatus *Stat,
1806 void **ViewSpecific,
1813 vcardview_struct *VS;
1815 VS = (vcardview_struct*) malloc (sizeof(vcardview_struct));
1816 memset(VS, 0, sizeof(vcardview_struct));
1817 *ViewSpecific = (void*)VS;
1819 VS->is_singlecard = ibstr("is_singlecard");
1820 if (VS->is_singlecard != 1) {
1821 if (oper == do_search) {
1822 snprintf(cmd, len, "MSGS SEARCH|%s", bstr("query"));
1825 strcpy(cmd, "MSGS ALL");
1827 Stat->maxmsgs = 9999999;
1832 int vcard_LoadMsgFromServer(SharedMessageStatus *Stat,
1833 void **ViewSpecific,
1834 message_summary* Msg,
1838 vcardview_struct *VS;
1841 VS = (vcardview_struct*) *ViewSpecific;
1844 fetch_ab_name(Msg, &ab_name);
1845 if (ab_name == NULL)
1848 VS->addrbook = realloc(VS->addrbook,
1849 (sizeof(addrbookent) * VS->num_ab) );
1850 safestrncpy(VS->addrbook[VS->num_ab-1].ab_name, ab_name,
1851 sizeof(VS->addrbook[VS->num_ab-1].ab_name));
1852 VS->addrbook[VS->num_ab-1].ab_msgnum = Msg->msgnum;
1858 int vcard_RenderView_or_Tail(SharedMessageStatus *Stat, void **ViewSpecific, long oper)
1861 vcardview_struct *VS;
1863 VS = (vcardview_struct*) *ViewSpecific;
1864 if (VS->is_singlecard)
1865 read_message(WC->WBuf, HKEY("view_message"), lbstr("startmsg"), NULL, &Mime);
1867 do_addrbook_view(VS->addrbook, VS->num_ab); /* Render the address book */
1871 int vcard_Cleanup(void **ViewSpecific)
1873 vcardview_struct *VS;
1875 VS = (vcardview_struct*) *ViewSpecific;
1878 (VS->addrbook != NULL))
1886 ServerStartModule_VCARD
1889 ///VCToEnum = NewHash(0, NULL);
1894 ServerShutdownModule_VCARD
1897 /// DeleteHash(&VCToEnum);
1904 RegisterCTX(CTX_VCARD);
1905 RegisterCTX(CTX_VCARD_TYPE);
1906 RegisterReadLoopHandlerset(
1908 vcard_GetParamsGetServerCall,
1912 vcard_LoadMsgFromServer,
1913 vcard_RenderView_or_Tail,
1915 WebcitAddUrlHandler(HKEY("edit_vcard"), "", 0, edit_vcard, 0);
1916 WebcitAddUrlHandler(HKEY("submit_vcard"), "", 0, submit_vcard, 0);
1917 WebcitAddUrlHandler(HKEY("vcardphoto"), "", 0, display_vcard_photo_img, NEED_URL);
1919 Put(VCToEnum, HKEY("n"), (void*)VC_n, reference_free_handler);
1920 Put(VCToEnum, HKEY("fn"), (void*)VC_fn, reference_free_handler);
1921 Put(VCToEnum, HKEY("title"), (void*)VC_title, reference_free_handler);
1922 Put(VCToEnum, HKEY("org"), (void*)VC_org, reference_free_handler);
1923 Put(VCToEnum, HKEY("email"), (void*)VC_email, reference_free_handler);
1924 Put(VCToEnum, HKEY("tel"), (void*)VC_tel, reference_free_handler);
1925 Put(VCToEnum, HKEY("work"), (void*)VC_work, reference_free_handler);
1926 Put(VCToEnum, HKEY("home"), (void*)VC_home, reference_free_handler);
1927 Put(VCToEnum, HKEY("cell"), (void*)VC_cell, reference_free_handler);
1928 Put(VCToEnum, HKEY("adr"), (void*)VC_adr, reference_free_handler);
1929 Put(VCToEnum, HKEY("photo"), (void*)VC_photo, reference_free_handler);
1930 Put(VCToEnum, HKEY("version"), (void*)VC_version, reference_free_handler);
1931 Put(VCToEnum, HKEY("rev"), (void*)VC_rev, reference_free_handler);
1932 Put(VCToEnum, HKEY("label"), (void*)VC_label, reference_free_handler);
1935 RegisterNamespace("VC", 1, 2, tmplput_VCARD_ITEM, NULL, CTX_VCARD);
1937 REGISTERTokenParamDefine(VC_n);
1938 REGISTERTokenParamDefine(VC_fn);
1939 REGISTERTokenParamDefine(VC_title);
1940 REGISTERTokenParamDefine(VC_org);
1941 REGISTERTokenParamDefine(VC_email);
1942 REGISTERTokenParamDefine(VC_tel);
1943 REGISTERTokenParamDefine(VC_work);
1944 REGISTERTokenParamDefine(VC_home);
1945 REGISTERTokenParamDefine(VC_cell);
1946 REGISTERTokenParamDefine(VC_adr);
1947 REGISTERTokenParamDefine(VC_photo);
1948 REGISTERTokenParamDefine(VC_version);
1949 REGISTERTokenParamDefine(VC_rev);
1950 REGISTERTokenParamDefine(VC_label);
1954 StrBuf *Prefix = NewStrBufPlain(HKEY("VC:"));
1955 DefineToToken = NewHash(1, lFlathash);
1956 vcNames = NewHash(1, lFlathash);
1957 VCTokenToDefine = NewHash(1, NULL);
1958 autoRegisterTokens(&VCEnumCounter, VCStrE, Prefix, 0);
1959 FreeStrBuf(&Prefix);
1961 RegisterCTX(CTX_VCARD);
1962 RegisterNamespace("VC:ITEM", 2, 2, tmpl_vcard_item, preeval_vcard_item, CTX_VCARD);
1963 RegisterNamespace("VC:CTXITEM", 1, 1, tmpl_vcard_context_item, NULL, CTX_VCARD_TYPE);
1964 RegisterNamespace("VC:NAME", 1, 1, tmpl_vcard_name_str, preeval_vcard_name_str, CTX_VCARD);
1965 RegisterNamespace("VC:CTXNAME", 1, 1, tmpl_vcard_context_name_str, NULL, CTX_VCARD_TYPE);
1966 REGISTERTokenParamDefine(FlatString);
1967 REGISTERTokenParamDefine(StringCluster);
1968 REGISTERTokenParamDefine(PhoneNumber);
1969 REGISTERTokenParamDefine(EmailAddr);
1970 REGISTERTokenParamDefine(Street);
1971 REGISTERTokenParamDefine(Number);
1972 REGISTERTokenParamDefine(AliasFor);
1973 REGISTERTokenParamDefine(Base64BinaryAttachment);
1974 REGISTERTokenParamDefine(TerminateList);
1976 RegisterConditional("VC:HAVE:TYPE", 1, conditional_VC_Havetype, CTX_VCARD);
1977 RegisterFilteredIterator("VC:TYPE", 1, DefineToToken, NULL, NULL, NULL, filter_VC_ByType, CTX_VCARD_TYPE, CTX_VCARD, IT_NOFLAG);
1978 RegisterFilteredIterator("VC:TYPE:ITEMS", 0, NULL, getContextVcard, NULL, NULL, filter_VC_ByContextType, CTX_STRBUF, CTX_VCARD_TYPE, IT_NOFLAG);