X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=webcit%2Fvcard_edit.c;h=d5369aa78e9ea1ab45ddb44f9d5a677e313bf832;hb=1b278ca1243861adba31579d1633b11c8e096271;hp=bcb79387cb43a2f25910e6edb30bfb357309a6a3;hpb=12af59f130372022695276c24333420e78ac8c45;p=citadel.git diff --git a/webcit/vcard_edit.c b/webcit/vcard_edit.c index bcb79387c..d5369aa78 100644 --- a/webcit/vcard_edit.c +++ b/webcit/vcard_edit.c @@ -1,65 +1,694 @@ + +#include "webcit.h" +#include "calendar.h" + +/* + * 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; + + 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "webcit.h" -#include "vcard.h" + 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, ""); + 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 { -/* Edit the vCard component of a MIME message. Supply the message number + /*** 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"); +} + + + +/* + * 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) +{ + 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))) + ) + { + display_parsed_vcard(Target, v, full, Mime); + } + + 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; + + tablabels = malloc(num_pages * sizeof (char *)); + if (tablabels == NULL) { + wc_printf("


"); + wc_printf(_("An internal error has occurred.")); + wc_printf("
\n"); + return; + } + + 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; + } + + if ((displayed % 4) == 0) { + if (displayed > 0) { + wc_printf("\n"); + } + bg = 1 - bg; + wc_printf("", + (bg ? "DDDDDD" : "FFFFFF") + ); + } + + wc_printf("\n"); + ++displayed; + } + + /* Placeholders for empty columns at end */ + if ((num_ab % 4) != 0) { + for (i=0; i<(4-(num_ab % 4)); ++i) { + wc_printf(""); + } + } + + 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; i= 0) { - sprintf(buf, "MSG0 %ld|1", msgnum); - serv_puts(buf); - serv_getln(buf, sizeof buf); - if (buf[0] != '1') { - convenience_page("770000", "Error", &buf[4]); - return; - } - while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) { - if (!strncasecmp(buf, "from=", 5)) { - safestrncpy(whatuser, &buf[5], sizeof whatuser); - } - else if (!strncasecmp(buf, "node=", 5)) { - strcat(whatuser, " @ "); - strcat(whatuser, &buf[5]); + if ((msgnum >= 0) || + ((VCMsg != NULL) && (VCAtt != NULL))) + { + if ((VCMsg == NULL) && (VCAtt == NULL)) { + + Msg = (message_summary *) malloc(sizeof(message_summary)); + memset(Msg, 0, sizeof(message_summary)); + Msg->msgnum = msgnum; + VCMime = load_vcard(Msg); + if (VCMime == NULL) { + convenience_page("770000", _("Error"), "");///TODO: important message + DestroyMessageSummary(Msg); + return; } + + v = VCardLoad(VCMime->Data); } - - sprintf(buf, "OPNA %ld|%s", msgnum, partnum); - serv_puts(buf); - serv_getln(buf, sizeof buf); - if (buf[0] != '2') { - convenience_page("770000", "Error", &buf[4]); - return; + else { + v = VCardLoad(VCAtt->Data); } - total_len = atoi(&buf[4]); - serialized_vcard = malloc(total_len + 2); - - read_server_binary(serialized_vcard, total_len); - - serv_puts("CLOS"); - serv_getln(buf, sizeof buf); - serialized_vcard[total_len] = 0; - - v = vcard_load(serialized_vcard); - free(serialized_vcard); - /* 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); - - if (!strcasecmp(key, "n")) { + + + 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); @@ -134,15 +757,19 @@ void do_edit_vcard(long msgnum, char *partnum, char *return_to) { extract_token(suffix, value, 4, ';', sizeof suffix); } - else if (!strcasecmp(key, "title")) { + else if (!strcasecmp(prp, "fn")) { + safestrncpy(fullname, value, sizeof fullname); + } + + else if (!strcasecmp(prp, "title")) { safestrncpy(title, value, sizeof title); } - else if (!strcasecmp(key, "org")) { + else if (!strcasecmp(prp, "org")) { safestrncpy(org, value, sizeof org); } - else if (!strcasecmp(key, "adr")) { + 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); @@ -151,16 +778,27 @@ void do_edit_vcard(long msgnum, char *partnum, char *return_to) { extract_token(zipcode, value, 5, ';', sizeof zipcode); extract_token(country, value, 6, ';', sizeof country); } - - else if (!strcasecmp(key, "tel;home")) { - extract_token(hometel, value, 0, ';', sizeof hometel); - } - - else if (!strcasecmp(key, "tel;work")) { - extract_token(worktel, value, 0, ';', sizeof worktel); + + 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(key, "email;internet")) { + else if ( (!strcasecmp(prp, "email")) && (bmstrcasestr(prm, "internet")) ) { if (primary_inetemail[0] == 0) { safestrncpy(primary_inetemail, value, sizeof primary_inetemail); } @@ -171,7 +809,10 @@ void do_edit_vcard(long msgnum, char *partnum, char *return_to) { 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, ":"); @@ -185,161 +826,251 @@ void do_edit_vcard(long msgnum, char *partnum, char *return_to) { } /* Display the form */ - output_headers(1, 1, 2, 0, 0, 0, 0); - wprintf("
\n" - "
" - "" - "" - "Edit contact information" - "" - "
\n" - "
\n
\n" - ); + output_headers(1, 1, 1, 0, 0, 0); - wprintf("
\n"); - wprintf("
" - "
\n"); - - wprintf("" - "" - "" - "" - "" - "\n"); - wprintf("", + do_template("beginbox_1", NULL); + StrBufAppendBufPlain(WC->WBuf, _("Edit contact information"), -1, 0); + do_template("beginbox_2", NULL); + + wc_printf("\n"); + wc_printf("\n", WC->nonce); + + if (force_room != NULL) { + wc_printf("\n"); + } + + wc_printf("
" + "
PrefixFirstMiddleLastSuffix
\n"); + + wc_printf("" + "" + "" + "" + "" + "\n", + _("Prefix"), _("First Name"), _("Middle Name"), _("Last Name"), _("Suffix") + ); + wc_printf("", prefix); - wprintf("", + wc_printf("", firstname); - wprintf("", + wc_printf("", middlename); - wprintf("", + wc_printf("", lastname); - wprintf("
%s%s%s%s%s
\n", + wc_printf("
\n", suffix); - wprintf(""); - wprintf("
"); + wc_printf(""); + wc_printf("
"); + + wc_printf(_("Display name:")); + wc_printf("
" + "

