Back to index

webcit  8.12-dfsg
vcard_edit.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 1996-2012 by the citadel.org team
00003  *
00004  * This program is open source software.  You can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License, version 3.
00006  *
00007  * This program is distributed in the hope that it will be useful,
00008  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00009  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00010  * GNU General Public License for more details.
00011  */
00012 
00013 #include "webcit.h"
00014 #include "webserver.h"
00015 #include "calendar.h"
00016 
00017 
00018 
00019 ConstStr VCStr [] = {
00020        {HKEY("n")}, /* N is name, but only if there's no FN already there */
00021        {HKEY("fn")}, /* FN (full name) is a true 'display name' field */
00022        {HKEY("title")},   /* title */
00023        {HKEY("org")},    /* organization */
00024        {HKEY("email")},
00025        {HKEY("tel")},
00026        {HKEY("tel_tel")},
00027        {HKEY("tel_work")},
00028        {HKEY("tel_home")},
00029        {HKEY("tel_cell")},
00030        {HKEY("adr")},
00031        {HKEY("photo")},
00032        {HKEY("version")},
00033        {HKEY("rev")},
00034        {HKEY("label")}
00035 };
00036 
00037 typedef enum _eVC{
00038        VC_n,
00039        VC_fn,
00040        VC_title,
00041        VC_org,
00042        VC_email,
00043        VC_tel,
00044        VC_tel_tel,
00045        VC_tel_work,
00046        VC_tel_home,
00047        VC_tel_cell,
00048        VC_adr,
00049        VC_photo,
00050        VC_version,
00051        VC_rev,
00052        VC_label
00053 } eVC;
00054 
00055 HashList *VCToEnum = NULL;
00056 
00057 /*
00058  * Record compare function for sorting address book indices
00059  */
00060 int abcmp(const void *ab1, const void *ab2) {
00061        return(strcasecmp(
00062               (((const addrbookent *)ab1)->ab_name),
00063               (((const addrbookent *)ab2)->ab_name)
00064        ));
00065 }
00066 
00067 
00068 /*
00069  * Helper function for do_addrbook_view()
00070  * Converts a name into a three-letter tab label
00071  */
00072 void nametab(char *tabbuf, long len, char *name) {
00073        stresc(tabbuf, len, name, 0, 0);
00074        tabbuf[0] = toupper(tabbuf[0]);
00075        tabbuf[1] = tolower(tabbuf[1]);
00076        tabbuf[2] = tolower(tabbuf[2]);
00077        tabbuf[3] = 0;
00078 }
00079 
00080 
00081 /*
00082  * If it's an old "Firstname Lastname" style record, try to convert it.
00083  */
00084 void lastfirst_firstlast(char *namebuf) {
00085        char firstname[SIZ];
00086        char lastname[SIZ];
00087        int i;
00088 
00089        if (namebuf == NULL) return;
00090        if (strchr(namebuf, ';') != NULL) return;
00091 
00092        i = num_tokens(namebuf, ' ');
00093        if (i < 2) return;
00094 
00095        extract_token(lastname, namebuf, i-1, ' ', sizeof lastname);
00096        remove_token(namebuf, i-1, ' ');
00097        strcpy(firstname, namebuf);
00098        sprintf(namebuf, "%s; %s", lastname, firstname);
00099 }
00100 
00101 
00102 
00103 wc_mime_attachment *load_vcard(message_summary *Msg) 
00104 {
00105        HashPos  *it;
00106        StrBuf *FoundCharset = NewStrBuf();
00107        StrBuf *Error;
00108        void *vMime;
00109        const char *Key;
00110        long len;
00111        wc_mime_attachment *Mime;
00112        wc_mime_attachment *VCMime = NULL;
00113 
00114        Msg->MsgBody =  (wc_mime_attachment*) malloc(sizeof(wc_mime_attachment));
00115        memset(Msg->MsgBody, 0, sizeof(wc_mime_attachment));
00116        Msg->MsgBody->msgnum = Msg->msgnum;
00117 
00118        load_message(Msg, FoundCharset, &Error);
00119 
00120        FreeStrBuf(&FoundCharset);
00121        /* look up the vcard... */
00122        it = GetNewHashPos(Msg->AllAttach, 0);
00123        while (GetNextHashPos(Msg->AllAttach, it, &len, &Key, &vMime) && 
00124               (vMime != NULL)) 
00125        {
00126               Mime = (wc_mime_attachment*) vMime;
00127               if ((strcmp(ChrPtr(Mime->ContentType),
00128                         "text/x-vcard") == 0) ||
00129                   (strcmp(ChrPtr(Mime->ContentType),
00130                          "text/vcard") == 0))
00131               {
00132                      VCMime = Mime;
00133                      break;
00134               }
00135        }
00136        DeleteHashPos(&it);
00137        if (VCMime == NULL)
00138               return NULL;
00139 
00140        MimeLoadData(VCMime);
00141        return VCMime;
00142 }
00143 
00144 /*
00145  * fetch the display name off a vCard
00146  */
00147 void fetch_ab_name(message_summary *Msg, char **namebuf) {
00148        long len;
00149        int i;
00150        wc_mime_attachment *VCMime = NULL;
00151 
00152        if (namebuf == NULL) return;
00153 
00154        VCMime = load_vcard(Msg);
00155        if (VCMime == NULL)
00156               return;
00157 
00158        /* Grab the name off the card */
00159        display_vcard(WC->WBuf, VCMime, 0, 0, namebuf, Msg->msgnum);
00160 
00161        if (*namebuf != NULL) {
00162               lastfirst_firstlast(*namebuf);
00163               striplt(*namebuf);
00164               len = strlen(*namebuf);
00165               for (i=0; i<len; ++i) {
00166                      if ((*namebuf)[i] != ';') return;
00167               }
00168               free (*namebuf);
00169               (*namebuf) = strdup(_("(no name)"));
00170        }
00171        else {
00172               (*namebuf) = strdup(_("(no name)"));
00173        }
00174 }
00175 
00176 
00177 
00178 /*
00179  * Turn a vCard "n" (name) field into something displayable.
00180  */
00181 void vcard_n_prettyize(char *name)
00182 {
00183        char *original_name;
00184        int i, j, len;
00185 
00186        original_name = strdup(name);
00187        len = strlen(original_name);
00188        for (i=0; i<5; ++i) {
00189               if (len > 0) {
00190                      if (original_name[len-1] == ' ') {
00191                             original_name[--len] = 0;
00192                      }
00193                      if (original_name[len-1] == ';') {
00194                             original_name[--len] = 0;
00195                      }
00196               }
00197        }
00198        strcpy(name, "");
00199        j=0;
00200        for (i=0; i<len; ++i) {
00201               if (original_name[i] == ';') {
00202                      name[j++] = ',';
00203                      name[j++] = ' ';                   
00204               }
00205               else {
00206                      name[j++] = original_name[i];
00207               }
00208        }
00209        name[j] = '\0';
00210        free(original_name);
00211 }
00212 
00213 
00214 
00215 
00216 /*
00217  * preparse a vcard name
00218  * display_vcard() calls this after parsing the textual vCard into
00219  * our 'struct vCard' data object.
00220  * This gets called instead of display_parsed_vcard() if we are only looking
00221  * to extract the person's name instead of displaying the card.
00222  */
00223 void fetchname_parsed_vcard(struct vCard *v, char **storename) {
00224        char *name;
00225        char *prop;
00226        char buf[SIZ];
00227        int j, n, len;
00228        int is_qp = 0;
00229        int is_b64 = 0;
00230 
00231        *storename = NULL;
00232 
00233        name = vcard_get_prop(v, "n", 1, 0, 0);
00234        if (name != NULL) {
00235               len = strlen(name);
00236               prop = vcard_get_prop(v, "n", 1, 0, 1);
00237               n = num_tokens(prop, ';');
00238 
00239               for (j=0; j<n; ++j) {
00240                      extract_token(buf, prop, j, ';', sizeof buf);
00241                      if (!strcasecmp(buf, "encoding=quoted-printable")) {
00242                             is_qp = 1;
00243                      }
00244                      if (!strcasecmp(buf, "encoding=base64")) {
00245                             is_b64 = 1;
00246                      }
00247               }
00248               if (is_qp) {
00249                      /* %ff can become 6 bytes in utf8  */
00250                      *storename = malloc(len * 2 + 3); 
00251                      j = CtdlDecodeQuotedPrintable(
00252                             *storename, name,
00253                             len);
00254                      (*storename)[j] = 0;
00255               }
00256               else if (is_b64) {
00257                      /* ff will become one byte.. */
00258                      *storename = malloc(len + 50);
00259                      CtdlDecodeBase64(
00260                             *storename, name,
00261                             len);
00262               }
00263               else {
00264                      size_t len;
00265 
00266                      len = strlen (name);
00267                      
00268                      *storename = malloc(len + 3); /* \0 + eventualy missing ', '*/
00269                      memcpy(*storename, name, len + 1);
00270               }
00271               /* vcard_n_prettyize(storename); */
00272        }
00273 
00274 }
00275 
00276 
00277 
00278 /*
00279  * html print a vcard
00280  * display_vcard() calls this after parsing the textual vCard into
00281  * our 'struct vCard' data object.
00282  *
00283  * Set 'full' to nonzero to display the full card, otherwise it will only
00284  * show a summary line.
00285  *
00286  * This code is a bit ugly, so perhaps an explanation is due: we do this
00287  * in two passes through the vCard fields.  On the first pass, we process
00288  * fields we understand, and then render them in a pretty fashion at the
00289  * end.  Then we make a second pass, outputting all the fields we don't
00290  * understand in a simple two-column name/value format.
00291  * v          the vCard to display
00292  * full              display all items of the vcard?
00293  * msgnum     Citadel message pointer
00294  */
00295 void display_parsed_vcard(StrBuf *Target, struct vCard *v, int full, wc_mime_attachment *Mime)
00296 {
00297        int i, j;
00298        char buf[SIZ];
00299        char *name;
00300        int is_qp = 0;
00301        int is_b64 = 0;
00302        char *thisname, *thisvalue;
00303        char firsttoken[SIZ];
00304        int pass;
00305 
00306        char fullname[SIZ];
00307        char title[SIZ];
00308        char org[SIZ];
00309        char phone[SIZ];
00310        char mailto[SIZ];
00311 
00312        strcpy(fullname, "");
00313        strcpy(phone, "");
00314        strcpy(mailto, "");
00315        strcpy(title, "");
00316        strcpy(org, "");
00317 
00318        if (!full) {
00319               StrBufAppendPrintf(Target, "<td>");
00320               name = vcard_get_prop(v, "fn", 1, 0, 0);
00321               if (name != NULL) {
00322                      StrEscAppend(Target, NULL, name, 0, 0);
00323               }
00324               else if (name = vcard_get_prop(v, "n", 1, 0, 0), name != NULL) {
00325                      strcpy(fullname, name);
00326                      vcard_n_prettyize(fullname);
00327                      StrEscAppend(Target, NULL, fullname, 0, 0);
00328               }
00329               else {
00330                      StrBufAppendPrintf(Target, "&nbsp;");
00331               }
00332               StrBufAppendPrintf(Target, "</td>");
00333               return;
00334        }
00335 
00336        StrBufAppendPrintf(Target, "<div align=\"center\">"
00337               "<table bgcolor=\"#aaaaaa\" width=\"50%%\">");
00338        for (pass=1; pass<=2; ++pass) {
00339 
00340               if (v->numprops) for (i=0; i<(v->numprops); ++i) {
00341                      int len;
00342                      thisname = strdup(v->prop[i].name);
00343                      extract_token(firsttoken, thisname, 0, ';', sizeof firsttoken);
00344        
00345                      for (j=0; j<num_tokens(thisname, ';'); ++j) {
00346                             extract_token(buf, thisname, j, ';', sizeof buf);
00347                             if (!strcasecmp(buf, "encoding=quoted-printable")) {
00348                                    is_qp = 1;
00349                                    remove_token(thisname, j, ';');
00350                             }
00351                             if (!strcasecmp(buf, "encoding=base64")) {
00352                                    is_b64 = 1;
00353                                    remove_token(thisname, j, ';');
00354                             }
00355                      }
00356                      
00357                      len = strlen(v->prop[i].value);
00358                      /* if we have some untagged QP, detect it here. */
00359                      if (!is_qp && (strstr(v->prop[i].value, "=?")!=NULL))
00360                             utf8ify_rfc822_string(&v->prop[i].value);
00361 
00362                      if (is_qp) {
00363                             // %ff can become 6 bytes in utf8 
00364                             thisvalue = malloc(len * 2 + 3); 
00365                             j = CtdlDecodeQuotedPrintable(
00366                                    thisvalue, v->prop[i].value,
00367                                    len);
00368                             thisvalue[j] = 0;
00369                      }
00370                      else if (is_b64) {
00371                             // ff will become one byte..
00372                             thisvalue = malloc(len + 50);
00373                             CtdlDecodeBase64(
00374                                    thisvalue, v->prop[i].value,
00375                                    strlen(v->prop[i].value) );
00376                      }
00377                      else {
00378                             thisvalue = strdup(v->prop[i].value);
00379                      }
00380        
00381                      /* Various fields we may encounter ***/
00382        
00383                      /* N is name, but only if there's no FN already there */
00384                      if (!strcasecmp(firsttoken, "n")) {
00385                             if (IsEmptyStr(fullname)) {
00386                                    strcpy(fullname, thisvalue);
00387                                    vcard_n_prettyize(fullname);
00388                             }
00389                      }
00390        
00391                      /* FN (full name) is a true 'display name' field */
00392                      else if (!strcasecmp(firsttoken, "fn")) {
00393                             strcpy(fullname, thisvalue);
00394                      }
00395 
00396                      /* title */
00397                      else if (!strcasecmp(firsttoken, "title")) {
00398                             strcpy(title, thisvalue);
00399                      }
00400        
00401                      /* organization */
00402                      else if (!strcasecmp(firsttoken, "org")) {
00403                             strcpy(org, thisvalue);
00404                      }
00405        
00406                      else if (!strcasecmp(firsttoken, "email")) {
00407                             size_t len;
00408                             if (!IsEmptyStr(mailto)) strcat(mailto, "<br>");
00409                             strcat(mailto,
00410                                    "<a href=\"display_enter"
00411                                    "?force_room=_MAIL_?recp=");
00412 
00413                             len = strlen(mailto);
00414                             urlesc(&mailto[len], SIZ - len, "\"");
00415                             len = strlen(mailto);
00416                             urlesc(&mailto[len], SIZ - len,  fullname);
00417                             len = strlen(mailto);
00418                             urlesc(&mailto[len], SIZ - len, "\" <");
00419                             len = strlen(mailto);
00420                             urlesc(&mailto[len], SIZ - len, thisvalue);
00421                             len = strlen(mailto);
00422                             urlesc(&mailto[len], SIZ - len, ">");
00423 
00424                             strcat(mailto, "\">");
00425                             len = strlen(mailto);
00426                             stresc(mailto+len, SIZ - len, thisvalue, 1, 1);
00427                             strcat(mailto, "</A>");
00428                      }
00429                      else if (!strcasecmp(firsttoken, "tel")) {
00430                             if (!IsEmptyStr(phone)) strcat(phone, "<br>");
00431                             strcat(phone, thisvalue);
00432                             for (j=0; j<num_tokens(thisname, ';'); ++j) {
00433                                    extract_token(buf, thisname, j, ';', sizeof buf);
00434                                    if (!strcasecmp(buf, "tel"))
00435                                           strcat(phone, "");
00436                                    else if (!strcasecmp(buf, "work"))
00437                                           strcat(phone, _(" (work)"));
00438                                    else if (!strcasecmp(buf, "home"))
00439                                           strcat(phone, _(" (home)"));
00440                                    else if (!strcasecmp(buf, "cell"))
00441                                           strcat(phone, _(" (cell)"));
00442                                    else {
00443                                           strcat(phone, " (");
00444                                           strcat(phone, buf);
00445                                           strcat(phone, ")");
00446                                    }
00447                             }
00448                      }
00449                      else if (!strcasecmp(firsttoken, "adr")) {
00450                             if (pass == 2) {
00451                                    StrBufAppendPrintf(Target, "<tr><td>");
00452                                    StrBufAppendPrintf(Target, _("Address:"));
00453                                    StrBufAppendPrintf(Target, "</td><td>");
00454                                    for (j=0; j<num_tokens(thisvalue, ';'); ++j) {
00455                                           extract_token(buf, thisvalue, j, ';', sizeof buf);
00456                                           if (!IsEmptyStr(buf)) {
00457                                                  StrEscAppend(Target, NULL, buf, 0, 0);
00458                                                  if (j<3) StrBufAppendPrintf(Target, "<br>");
00459                                                  else StrBufAppendPrintf(Target, " ");
00460                                           }
00461                                    }
00462                                    StrBufAppendPrintf(Target, "</td></tr>\n");
00463                             }
00464                      }
00465                      /* else if (!strcasecmp(firsttoken, "photo") && full && pass == 2) { 
00466                             // Only output on second pass
00467                             StrBufAppendPrintf(Target, "<tr><td>");
00468                             StrBufAppendPrintf(Target, _("Photo:"));
00469                             StrBufAppendPrintf(Target, "</td><td>");
00470                             StrBufAppendPrintf(Target, "<img src=\"/vcardphoto/%ld/\" alt=\"Contact photo\"/>",msgnum);
00471                             StrBufAppendPrintf(Target, "</td></tr>\n");
00472                      } */
00473                      else if (!strcasecmp(firsttoken, "version")) {
00474                             /* ignore */
00475                      }
00476                      else if (!strcasecmp(firsttoken, "rev")) {
00477                             /* ignore */
00478                      }
00479                      else if (!strcasecmp(firsttoken, "label")) {
00480                             /* ignore */
00481                      }
00482                      else {
00483 
00484                             /*** Don't show extra fields.  They're ugly.
00485                             if (pass == 2) {
00486                                    StrBufAppendPrintf(Target, "<TR><TD>");
00487                                    StrEscAppend(Target, NULL, thisname, 0, 0);
00488                                    StrBufAppendPrintf(Target, "</TD><TD>");
00489                                    StrEscAppend(Target, NULL, thisvalue, 0, 0);
00490                                    StrBufAppendPrintf(Target, "</TD></TR>\n");
00491                             }
00492                             ***/
00493                      }
00494        
00495                      free(thisname);
00496                      free(thisvalue);
00497               }
00498        
00499               if (pass == 1) {
00500                      StrBufAppendPrintf(Target, "<tr bgcolor=\"#aaaaaa\">"
00501       "<td colspan=2 bgcolor=\"#ffffff\">"
00502       "<img align=\"center\" src=\"static/webcit_icons/essen/32x32/contact.png\">"
00503       "<font size=\"+1\"><b>");
00504                      StrEscAppend(Target, NULL, fullname, 0, 0);
00505                      StrBufAppendPrintf(Target, "</b></font>");
00506                      if (!IsEmptyStr(title)) {
00507                             StrBufAppendPrintf(Target, "<div align=\"right>\"");
00508                             StrEscAppend(Target, NULL, title, 0, 0);
00509                             StrBufAppendPrintf(Target, "</div>");
00510                      }
00511                      if (!IsEmptyStr(org)) {
00512                             StrBufAppendPrintf(Target, "<div align=\"right\">");
00513                             StrEscAppend(Target, NULL, org, 0, 0);
00514                             StrBufAppendPrintf(Target, "</div>");
00515                      }
00516                      StrBufAppendPrintf(Target, "</td></tr>\n");
00517               
00518                      if (!IsEmptyStr(phone)) {
00519                             StrBufAppendPrintf(Target, "<tr><td>");
00520                             StrBufAppendPrintf(Target, _("Telephone:"));
00521                             StrBufAppendPrintf(Target, "</td><td>%s</td></tr>\n", phone);
00522                      }
00523                      if (!IsEmptyStr(mailto)) {
00524                             StrBufAppendPrintf(Target, "<tr><td>");
00525                             StrBufAppendPrintf(Target, _("E-mail:"));
00526                             StrBufAppendPrintf(Target, "</td><td>%s</td></tr>\n", mailto);
00527                      }
00528               }
00529 
00530        }
00531 
00532        StrBufAppendPrintf(Target, "</table></div>\n");
00533 }
00534 
00535 /*
00536  * html print a vcard
00537  * display_vcard() calls this after parsing the textual vCard into
00538  * our 'struct vCard' data object.
00539  *
00540  * Set 'full' to nonzero to display the full card, otherwise it will only
00541  * show a summary line.
00542  *
00543  * This code is a bit ugly, so perhaps an explanation is due: we do this
00544  * in two passes through the vCard fields.  On the first pass, we process
00545  * fields we understand, and then render them in a pretty fashion at the
00546  * end.  Then we make a second pass, outputting all the fields we don't
00547  * understand in a simple two-column name/value format.
00548  * v          the vCard to display
00549  * full              display all items of the vcard?
00550  * msgnum     Citadel message pointer
00551  */
00552 void parse_vcard(StrBuf *Target, struct vCard *v, HashList *VC, int full, wc_mime_attachment *Mime)
00553 {
00554        StrBuf *Val = NULL;
00555        StrBuf *Swap = NULL;
00556        int i, j;
00557        char buf[SIZ];
00558        int is_qp = 0;
00559        int is_b64 = 0;
00560        StrBuf *thisname = NULL;
00561        char firsttoken[SIZ];
00562        void *V;
00563 
00564        Swap = NewStrBuf ();
00565        thisname = NewStrBuf();
00566        for (i=0; i<(v->numprops); ++i) {
00567               is_qp = 0;
00568               is_b64 = 0;
00569               StrBufPlain(thisname, v->prop[i].name, -1);
00570               StrBufLowerCase(thisname);
00571               
00572               /*len = */extract_token(firsttoken, ChrPtr(thisname), 0, ';', sizeof firsttoken);
00573               
00574               for (j=0; j<num_tokens(ChrPtr(thisname), ';'); ++j) {
00575                      extract_token(buf, ChrPtr(thisname), j, ';', sizeof buf);
00576                      if (!strcasecmp(buf, "encoding=quoted-printable")) {
00577                             is_qp = 1;
00578 /*                          remove_token(thisname, j, ';');*/
00579                      }
00580                      if (!strcasecmp(buf, "encoding=base64")) {
00581                             is_b64 = 1;
00582 /*                          remove_token(thisname, j, ';');*/
00583                      }
00584               }
00585               
00586               /* copy over the payload into a StrBuf */
00587               Val = NewStrBufPlain(v->prop[i].value, -1);
00588                      
00589               /* if we have some untagged QP, detect it here. */
00590               if (is_qp || (strstr(v->prop[i].value, "=?")!=NULL)){
00591                      StrBuf *b;
00592                      StrBuf_RFC822_to_Utf8(Swap, Val, NULL, NULL); /* default charset, current charset */
00593                      b = Val;
00594                      Val = Swap; 
00595                      Swap = b;
00596                      FlushStrBuf(Swap);
00597               }
00598               else if (is_b64) {
00599                      StrBufDecodeBase64(Val);
00600 
00601               }
00602               syslog(1, "%s [%s][%s]",
00603                      firsttoken,
00604                      ChrPtr(Val),
00605                      v->prop[i].value);
00606               if (GetHash(VCToEnum, firsttoken, strlen(firsttoken), &V))
00607               {
00608                      eVC evc = (eVC) V;
00609                      Put(VC, IKEY(evc), Val, HFreeStrBuf);
00610                      syslog(1, "[%ul]\n", evc);
00611                      Val = NULL;
00612               }
00613               else
00614                      syslog(1, "[]\n");
00615 /*
00616 TODO: check for layer II
00617               else 
00618               {
00619                      long max = num_tokens(thisname, ';');
00620                      firsttoken[len] = '_';
00621 
00622                      for (j = 0; j < max; j++) {
00623 //                   firsttoken[len]
00624 
00625                             extract_token(buf, thisname, j, ';', sizeof (buf));
00626                                    if (!strcasecmp(buf, "tel"))
00627                                           strcat(phone, "");
00628                                    else if (!strcasecmp(buf, "work"))
00629                                           strcat(phone, _(" (work)"));
00630                                    else if (!strcasecmp(buf, "home"))
00631                                           strcat(phone, _(" (home)"));
00632                                    else if (!strcasecmp(buf, "cell"))
00633                                           strcat(phone, _(" (cell)"));
00634                                    else {
00635                                           strcat(phone, " (");
00636                                           strcat(phone, buf);
00637                                           strcat(phone, ")");
00638                                    }
00639                             }
00640                      }
00641 
00642               }
00643 */
00644        
00645               FreeStrBuf(&Val);
00646               free(thisname);
00647               thisname = NULL;
00648        }
00649 
00650 }
00651 
00652 void tmplput_VCARD_ITEM(StrBuf *Target, WCTemplputParams *TP)
00653 {
00654        HashList *VC = CTX;
00655        eVC evc;
00656        void *vStr;
00657 
00658        evc = GetTemplateTokenNumber(Target, TP, 0, -1);
00659        if (evc != -1)
00660        {
00661               if (GetHash(VC, IKEY(evc), &vStr))
00662               {
00663                      StrBufAppendTemplate(Target, TP,
00664                                         (StrBuf*) vStr,
00665                                         1);
00666               }
00667        }
00668        
00669 }
00670 
00671 void new_vcard (StrBuf *Target, struct vCard *v, int full, wc_mime_attachment *Mime)
00672 {
00673        HashList *VC;
00674        WCTemplputParams SubTP;
00675 
00676         memset(&SubTP, 0, sizeof(WCTemplputParams));    
00677 
00678 
00679        VC = NewHash(0, Flathash);
00680        parse_vcard(Target, v, VC, full, Mime);
00681 
00682        SubTP.Filter.ContextType = CTX_VCARD;
00683        SubTP.Context = VC;
00684 
00685        DoTemplate(HKEY("test_vcard"), Target, &SubTP);
00686        DeleteHash(&VC);
00687 }
00688 
00689 
00690 
00691 /*
00692  * Display a textual vCard
00693  * (Converts to a vCard object and then calls the actual display function)
00694  * Set 'full' to nonzero to display the whole card instead of a one-liner.
00695  * Or, if "storename" is non-NULL, just store the person's name in that
00696  * buffer instead of displaying the card at all.
00697  *
00698  * vcard_source      the buffer containing the vcard text
00699  * alpha      Display only if name begins with this letter of the alphabet
00700  * full              Display the full vCard (otherwise just the display name)
00701  * storename  If not NULL, also store the display name here
00702  * msgnum     Citadel message pointer
00703  */
00704 void display_vcard(StrBuf *Target, 
00705                  wc_mime_attachment *Mime, 
00706                  char alpha, 
00707                  int full, 
00708                  char **storename, 
00709                  long msgnum) 
00710 {
00711        struct vCard *v;
00712        char *name;
00713        StrBuf *Buf;
00714        StrBuf *Buf2;
00715        char this_alpha = 0;
00716 
00717        v = VCardLoad(Mime->Data);
00718 
00719        if (v == NULL) return;
00720 
00721        name = vcard_get_prop(v, "n", 1, 0, 0);
00722        if (name != NULL) {
00723               Buf = NewStrBufPlain(name, -1);
00724               Buf2 = NewStrBufPlain(NULL, StrLength(Buf));
00725               StrBuf_RFC822_to_Utf8(Buf2, Buf, WC->DefaultCharset, NULL);
00726               this_alpha = ChrPtr(Buf)[0];
00727               FreeStrBuf(&Buf);
00728               FreeStrBuf(&Buf2);
00729        }
00730 
00731        if (storename != NULL) {
00732               fetchname_parsed_vcard(v, storename);
00733        }
00734        else if ((alpha == 0) || 
00735                ((isalpha(alpha)) && (tolower(alpha) == tolower(this_alpha))) || 
00736                ((!isalpha(alpha)) && (!isalpha(this_alpha)))
00737               ) 
00738        {
00739 #ifdef XXX_XXX
00740               new_vcard (Target, v, full, Mime);
00741 #else
00742               display_parsed_vcard(Target, v, full, Mime);
00743 #endif        
00744        }
00745 
00746        vcard_free(v);
00747 }
00748 
00749 
00750 
00751 /*
00752  * Render the address book using info we gathered during the scan
00753  *
00754  * addrbook   the addressbook to render
00755  * num_ab     the number of the addressbook
00756  */
00757 void do_addrbook_view(addrbookent *addrbook, int num_ab) {
00758        int i = 0;
00759        int displayed = 0;
00760        int bg = 0;
00761        static int NAMESPERPAGE = 60;
00762        int num_pages = 0;
00763        int tabfirst = 0;
00764        char tabfirst_label[64];
00765        int tablast = 0;
00766        char tablast_label[64];
00767        char this_tablabel[64];
00768        int page = 0;
00769        char **tablabels;
00770 
00771        if (num_ab == 0) {
00772               wc_printf("<br><br><br><div align=\"center\"><i>");
00773               wc_printf(_("This address book is empty."));
00774               wc_printf("</i></div>\n");
00775               return;
00776        }
00777 
00778        if (num_ab > 1) {
00779               qsort(addrbook, num_ab, sizeof(addrbookent), abcmp);
00780        }
00781 
00782        num_pages = (num_ab / NAMESPERPAGE) + 1;
00783 
00784        tablabels = malloc(num_pages * sizeof (char *));
00785        if (tablabels == NULL) {
00786               wc_printf("<br><br><br><div align=\"center\"><i>");
00787               wc_printf(_("An internal error has occurred."));
00788               wc_printf("</i></div>\n");
00789               return;
00790        }
00791 
00792        for (i=0; i<num_pages; ++i) {
00793               tabfirst = i * NAMESPERPAGE;
00794               tablast = tabfirst + NAMESPERPAGE - 1;
00795               if (tablast > (num_ab - 1)) tablast = (num_ab - 1);
00796               nametab(tabfirst_label, 64, addrbook[tabfirst].ab_name);
00797               nametab(tablast_label, 64, addrbook[tablast].ab_name);
00798               sprintf(this_tablabel, "%s&nbsp;-&nbsp;%s", tabfirst_label, tablast_label);
00799               tablabels[i] = strdup(this_tablabel);
00800        }
00801 
00802        tabbed_dialog(num_pages, tablabels);
00803        page = (-1);
00804 
00805        for (i=0; i<num_ab; ++i) {
00806 
00807               if ((i / NAMESPERPAGE) != page) {  /* New tab */
00808                      page = (i / NAMESPERPAGE);
00809                      if (page > 0) {
00810                             wc_printf("</tr></table>\n");
00811                             end_tab(page-1, num_pages);
00812                      }
00813                      begin_tab(page, num_pages);
00814                      wc_printf("<table border=\"0\" cellspacing=\"0\" cellpadding=\"3\" width=\"100%%\">\n");
00815                      displayed = 0;
00816               }
00817 
00818               if ((displayed % 4) == 0) {
00819                      if (displayed > 0) {
00820                             wc_printf("</tr>\n");
00821                      }
00822                      bg = 1 - bg;
00823                      wc_printf("<tr bgcolor=\"#%s\">",
00824                             (bg ? "dddddd" : "ffffff")
00825                      );
00826               }
00827        
00828               wc_printf("<td>");
00829 
00830               wc_printf("<a href=\"readfwd?startmsg=%ld?is_singlecard=1",
00831                      addrbook[i].ab_msgnum);
00832               wc_printf("?maxmsgs=1?is_summary=0?alpha=%s\">", bstr("alpha"));
00833               vcard_n_prettyize(addrbook[i].ab_name);
00834               escputs(addrbook[i].ab_name);
00835               wc_printf("</a></td>\n");
00836               ++displayed;
00837        }
00838 
00839        /* Placeholders for empty columns at end */
00840        if ((num_ab % 4) != 0) {
00841               for (i=0; i<(4-(num_ab % 4)); ++i) {
00842                      wc_printf("<td>&nbsp;</td>");
00843               }
00844        }
00845 
00846        wc_printf("</tr></table>\n");
00847        end_tab((num_pages-1), num_pages);
00848 
00849        begin_tab(num_pages, num_pages);
00850        /* FIXME there ought to be something here */
00851        end_tab(num_pages, num_pages);
00852 
00853        for (i=0; i<num_pages; ++i) {
00854               free(tablabels[i]);
00855        }
00856        free(tablabels);
00857 }
00858 
00859 
00860 
00861 
00862 /*
00863  * Edit the vCard component of a MIME message.  
00864  * Supply the message number
00865  * and MIME part number to fetch.  Or, specify -1 for the message number
00866  * to start with a blank card.
00867  */
00868 void do_edit_vcard(long msgnum, char *partnum, 
00869                  message_summary *VCMsg,
00870                  wc_mime_attachment *VCAtt,
00871                  const char *return_to, 
00872                  const char *force_room) {
00873        message_summary *Msg = NULL;
00874        wc_mime_attachment *VCMime = NULL;
00875        struct vCard *v;
00876        int i;
00877        char *key, *value;
00878        char whatuser[256];
00879 
00880        char lastname[256];
00881        char firstname[256];
00882        char middlename[256];
00883        char prefix[256];
00884        char suffix[256];
00885        char pobox[256];
00886        char extadr[256];
00887        char street[256];
00888        char city[256];
00889        char state[256];
00890        char zipcode[256];
00891        char country[256];
00892        char hometel[256];
00893        char worktel[256];
00894        char faxtel[256];
00895        char mobiletel[256];
00896        char primary_inetemail[256];
00897        char other_inetemail[SIZ];
00898        char extrafields[SIZ];
00899        char fullname[256];
00900        char title[256];
00901        char org[256];
00902 
00903        lastname[0] = 0;
00904        firstname[0] = 0;
00905        middlename[0] = 0;
00906        prefix[0] = 0;
00907        suffix[0] = 0;
00908        pobox[0] = 0;
00909        extadr[0] = 0;
00910        street[0] = 0;
00911        city[0] = 0;
00912        state[0] = 0;
00913        zipcode[0] = 0;
00914        country[0] = 0;
00915        hometel[0] = 0;
00916        worktel[0] = 0;
00917        faxtel[0] = 0;
00918        mobiletel[0] = 0;
00919        primary_inetemail[0] = 0;
00920        other_inetemail[0] = 0;
00921        title[0] = 0;
00922        org[0] = 0;
00923        extrafields[0] = 0;
00924        fullname[0] = 0;
00925 
00926        safestrncpy(whatuser, "", sizeof whatuser);
00927 
00928        if ((msgnum >= 0) || 
00929            ((VCMsg != NULL) && (VCAtt != NULL)))
00930        {
00931               if ((VCMsg == NULL) && (VCAtt == NULL)) {
00932 
00933                      Msg = (message_summary *) malloc(sizeof(message_summary));
00934                      memset(Msg, 0, sizeof(message_summary));
00935                      Msg->msgnum = msgnum;
00936                      VCMime = load_vcard(Msg);
00937                      if (VCMime == NULL) {
00938                             convenience_page("770000", _("Error"), "");
00939                             DestroyMessageSummary(Msg);
00940                             return;
00941                      }
00942               
00943                      v = VCardLoad(VCMime->Data);
00944               }
00945               else {
00946                      v = VCardLoad(VCAtt->Data);
00947               }
00948        
00949               /* Populate the variables for our form */
00950               i = 0;
00951               while (key = vcard_get_prop(v, "", 0, i, 1), key != NULL) {
00952                      char prp[256];       /* property name */
00953                      char prm[256];       /* parameters */
00954 
00955                      value = vcard_get_prop(v, "", 0, i++, 0);
00956 
00957 
00958                      extract_token(prp, key, 0, ';', sizeof prp);
00959                      safestrncpy(prm, key, sizeof prm);
00960                      remove_token(prm, 0, ';');
00961 
00962                      if (!strcasecmp(prp, "n")) {
00963                             extract_token(lastname, value, 0, ';', sizeof lastname);
00964                             extract_token(firstname, value, 1, ';', sizeof firstname);
00965                             extract_token(middlename, value, 2, ';', sizeof middlename);
00966                             extract_token(prefix, value, 3, ';', sizeof prefix);
00967                             extract_token(suffix, value, 4, ';', sizeof suffix);
00968                      }
00969 
00970                      else if (!strcasecmp(prp, "fn")) {
00971                             safestrncpy(fullname, value, sizeof fullname);
00972                      }
00973 
00974                      else if (!strcasecmp(prp, "title")) {
00975                             safestrncpy(title, value, sizeof title);
00976                      }
00977        
00978                      else if (!strcasecmp(prp, "org")) {
00979                             safestrncpy(org, value, sizeof org);
00980                      }
00981        
00982                      else if (!strcasecmp(prp, "adr")) {
00983                             extract_token(pobox, value, 0, ';', sizeof pobox);
00984                             extract_token(extadr, value, 1, ';', sizeof extadr);
00985                             extract_token(street, value, 2, ';', sizeof street);
00986                             extract_token(city, value, 3, ';', sizeof city);
00987                             extract_token(state, value, 4, ';', sizeof state);
00988                             extract_token(zipcode, value, 5, ';', sizeof zipcode);
00989                             extract_token(country, value, 6, ';', sizeof country);
00990                      }
00991 
00992                      else if (!strcasecmp(prp, "tel")) {
00993 
00994                             if (bmstrcasestr(prm, "home")) {
00995                                    extract_token(hometel, value, 0, ';', sizeof hometel);
00996                             }
00997                             else if (bmstrcasestr(prm, "work")) {
00998                                    extract_token(worktel, value, 0, ';', sizeof worktel);
00999                             }
01000                             else if (bmstrcasestr(prm, "fax")) {
01001                                    extract_token(faxtel, value, 0, ';', sizeof faxtel);
01002                             }
01003                             else if (bmstrcasestr(prm, "cell")) {
01004                                    extract_token(mobiletel, value, 0, ';', sizeof mobiletel);
01005                             }
01006                             else { /* Missing or unknown type; put it in the home phone */
01007                                    extract_token(hometel, value, 0, ';', sizeof hometel);
01008                             }
01009                      }
01010        
01011                      else if ( (!strcasecmp(prp, "email")) && (bmstrcasestr(prm, "internet")) ) {
01012                             if (primary_inetemail[0] == 0) {
01013                                    safestrncpy(primary_inetemail, value, sizeof primary_inetemail);
01014                             }
01015                             else {
01016                                    if (other_inetemail[0] != 0) {
01017                                           strcat(other_inetemail, "\n");
01018                                    }
01019                                    strcat(other_inetemail, value);
01020                             }
01021                      }
01022 
01023                      /* Unrecognized properties are preserved here so we don't discard them
01024                       * just because the vCard was edited with WebCit.
01025                       */
01026                      else {
01027                             strcat(extrafields, key);
01028                             strcat(extrafields, ":");
01029                             strcat(extrafields, value);
01030                             strcat(extrafields, "\n");
01031                      }
01032        
01033               }
01034        
01035               vcard_free(v);
01036        }
01037 
01038        /* Display the form */
01039        output_headers(1, 1, 1, 0, 0, 0);
01040 
01041        do_template("box_begin_1");
01042        StrBufAppendBufPlain(WC->WBuf, _("Edit contact information"), -1, 0);
01043        do_template("box_begin_2");
01044 
01045        wc_printf("<form method=\"POST\" action=\"submit_vcard\">\n");
01046        wc_printf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
01047 
01048        if (force_room != NULL) {
01049               wc_printf("<input type=\"hidden\" name=\"force_room\" value=\"");
01050               escputs(force_room);
01051               wc_printf("\">\n");
01052        }
01053 
01054        wc_printf("<table class=\"vcard_edit_background\"><tr><td>\n");
01055 
01056        wc_printf("<table border=\"0\"><tr>"
01057               "<td>%s</td>"
01058               "<td>%s</td>"
01059               "<td>%s</td>"
01060               "<td>%s</td>"
01061               "<td>%s</td></tr>\n",
01062               _("Prefix"), _("First Name"), _("Middle Name"), _("Last Name"), _("Suffix")
01063        );
01064        wc_printf("<tr><td><input type=\"text\" name=\"prefix\" "
01065               "value=\"%s\" maxlength=\"5\" size=\"5\"></td>",
01066               prefix);
01067        wc_printf("<td><input type=\"text\" name=\"firstname\" "
01068               "value=\"%s\" maxlength=\"29\"></td>",
01069               firstname);
01070        wc_printf("<td><input type=\"text\" name=\"middlename\" "
01071               "value=\"%s\" maxlength=\"29\"></td>",
01072               middlename);
01073        wc_printf("<td><input type=\"text\" name=\"lastname\" "
01074               "value=\"%s\" maxlength=\"29\"></td>",
01075               lastname);
01076        wc_printf("<td><input type=\"text\" name=\"suffix\" "
01077               "value=\"%s\" maxlength=\"10\" size=\"10\"></td></tr></table>\n",
01078               suffix);
01079 
01080        wc_printf("<table  class=\"vcard_edit_background_alt\">");
01081        wc_printf("<tr><td>");
01082 
01083        wc_printf(_("Display name:"));
01084        wc_printf("<br>"
01085               "<input type=\"text\" name=\"fullname\" "
01086               "value=\"%s\" maxlength=\"40\"><br><br>\n",
01087               fullname
01088        );
01089 
01090        wc_printf(_("Title:"));
01091        wc_printf("<br>"
01092               "<input type=\"text\" name=\"title\" "
01093               "value=\"%s\" maxlength=\"40\"><br><br>\n",
01094               title
01095        );
01096 
01097        wc_printf(_("Organization:"));
01098        wc_printf("<br>"
01099               "<input type=\"text\" name=\"org\" "
01100               "value=\"%s\" maxlength=\"40\"><br><br>\n",
01101               org
01102        );
01103 
01104        wc_printf("</td><td>");
01105 
01106        wc_printf("<table border=\"0\">");
01107        wc_printf("<tr><td>");
01108        wc_printf(_("PO box:"));
01109        wc_printf("</td><td>"
01110               "<input type=\"text\" name=\"pobox\" "
01111               "value=\"%s\" maxlength=\"29\"></td></tr>\n",
01112               pobox);
01113        wc_printf("<tr><td>");
01114        wc_printf(_("Address:"));
01115        wc_printf("</td><td>"
01116               "<input type=\"text\" name=\"extadr\" "
01117               "value=\"%s\" maxlength=\"29\"></td></tr>\n",
01118               extadr);
01119        wc_printf("<tr><td> </td><td>"
01120               "<input type=\"text\" name=\"street\" "
01121               "value=\"%s\" maxlength=\"29\"></td></tr>\n",
01122               street);
01123        wc_printf("<tr><td>");
01124        wc_printf(_("City:"));
01125        wc_printf("</td><td>"
01126               "<input type=\"text\" name=\"city\" "
01127               "value=\"%s\" maxlength=\"29\"></td></tr>\n",
01128               city);
01129        wc_printf("<tr><td>");
01130        wc_printf(_("State:"));
01131        wc_printf("</td><td>"
01132               "<input type=\"text\" name=\"state\" "
01133               "value=\"%s\" maxlength=\"29\"></td></tr>\n",
01134               state);
01135        wc_printf("<tr><td>");
01136        wc_printf(_("ZIP code:"));
01137        wc_printf("</td><td>"
01138               "<input type=\"text\" name=\"zipcode\" "
01139               "value=\"%s\" maxlength=\"10\"></td></tr>\n",
01140               zipcode);
01141        wc_printf("<tr><td>");
01142        wc_printf(_("Country:"));
01143        wc_printf("</td><td>"
01144               "<input type=\"text\" name=\"country\" "
01145               "value=\"%s\" maxlength=\"29\" width=\"5\"></td></tr>\n",
01146               country);
01147        wc_printf("</table>\n");
01148 
01149        wc_printf("</table>\n");
01150 
01151        wc_printf("<table border=0><tr><td>");
01152        wc_printf(_("Home telephone:"));
01153        wc_printf("</td>"
01154               "<td><input type=\"text\" name=\"hometel\" "
01155               "value=\"%s\" maxlength=\"29\"></td>\n",
01156               hometel);
01157        wc_printf("<td>");
01158        wc_printf(_("Work telephone:"));
01159        wc_printf("</td>"
01160               "<td><input type=\"text\" name=\"worktel\" "
01161               "value=\"%s\" maxlength=\"29\"></td></tr>\n",
01162               worktel);
01163        wc_printf("<tr><td>");
01164        wc_printf(_("Mobile telephone:"));
01165        wc_printf("</td>"
01166               "<td><input type=\"text\" name=\"mobiletel\" "
01167               "value=\"%s\" maxlength=\"29\"></td>\n",
01168               mobiletel);
01169        wc_printf("<td>");
01170        wc_printf(_("Fax number:"));
01171        wc_printf("</td>"
01172               "<td><input type=\"text\" name=\"faxtel\" "
01173               "value=\"%s\" maxlength=\"29\"></td></tr></table>\n",
01174               faxtel);
01175 
01176        wc_printf("<table class=\"vcard_edit_background_alt\">");
01177        wc_printf("<tr><td>");
01178 
01179        wc_printf("<table border=0><TR>"
01180               "<td valign=top>");
01181        wc_printf(_("Primary Internet e-mail address"));
01182        wc_printf("<br>"
01183               "<input type=\"text\" name=\"primary_inetemail\" "
01184               "size=40 maxlength=60 value=\"");
01185        escputs(primary_inetemail);
01186        wc_printf("\"><br>"
01187               "</td><td valign=top>");
01188        wc_printf(_("Internet e-mail aliases"));
01189        wc_printf("<br>"
01190               "<textarea name=\"other_inetemail\" rows=5 cols=40 width=40>");
01191        escputs(other_inetemail);
01192        wc_printf("</textarea></td></tr></table>\n");
01193 
01194        wc_printf("</td></tr></table>\n");
01195 
01196        wc_printf("<input type=\"hidden\" name=\"extrafields\" value=\"");
01197        escputs(extrafields);
01198        wc_printf("\">\n");
01199 
01200        wc_printf("<input type=\"hidden\" name=\"return_to\" value=\"");
01201        escputs(return_to);
01202        wc_printf("\">\n");
01203 
01204        wc_printf("<div class=\"buttons\">\n"
01205               "<input type=\"submit\" name=\"ok_button\" value=\"%s\">"
01206               "&nbsp;"
01207               "<input type=\"submit\" name=\"cancel_button\" value=\"%s\">"
01208               "</div></form>\n",
01209               _("Save changes"),
01210               _("Cancel")
01211        );
01212        
01213        wc_printf("</td></tr></table>\n");
01214        do_template("box_end");
01215        wDumpContent(1);
01216        if (Msg != NULL) {
01217               DestroyMessageSummary(Msg);
01218        }
01219 }
01220 
01221 
01222 /*
01223  *  commit the edits to the citadel server
01224  */
01225 void edit_vcard(void) {
01226        long msgnum;
01227        char *partnum;
01228 
01229        msgnum = lbstr("msgnum");
01230        partnum = bstr("partnum");
01231        do_edit_vcard(msgnum, partnum, NULL, NULL, "", NULL);
01232 }
01233 
01234 
01235 
01236 /*
01237  *  parse edited vcard from the browser
01238  */
01239 void submit_vcard(void) {
01240        struct vCard *v;
01241        char *serialized_vcard;
01242        char buf[SIZ];
01243        StrBuf *Buf;
01244        const StrBuf *ForceRoom;
01245        int i;
01246 
01247        if (!havebstr("ok_button")) { 
01248               readloop(readnew, eUseDefault);
01249               return;
01250        }
01251 
01252        if (havebstr("force_room")) {
01253               ForceRoom = sbstr("force_room");
01254               if (gotoroom(ForceRoom) != 200) {
01255                      AppendImportantMessage(_("Unable to enter the room to save your message"), -1);
01256                      AppendImportantMessage(HKEY(": "));
01257                      AppendImportantMessage(SKEY(ForceRoom));
01258                      AppendImportantMessage(HKEY("; "));
01259                      AppendImportantMessage(_("Aborting."), -1);
01260 
01261                      if (!strcmp(bstr("return_to"), "select_user_to_edit")) {
01262                             select_user_to_edit(NULL);
01263                      }
01264                      else if (!strcmp(bstr("return_to"), "do_welcome")) {
01265                             do_welcome();
01266                      }
01267                      else if (!IsEmptyStr(bstr("return_to"))) {
01268                             http_redirect(bstr("return_to"));
01269                      }
01270                      else {
01271                             readloop(readnew, eUseDefault);
01272                      }
01273                      return;
01274               }
01275        }
01276 
01277        Buf = NewStrBuf();
01278        serv_write(HKEY("ENT0 1|||4\n"));
01279        if (!StrBuf_ServGetln(Buf) && (GetServerStatus(Buf, NULL) != 4))
01280        {
01281               edit_vcard();
01282               return;
01283        }
01284 
01285        /* Make a vCard structure out of the data supplied in the form */
01286        StrBufPrintf(Buf, "begin:vcard\r\n%s\r\nend:vcard\r\n",
01287                    bstr("extrafields")
01288        );
01289        v = VCardLoad(Buf);  /* Start with the extra fields */
01290        if (v == NULL) {
01291               AppendImportantMessage(_("An error has occurred."), -1);
01292               edit_vcard();
01293               FreeStrBuf(&Buf);
01294               return;
01295        }
01296 
01297        snprintf(buf, sizeof buf, "%s;%s;%s;%s;%s",
01298               bstr("lastname"),
01299               bstr("firstname"),
01300               bstr("middlename"),
01301               bstr("prefix"),
01302               bstr("suffix") );
01303        vcard_add_prop(v, "n", buf);
01304        
01305        vcard_add_prop(v, "title", bstr("title"));
01306        vcard_add_prop(v, "fn", bstr("fullname"));
01307        vcard_add_prop(v, "org", bstr("org"));
01308 
01309        snprintf(buf, sizeof buf, "%s;%s;%s;%s;%s;%s;%s",
01310               bstr("pobox"),
01311               bstr("extadr"),
01312               bstr("street"),
01313               bstr("city"),
01314               bstr("state"),
01315               bstr("zipcode"),
01316               bstr("country") );
01317        vcard_add_prop(v, "adr", buf);
01318 
01319        vcard_add_prop(v, "tel;home", bstr("hometel"));
01320        vcard_add_prop(v, "tel;work", bstr("worktel"));
01321        vcard_add_prop(v, "tel;fax", bstr("faxtel"));
01322        vcard_add_prop(v, "tel;cell", bstr("mobiletel"));
01323        vcard_add_prop(v, "email;internet", bstr("primary_inetemail"));
01324 
01325        for (i=0; i<num_tokens(bstr("other_inetemail"), '\n'); ++i) {
01326               extract_token(buf, bstr("other_inetemail"), i, '\n', sizeof buf);
01327               if (!IsEmptyStr(buf)) {
01328                      vcard_add_prop(v, "email;internet", buf);
01329               }
01330        }
01331 
01332        serialized_vcard = vcard_serialize(v);
01333        vcard_free(v);
01334        if (serialized_vcard == NULL) {
01335               AppendImportantMessage(_("An error has occurred."), -1);
01336               edit_vcard();
01337               FreeStrBuf(&Buf);
01338               return;
01339        }
01340 
01341        serv_write(HKEY("Content-type: text/x-vcard; charset=UTF-8\n"));
01342        serv_write(HKEY("\n"));
01343        serv_printf("%s\r\n", serialized_vcard);
01344        serv_write(HKEY("000\n"));
01345        free(serialized_vcard);
01346 
01347        if (!strcmp(bstr("return_to"), "select_user_to_edit")) {
01348               select_user_to_edit(NULL);
01349        }
01350        else if (!strcmp(bstr("return_to"), "do_welcome")) {
01351               do_welcome();
01352        }
01353        else if (!IsEmptyStr(bstr("return_to"))) {
01354               http_redirect(bstr("return_to"));
01355        }
01356        else {
01357               readloop(readnew, eUseDefault);
01358        }
01359        FreeStrBuf(&Buf);
01360 }
01361 
01362 
01363 
01364 /*
01365  * Extract an embedded photo from a vCard for display on the client
01366  */
01367 void display_vcard_photo_img(void)
01368 {
01369        long msgnum = 0L;
01370        StrBuf *vcard;
01371        struct vCard *v;
01372        char *photosrc;
01373        const char *contentType;
01374        wcsession *WCC = WC;
01375 
01376        msgnum = StrBufExtract_long(WCC->Hdr->HR.ReqLine, 0, '/');
01377        
01378        vcard = load_mimepart(msgnum,"1");
01379        v = VCardLoad(vcard);
01380        
01381        photosrc = vcard_get_prop(v, "PHOTO", 1,0,0);
01382        FlushStrBuf(WCC->WBuf);
01383        StrBufAppendBufPlain(WCC->WBuf, photosrc, -1, 0);
01384        if (StrBufDecodeBase64(WCC->WBuf) <= 0) {
01385               FlushStrBuf(WCC->WBuf);
01386               
01387               hprintf("HTTP/1.1 500 %s\n","Unable to get photo");
01388               output_headers(0, 0, 0, 0, 0, 0);
01389               hprintf("Content-Type: text/plain\r\n");
01390               begin_burst();
01391               wc_printf(_("Could Not decode vcard photo\n"));
01392               end_burst();
01393               return;
01394        }
01395        contentType = GuessMimeType(ChrPtr(WCC->WBuf), StrLength(WCC->WBuf));
01396        http_transmit_thing(contentType, 0);
01397        free(v);
01398        free(photosrc);
01399 }
01400 
01401 typedef struct _vcardview_struct {
01402        long is_singlecard;
01403        addrbookent *addrbook;
01404        long num_ab;
01405 
01406 } vcardview_struct;
01407 
01408 int vcard_GetParamsGetServerCall(SharedMessageStatus *Stat, 
01409                              void **ViewSpecific, 
01410                              long oper, 
01411                              char *cmd, 
01412                              long len,
01413                              char *filter,
01414                              long flen)
01415 {
01416        vcardview_struct *VS;
01417 
01418        VS = (vcardview_struct*) malloc (sizeof(vcardview_struct));
01419        memset(VS, 0, sizeof(vcardview_struct));
01420        *ViewSpecific = (void*)VS;
01421 
01422        VS->is_singlecard = ibstr("is_singlecard");
01423        if (VS->is_singlecard != 1) {
01424               if (oper == do_search) {
01425                      snprintf(cmd, len, "MSGS SEARCH|%s", bstr("query"));
01426               }
01427               else {
01428                      strcpy(cmd, "MSGS ALL");
01429               }
01430               Stat->maxmsgs = 9999999;
01431        }
01432        return 200;
01433 }
01434 
01435 int vcard_LoadMsgFromServer(SharedMessageStatus *Stat, 
01436                          void **ViewSpecific, 
01437                          message_summary* Msg, 
01438                          int is_new, 
01439                          int i)
01440 {
01441        vcardview_struct *VS;
01442        char *ab_name;
01443 
01444        VS = (vcardview_struct*) *ViewSpecific;
01445 
01446        ab_name = NULL;
01447        fetch_ab_name(Msg, &ab_name);
01448        if (ab_name == NULL) 
01449               return 0;
01450        ++VS->num_ab;
01451        VS->addrbook = realloc(VS->addrbook,
01452                             (sizeof(addrbookent) * VS->num_ab) );
01453        safestrncpy(VS->addrbook[VS->num_ab-1].ab_name, ab_name,
01454                   sizeof(VS->addrbook[VS->num_ab-1].ab_name));
01455        VS->addrbook[VS->num_ab-1].ab_msgnum = Msg->msgnum;
01456        free(ab_name);
01457        return 0;
01458 }
01459 
01460 
01461 int vcard_RenderView_or_Tail(SharedMessageStatus *Stat, void **ViewSpecific, long oper)
01462 {
01463        const StrBuf *Mime;
01464        vcardview_struct *VS;
01465 
01466        VS = (vcardview_struct*) *ViewSpecific;
01467        if (VS->is_singlecard)
01468               read_message(WC->WBuf, HKEY("view_message"), lbstr("startmsg"), NULL, &Mime);
01469        else
01470               do_addrbook_view(VS->addrbook, VS->num_ab);      /* Render the address book */
01471        return 0;
01472 }
01473 
01474 int vcard_Cleanup(void **ViewSpecific)
01475 {
01476        vcardview_struct *VS;
01477 
01478        VS = (vcardview_struct*) *ViewSpecific;
01479        wDumpContent(1);
01480        if ((VS != NULL) && 
01481            (VS->addrbook != NULL))
01482               free(VS->addrbook);
01483        if (VS != NULL) 
01484               free(VS);
01485        return 0;
01486 }
01487 
01488 void 
01489 ServerStartModule_VCARD
01490 (void)
01491 {
01492        VCToEnum = NewHash(0, NULL);
01493 
01494 }
01495 
01496 void 
01497 ServerShutdownModule_VCARD
01498 (void)
01499 {
01500        DeleteHash(&VCToEnum);
01501 }
01502 
01503 void 
01504 InitModule_VCARD
01505 (void)
01506 {
01507        RegisterReadLoopHandlerset(
01508               VIEW_ADDRESSBOOK,
01509               vcard_GetParamsGetServerCall,
01510               NULL,
01511               NULL,
01512               NULL, 
01513               vcard_LoadMsgFromServer,
01514               vcard_RenderView_or_Tail,
01515               vcard_Cleanup);
01516        WebcitAddUrlHandler(HKEY("edit_vcard"), "", 0, edit_vcard, 0);
01517        WebcitAddUrlHandler(HKEY("submit_vcard"), "", 0, submit_vcard, 0);
01518        WebcitAddUrlHandler(HKEY("vcardphoto"), "", 0, display_vcard_photo_img, NEED_URL);
01519 
01520        Put(VCToEnum, HKEY("n"), (void*)VC_n, reference_free_handler);
01521        Put(VCToEnum, HKEY("fn"), (void*)VC_fn, reference_free_handler);
01522        Put(VCToEnum, HKEY("title"), (void*)VC_title, reference_free_handler);
01523        Put(VCToEnum, HKEY("org"), (void*)VC_org, reference_free_handler);
01524        Put(VCToEnum, HKEY("email"), (void*)VC_email, reference_free_handler);
01525        Put(VCToEnum, HKEY("tel"), (void*)VC_tel, reference_free_handler);
01526        Put(VCToEnum, HKEY("tel_tel"), (void*)VC_tel_tel, reference_free_handler);
01527        Put(VCToEnum, HKEY("tel_work"), (void*)VC_tel_work, reference_free_handler);
01528        Put(VCToEnum, HKEY("tel_home"), (void*)VC_tel_home, reference_free_handler);
01529        Put(VCToEnum, HKEY("tel_cell"), (void*)VC_tel_cell, reference_free_handler);
01530        Put(VCToEnum, HKEY("adr"), (void*)VC_adr, reference_free_handler);
01531        Put(VCToEnum, HKEY("photo"), (void*)VC_photo, reference_free_handler);
01532        Put(VCToEnum, HKEY("version"), (void*)VC_version, reference_free_handler);
01533        Put(VCToEnum, HKEY("rev"), (void*)VC_rev, reference_free_handler);
01534        Put(VCToEnum, HKEY("label"), (void*)VC_label, reference_free_handler);
01535 
01536 
01537        RegisterNamespace("VC", 1, 2, tmplput_VCARD_ITEM, NULL, CTX_VCARD);
01538 
01539        REGISTERTokenParamDefine(VC_n);
01540        REGISTERTokenParamDefine(VC_fn);
01541        REGISTERTokenParamDefine(VC_title);
01542        REGISTERTokenParamDefine(VC_org);
01543        REGISTERTokenParamDefine(VC_email);
01544        REGISTERTokenParamDefine(VC_tel);
01545        REGISTERTokenParamDefine(VC_tel_tel);
01546        REGISTERTokenParamDefine(VC_tel_work);
01547        REGISTERTokenParamDefine(VC_tel_home);
01548        REGISTERTokenParamDefine(VC_tel_cell);
01549        REGISTERTokenParamDefine(VC_adr);
01550        REGISTERTokenParamDefine(VC_photo);
01551        REGISTERTokenParamDefine(VC_version);
01552        REGISTERTokenParamDefine(VC_rev);
01553        REGISTERTokenParamDefine(VC_label);
01554 
01555 }
01556