\n", + fullname + ); - wprintf("Title:
" - "

\n", + wc_printf(_("Title:")); + wc_printf("
" + "

\n", title ); - wprintf("Organization:
" - "

\n", + wc_printf(_("Organization:")); + wc_printf("
" + "

\n", org ); - wprintf("
"); + wc_printf(""); - wprintf(""); - wprintf("\n", + wc_printf("
PO box:" - "
"); + wc_printf("\n", pobox); - wprintf("\n", + wc_printf("\n", extadr); - wprintf("\n", + wc_printf("\n", street); - wprintf("\n", + wc_printf("\n", city); - wprintf("\n", + wc_printf("\n", state); - wprintf("\n", + wc_printf("\n", zipcode); - wprintf("\n", + wc_printf("\n", country); - wprintf("
"); + wc_printf(_("PO box:")); + wc_printf("" + "
Address:" - "
"); + wc_printf(_("Address:")); + wc_printf("" + "
" - "
" + "
City:" - "
"); + wc_printf(_("City:")); + wc_printf("" + "
State:" - "
"); + wc_printf(_("State:")); + wc_printf("" + "
ZIP code:" - "
"); + wc_printf(_("ZIP code:")); + wc_printf("" + "
Country:" - "
"); + wc_printf(_("Country:")); + wc_printf("" + "
\n"); + wc_printf("
\n"); - wprintf("
\n"); + wc_printf("
\n"); - wprintf("" - "\n", + wc_printf("
Home telephone:
" + "\n", hometel); - wprintf("" - "
"); + wc_printf(_("Home telephone:")); + wc_printf("Work telephone:
\n", + wc_printf(""); + wc_printf(_("Work telephone:")); + wc_printf("" + "\n", worktel); + wc_printf(""); + wc_printf(_("Mobile telephone:")); + wc_printf("" + "\n", + mobiletel); + wc_printf(""); + wc_printf(_("Fax number:")); + wc_printf("" + "\n", + faxtel); - wprintf(""); - wprintf("
"); + wc_printf(""); + wc_printf("
"); - wprintf("" - "" + "
Primary Internet e-mail address
" - "
"); + wc_printf(_("Primary Internet e-mail address")); + wc_printf("
" + "
" - "
" - "Internet e-mail aliases
" - "
\n"); + wc_printf("
\n"); - wprintf("
\n"); + wc_printf("\n"); - wprintf("\n"); + wc_printf("\">\n"); - wprintf("\n"); + wc_printf("\n"); - wprintf("
\n" - "" + wc_printf("
\n" + "" " " - "" - "
\n" + "" + "
\n", + _("Save changes"), + _("Cancel") ); - wprintf("
\n"); + wc_printf("\n"); + do_template("endbox", NULL); wDumpContent(1); + if (Msg != NULL) { + DestroyMessageSummary(Msg); + } } - +/* + * commit the edits to the citadel server + */ void edit_vcard(void) { long msgnum; char *partnum; - msgnum = atol(bstr("msgnum")); + msgnum = lbstr("msgnum"); partnum = bstr("partnum"); - do_edit_vcard(msgnum, partnum, ""); + do_edit_vcard(msgnum, partnum, NULL, NULL, "", NULL); } - +/* + * parse edited vcard from the browser + */ void submit_vcard(void) { + wcsession *WCC = WC; + struct vCard *v; + char *serialized_vcard; char buf[SIZ]; + StrBuf *Buf; int i; - if (strcmp(bstr("sc"), "OK")) { - readloop("readnew"); + if (!havebstr("ok_button")) { + readloop(readnew, eUseDefault); return; } + if (havebstr("force_room")) { + if (gotoroom(sbstr("force_room")) != 200) { + StrBufAppendBufPlain(WCC->ImportantMsg, + _("Unable to enter the room to save your message"), + -1, 0); + StrBufAppendBufPlain(WCC->ImportantMsg, + HKEY(": "), 0); + StrBufAppendBuf(WCC->ImportantMsg, sbstr("force_room"), 0); + StrBufAppendBufPlain(WCC->ImportantMsg, + HKEY("; "), 0); + + StrBufAppendBufPlain(WCC->ImportantMsg, + _("Aborting."), + -1, 0); + + if (!strcmp(bstr("return_to"), "select_user_to_edit")) { + select_user_to_edit(NULL); + } + else if (!strcmp(bstr("return_to"), "do_welcome")) { + do_welcome(); + } + else if (!IsEmptyStr(bstr("return_to"))) { + http_redirect(bstr("return_to")); + } + else { + readloop(readnew, eUseDefault); + } + return; + } + } + sprintf(buf, "ENT0 1|||4||"); serv_puts(buf); serv_getln(buf, sizeof buf); @@ -348,18 +1079,35 @@ void submit_vcard(void) { return; } - serv_puts("Content-type: text/x-vcard"); - serv_puts(""); - serv_puts("begin:vcard"); - serv_printf("n:%s;%s;%s;%s;%s", + /* Make a vCard structure out of the data supplied in the form */ + Buf = NewStrBuf(); + StrBufPrintf(Buf, "begin:vcard\r\n%s\r\nend:vcard\r\n", + bstr("extrafields") + ); + v = VCardLoad(Buf); /* Start with the extra fields */ + FreeStrBuf(&Buf); + if (v == NULL) { + safestrncpy(WCC->ImportantMessage, + _("An error has occurred."), + sizeof WCC->ImportantMessage + ); + edit_vcard(); + return; + } + + snprintf(buf, sizeof buf, "%s;%s;%s;%s;%s", bstr("lastname"), bstr("firstname"), bstr("middlename"), bstr("prefix"), bstr("suffix") ); - serv_printf("title:%s", bstr("title") ); - serv_printf("org:%s", bstr("org") ); - serv_printf("adr:%s;%s;%s;%s;%s;%s;%s", + 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"), @@ -367,28 +1115,190 @@ void submit_vcard(void) { bstr("state"), bstr("zipcode"), bstr("country") ); - serv_printf("tel;home:%s", bstr("hometel") ); - serv_printf("tel;work:%s", bstr("worktel") ); + 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")); - serv_printf("email;internet:%s\n", bstr("primary_inetemail")); for (i=0; i 0) { - serv_printf("email;internet:%s", buf); + if (!IsEmptyStr(buf)) { + vcard_add_prop(v, "email;internet", buf); } } - serv_printf("%s", bstr("extrafields") ); - serv_puts("end:vcard"); + serialized_vcard = vcard_serialize(v); + vcard_free(v); + if (serialized_vcard == NULL) { + safestrncpy(WCC->ImportantMessage, + _("An error has occurred."), + sizeof WCC->ImportantMessage + ); + edit_vcard(); + return; + } + + serv_puts("Content-type: text/x-vcard; charset=UTF-8"); + serv_puts(""); + serv_printf("%s\r\n", serialized_vcard); serv_puts("000"); + free(serialized_vcard); - if (!strcmp(bstr("return_to"), "/select_user_to_edit")) { - select_user_to_edit(NULL, NULL); + if (!strcmp(bstr("return_to"), "select_user_to_edit")) { + select_user_to_edit(NULL); } - else if (!strcmp(bstr("return_to"), "/do_welcome")) { + else if (!strcmp(bstr("return_to"), "do_welcome")) { do_welcome(); } + else if (!IsEmptyStr(bstr("return_to"))) { + http_redirect(bstr("return_to")); + } else { - readloop("readnew"); + readloop(readnew, eUseDefault); + } +} + + + +/* + * 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); +} + +typedef struct _vcardview_struct { + long is_singlecard; + addrbookent *addrbook; + long num_ab; + +} vcardview_struct; + +int vcard_GetParamsGetServerCall(SharedMessageStatus *Stat, + void **ViewSpecific, + long oper, + char *cmd, + long len) +{ + vcardview_struct *VS; + + VS = (vcardview_struct*) malloc (sizeof(vcardview_struct)); + memset(VS, 0, sizeof(vcardview_struct)); + *ViewSpecific = (void*)VS; + + VS->is_singlecard = ibstr("is_singlecard"); + if (VS->is_singlecard != 1) { + if (oper == do_search) { + snprintf(cmd, len, "MSGS SEARCH|%s", bstr("query")); + } + else { + strcpy(cmd, "MSGS ALL"); + } + Stat->maxmsgs = 9999999; } + return 200; +} + +int vcard_LoadMsgFromServer(SharedMessageStatus *Stat, + void **ViewSpecific, + message_summary* Msg, + int is_new, + int i) +{ + vcardview_struct *VS; + char *ab_name; + + VS = (vcardview_struct*) *ViewSpecific; + + ab_name = NULL; + fetch_ab_name(Msg, &ab_name); + if (ab_name == 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); + return 0; } + + +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 */ + return 0; +} + +int vcard_Cleanup(void **ViewSpecific) +{ + vcardview_struct *VS; + + VS = (vcardview_struct*) *ViewSpecific; + wDumpContent(1); + if ((VS != NULL) && + (VS->addrbook != NULL)) + free(VS->addrbook); + if (VS != NULL) + free(VS); + return 0; +} + +void +InitModule_VCARD +(void) +{ + RegisterReadLoopHandlerset( + VIEW_ADDRESSBOOK, + vcard_GetParamsGetServerCall, + NULL, + NULL, + vcard_LoadMsgFromServer, + vcard_RenderView_or_Tail, + vcard_Cleanup); + 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); +} +